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;
2627namespace 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-
139136void OCIOGPUTest::setProcessor (OCIO::TransformRcPtr transform)
140137{
141138 OCIO::ConfigRcPtr config = OCIO::Config::Create ();
@@ -151,7 +148,7 @@ void OCIOGPUTest::setProcessor(OCIO::ConstConfigRcPtr config,
151148
152149void 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
193190namespace
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 << " \n Large 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 << " \n NAN 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 (" \n Command 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+ " \t ex: --run_only ExponentOp/forward i.e. run only \" ExponentOp/forward\"\n "
536+ " \t ex: --run_only ExponentOp i.e. run \" ExponentOp/*\"\n "
537+ " \t ex: --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