Skip to content

Commit bb28982

Browse files
authored
Adsk Contrib - Improve the GPU unit test framework (#1562) (#1587)
Signed-off-by: Patrick Hodoul <[email protected]>
1 parent 7ffc349 commit bb28982

File tree

6 files changed

+139
-68
lines changed

6 files changed

+139
-68
lines changed

src/OpenColorIO/ops/gradingtone/GradingToneOpGPU.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void AddBoolUniform(GpuShaderCreatorRcPtr & shaderCreator,
8484
}
8585
}
8686

87-
static const std::string opPrefix{ "grading_tone" };
87+
const std::string opPrefix{ "grading_tone" };
8888

8989
void AddGTProperties(GpuShaderCreatorRcPtr & shaderCreator,
9090
GpuShaderText & st,
@@ -1301,7 +1301,7 @@ void Add_SContrastBottomPre_Shader(GpuShaderText & st, GradingStyle style)
13011301

13021302
// Bottom end
13031303
st.newLine() << "{"; // establish scope so local variable names won't conflict
1304-
st.setIndent(4);
1304+
st.indent();
13051305
st.newLine() << st.floatKeywordConst() << " x0 = " << bottomPoint << ";";
13061306
st.newLine() << st.floatKeywordConst() << " y0 = " << bottomPoint << ";";
13071307
st.newLine() << st.floatKeywordConst() << " y3 = pivot - (pivot - y0) * 0.25;";
@@ -1562,7 +1562,7 @@ void GetGradingToneGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
15621562
st.newLine() << "{";
15631563
st.indent();
15641564

1565-
// Properties holds shader variables names and is initialized with undecorated names suitable
1565+
// Properties hold shader variables names and are initialized with undecorated names suitable
15661566
// for local variables.
15671567
GTProperties properties;
15681568
AddGTProperties(shaderCreator, st, gtData, properties, dyn);

src/libutils/oglapphelpers/glsl.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -479,21 +479,20 @@ unsigned OpenGLBuilder::buildProgram(const std::string & clientShaderProgram, bo
479479
glDeleteShader(m_fragShader);
480480
}
481481

482-
std::ostringstream os;
483-
os << getGLSLVersionString() << std::endl
484-
<< (!standaloneShader ? m_shaderDesc->getShaderText() : "") << std::endl
485-
<< clientShaderProgram << std::endl;
482+
std::ostringstream oss;
483+
oss << getGLSLVersionString() << std::endl
484+
<< (!standaloneShader ? m_shaderDesc->getShaderText() : "") << std::endl
485+
<< clientShaderProgram << std::endl;
486486

487487
if(m_verbose)
488488
{
489-
std::cout << std::endl;
490-
std::cout << "GPU Shader Program:" << std::endl;
491-
std::cout << std::endl;
492-
std::cout << os.str() << std::endl;
493-
std::cout << std::endl;
489+
std::cout << "\nGPU Shader Program:\n\n"
490+
<< oss.str()
491+
<< "\n\n"
492+
<< std::flush;
494493
}
495494

496-
m_fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
495+
m_fragShader = CompileShaderText(GL_FRAGMENT_SHADER, oss.str().c_str());
497496

498497
LinkShaders(m_program, m_fragShader);
499498
m_shaderCacheID = shaderCacheID;

tests/gpu/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ target_link_libraries(test_gpu_exec
4747
PRIVATE
4848
OpenColorIO
4949
oglapphelpers
50+
pystring::pystring
5051
unittest_data
52+
utils::strings
53+
testutils
5154
)
5255

5356
add_test(NAME test_gpu COMMAND test_gpu_exec)

tests/gpu/GPUUnitTest.cpp

Lines changed: 118 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22
// Copyright Contributors to the OpenColorIO Project.
33

44

5-
#include <sstream>
6-
#include <map>
5+
#include <algorithm>
6+
#include <cmath>
7+
#include <cstring>
78
#include <iomanip>
89
#include <iostream>
9-
10-
#include <stdlib.h>
11-
#include <string.h>
12-
#include <cmath>
13-
#include <algorithm>
10+
#include <sstream>
1411

1512
#include <OpenColorIO/OpenColorIO.h>
1613

1714
#include "GPUUnitTest.h"
15+
16+
#include "apputils/argparse.h"
17+
#include "utils/StringUtils.h"
18+
1819
#include "oglapp.h"
1920
#if __APPLE__
2021
#include "metalapp.h"
@@ -26,12 +27,12 @@ namespace OCIO = OCIO_NAMESPACE;
2627
namespace Shader
2728
{
2829
// Default error threshold
29-
const float defaultErrorThreshold = 1e-7f;
30+
constexpr float defaultErrorThreshold = 1e-7f;
3031

3132
// In some occasions, MAX_FLOAT will be "rounded" to infinity on some GPU renderers.
3233
// In order to avoid this issue, consider all number over/under a given threshold as
3334
// equal for testing purposes.
34-
const float largeThreshold = std::numeric_limits<float>::max();
35+
constexpr float largeThreshold = std::numeric_limits<float>::max();
3536

3637
enum LimitsDiff
3738
{
@@ -95,7 +96,7 @@ namespace Shader
9596
inline bool RelativeDifference(float x1, float x2, float min_x1, float & diff)
9697
{
9798
const float absx1 = fabs(x1);
98-
float div = std::max(absx1, min_x1);
99+
const float div = std::max(absx1, min_x1);
99100
const float thisDiff = fabs(x1 - x2) / div;
100101
if (thisDiff > diff)
101102
{
@@ -122,8 +123,8 @@ namespace Shader
122123
}
123124

124125

125-
OCIOGPUTest::OCIOGPUTest(const std::string& testgroup,
126-
const std::string& testname,
126+
OCIOGPUTest::OCIOGPUTest(const std::string & testgroup,
127+
const std::string & testname,
127128
OCIOTestFuncCallback test)
128129
: m_group(testgroup)
129130
, m_name(testname)
@@ -132,10 +133,6 @@ OCIOGPUTest::OCIOGPUTest(const std::string& testgroup,
132133
{
133134
}
134135

135-
OCIOGPUTest::~OCIOGPUTest()
136-
{
137-
}
138-
139136
void OCIOGPUTest::setProcessor(OCIO::TransformRcPtr transform)
140137
{
141138
OCIO::ConfigRcPtr config = OCIO::Config::Create();
@@ -151,7 +148,7 @@ void OCIOGPUTest::setProcessor(OCIO::ConstConfigRcPtr config,
151148

152149
void OCIOGPUTest::setProcessor(OCIO::ConstProcessorRcPtr processor)
153150
{
154-
if(m_processor.get()!=0x0)
151+
if (m_processor.get() != nullptr)
155152
{
156153
throw OCIO::Exception("GPU Unit test already exists");
157154
}
@@ -192,9 +189,9 @@ AddTest::AddTest(OCIOGPUTestRcPtr test)
192189

193190
namespace
194191
{
195-
static constexpr unsigned g_winWidth = 256;
196-
static constexpr unsigned g_winHeight = 256;
197-
static constexpr unsigned g_components = 4;
192+
constexpr unsigned g_winWidth = 256;
193+
constexpr unsigned g_winHeight = 256;
194+
constexpr unsigned g_components = 4;
198195

199196
void AllocateImageTexture(OCIO::OglAppRcPtr & app)
200197
{
@@ -381,7 +378,7 @@ namespace
381378
}
382379
}
383380

384-
static constexpr size_t invalidIndex = std::numeric_limits<size_t>::max();
381+
constexpr size_t invalidIndex = std::numeric_limits<size_t>::max();
385382

386383
// Validate the GPU processing against the CPU one.
387384
void ValidateImageTexture(OCIO::OglAppRcPtr & app, OCIOGPUTestRcPtr & test)
@@ -471,8 +468,8 @@ namespace
471468
}
472469
if (idxInf != invalidIndex)
473470
{
474-
size_t componentIdx = idxInf % 4;
475-
size_t pixelIdx = idxInf / 4;
471+
componentIdx = idxInf % 4;
472+
pixelIdx = idxInf / 4;
476473
err << std::setprecision(10)
477474
<< "\nLarge number error: " << diff << " at pixel: " << pixelIdx
478475
<< " on component " << componentIdx
@@ -488,8 +485,8 @@ namespace
488485
}
489486
if (idxNan != invalidIndex)
490487
{
491-
size_t componentIdx = idxNan % 4;
492-
size_t pixelIdx = idxNan / 4;
488+
componentIdx = idxNan % 4;
489+
pixelIdx = idxNan / 4;
493490
err << std::setprecision(10)
494491
<< "\nNAN error: " << diff << " at pixel: " << pixelIdx
495492
<< " on component " << componentIdx
@@ -512,19 +509,70 @@ namespace
512509
}
513510
};
514511

515-
int main(int argc, char ** argv)
512+
int main(int argc, const char ** argv)
516513
{
517-
// Step 1: Initialize the graphic library engines.
518-
OCIO::OglAppRcPtr app;
519-
514+
515+
#if !defined(NDEBUG) && defined(_WIN32)
516+
// Disable the 'assert' dialog box in debug mode.
517+
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
518+
#endif
519+
520+
bool printHelp = false;
520521
bool useMetalRenderer = false;
521-
for(int i = 0; i < argc; ++i)
522+
bool verbose = false;
523+
bool stopOnFirstError = false;
524+
525+
// Note that empty strings mean to run all the unit tests.
526+
std::string filter, utestGroupAllowed, utestNameAllowed;
527+
528+
ArgParse ap;
529+
ap.options("\nCommand line arguments:\n",
530+
"--help", &printHelp, "Print help message",
531+
"--metal", &useMetalRenderer, "Run the GPU unit test with Metal",
532+
"-v", &verbose, "Output the GPU shader program",
533+
"--stop_on_error", &stopOnFirstError, "Stop on the first error",
534+
"--run_only %s", &filter, "Run only some unit tests\n"
535+
"\tex: --run_only ExponentOp/forward i.e. run only \"ExponentOp/forward\"\n"
536+
"\tex: --run_only ExponentOp i.e. run \"ExponentOp/*\"\n"
537+
"\tex: --run_only /forward i.e. run \"*/forward\"\n",
538+
nullptr);
539+
540+
if (ap.parse(argc, argv) < 0)
541+
{
542+
std::cerr << ap.geterror() << std::endl;
543+
ap.usage();
544+
return 1;
545+
}
546+
547+
if (printHelp)
548+
{
549+
ap.usage();
550+
return 1;
551+
}
552+
553+
if (!filter.empty())
522554
{
523-
if(strcmp(argv[i], "-metal") == 0)
555+
const std::vector<std::string> results = StringUtils::Split(filter, '/');
556+
if (!results.empty())
524557
{
525-
useMetalRenderer = true;
558+
utestGroupAllowed = StringUtils::Lower(StringUtils::Trim(results[0]));
559+
if (results.size() >= 2)
560+
{
561+
utestNameAllowed = StringUtils::Lower(StringUtils::Trim(results[1]));
562+
563+
if (results.size() >= 3)
564+
{
565+
std::cerr << "Invalid value for the argument '--run_only'." << std::endl;
566+
ap.usage();
567+
return 1;
568+
}
569+
}
526570
}
527571
}
572+
573+
// Step 1: Initialize the graphic library engines.
574+
OCIO::OglAppRcPtr app;
575+
528576
try
529577
{
530578
if(useMetalRenderer)
@@ -561,7 +609,7 @@ int main(int argc, char ** argv)
561609

562610
unsigned failures = 0;
563611

564-
std::cerr << "\n OpenColorIO_Core_GPU_Unit_Tests\n\n";
612+
std::cout << "\n OpenColorIO_Core_GPU_Unit_Tests\n\n";
565613

566614
UnitTests & tests = GetUnitTests();
567615
const size_t numTests = tests.size();
@@ -570,7 +618,32 @@ int main(int argc, char ** argv)
570618
const unsigned curr_failures = failures;
571619

572620
OCIOGPUTestRcPtr test = tests[idx];
573-
621+
622+
// Is that a unit test to run ?
623+
624+
const std::string utestGroup = test->group();
625+
const std::string utestName = test->name();
626+
627+
bool utestAllowed = true;
628+
629+
if (!utestGroupAllowed.empty() && StringUtils::Lower(utestGroup)!=utestGroupAllowed)
630+
{
631+
utestAllowed = false;
632+
}
633+
634+
if (!utestNameAllowed.empty() && StringUtils::Lower(utestName)!=utestNameAllowed)
635+
{
636+
utestAllowed = false;
637+
}
638+
639+
if (!utestAllowed)
640+
{
641+
continue;
642+
}
643+
644+
// Prepare the unit test.
645+
646+
test->setVerbose(verbose);
574647
test->setShadingLanguage(
575648
#if __APPLE__
576649
useMetalRenderer ?
@@ -582,6 +655,7 @@ int main(int argc, char ** argv)
582655
try
583656
{
584657
test->setup();
658+
585659
enabledTest = test->isEnabled();
586660

587661
constexpr size_t maxCharToDisplay = 49;
@@ -594,7 +668,7 @@ int main(int argc, char ** argv)
594668
name.resize(maxCharToDisplay);
595669
}
596670

597-
std::cerr << "["
671+
std::cout << "["
598672
<< std::right << std::setw(3)
599673
<< (idx+1) << "/" << numTests << "] ["
600674
<< std::left << std::setw(maxCharToDisplay+1)
@@ -610,12 +684,12 @@ int main(int argc, char ** argv)
610684

611685
const size_t numRetest = test->getNumRetests();
612686
// Need to run once and for each retest.
613-
for (size_t idx = 0; idx <= numRetest; ++idx)
687+
for (size_t idxRetest = 0; idxRetest <= numRetest; ++idxRetest)
614688
{
615-
if (idx != 0) // Skip first run.
689+
if (idxRetest != 0) // Skip first run.
616690
{
617691
// Call the retest callback.
618-
test->retestSetup(idx - 1);
692+
test->retestSetup(idxRetest - 1);
619693
}
620694

621695
// Process the image texture into the rendering buffer.
@@ -640,15 +714,15 @@ int main(int argc, char ** argv)
640714

641715
if (!enabledTest)
642716
{
643-
std::cerr << "DISABLED" << std::endl;
717+
std::cout << "DISABLED" << std::endl;
644718
}
645719
else if(curr_failures==failures && test->isValid())
646720
{
647-
size_t idx = test->getMaxDiffIndex();
648-
size_t componentIdx = idx % 4;
649-
size_t pixelIdx = idx / 4;
721+
const size_t idxMaxDiff = test->getMaxDiffIndex();
722+
const size_t componentIdx = idxMaxDiff % 4;
723+
const size_t pixelIdx = idxMaxDiff / 4;
650724

651-
std::cerr << "PASSED - (MaxDiff: " << test->getMaxDiff()
725+
std::cout << "PASSED - (MaxDiff: " << test->getMaxDiff()
652726
<< " at pix[" << pixelIdx
653727
<< "][" << componentIdx << "])" << std::endl;
654728
}
@@ -660,9 +734,8 @@ int main(int argc, char ** argv)
660734

661735
// Get rid of the test.
662736
tests[idx] = nullptr;
663-
664737
}
665738

666-
std::cerr << std::endl << failures << " tests failed" << std::endl << std::endl;
739+
std::cout << std::endl << failures << " tests failed" << std::endl << std::endl;
667740
return failures;
668741
}

0 commit comments

Comments
 (0)