3030#include < algorithm>
3131#include < limits>
3232#include < memory>
33+ #include < sstream>
3334
3435#include " TestingSwapChainBase.hpp"
3536#include " GraphicsAccessories.hpp"
@@ -105,6 +106,35 @@ bool LoadTestImage(const char* FilePath,
105106 return true ;
106107}
107108
109+ std::string GetTestImageComparisonFailureFileName (Uint32 FailureIndex)
110+ {
111+ const auto * const TestInfo = ::testing::UnitTest::GetInstance ()->current_test_info ();
112+ GPUTestingEnvironment* const pEnvironment = GPUTestingEnvironment::GetInstance ();
113+ VERIFY_EXPR (TestInfo != nullptr );
114+ VERIFY_EXPR (pEnvironment != nullptr && pEnvironment->GetDevice () != nullptr );
115+
116+ const auto ValidateName = [](const std::string& src) {
117+ std::string dst = src;
118+ for (char & c : dst)
119+ {
120+ if (c == ' .' || c == ' \\ ' || c == ' /' )
121+ c = ' _' ;
122+ }
123+ return dst;
124+ };
125+
126+ std::string FileName{ValidateName (TestInfo->test_suite_name ())};
127+ FileName += ' .' ;
128+ FileName += ValidateName (TestInfo->name ());
129+ FileName += ' _' ;
130+ FileName += GetRenderDeviceTypeShortString (pEnvironment->GetDevice ()->GetDeviceInfo ().Type );
131+ FileName += " _FAIL" ;
132+ if (FailureIndex > 0 )
133+ FileName += std::to_string (FailureIndex);
134+ FileName += " _.png" ;
135+ return FileName;
136+ }
137+
108138void CompareTestImages (const Uint8* pReferencePixels,
109139 Uint64 RefPixelsStride,
110140 const Uint8* pPixels,
@@ -161,29 +191,64 @@ void CompareTestImages(const Uint8* pReferencePixels,
161191 if (bIsIdentical)
162192 return ;
163193
164- Uint64 BadPixelCount = 0 ;
165- Uint32 MaxObservedChannelErr = 0 ;
194+ Uint64 ToleratedPixelCount = 0 ;
195+ Uint64 BadPixelCount = 0 ;
196+ Uint32 MaxToleratedChannelError = 0 ;
197+ Uint32 MaxBadChannelError = 0 ;
166198 for (Uint32 Row = 0 ; Row < Height; ++Row)
167199 {
168200 for (Uint32 Col = 0 ; Col < Width; ++Col)
169201 {
170- bool BadPixel = false ;
202+ Uint32 PixelMaxChannelError = 0 ;
171203 for (Uint32 Component = 0 ; Component < ComponentCount; ++Component)
172204 {
173205 const Uint32 RefValue = pReferencePixels[Row * RefPixelsStride + Col * 4 + Component];
174206 const Uint32 Value = pPixels[Row * PixelsStride + Col * 4 + Component];
175207 const Uint32 Error = RefValue > Value ? RefValue - Value : Value - RefValue;
176- MaxObservedChannelErr = std::max (MaxObservedChannelErr, Error);
177- BadPixel |= Error > ComparisonAttribs.MaxChannelError ;
208+ PixelMaxChannelError = std::max (PixelMaxChannelError, Error);
209+ }
210+
211+ if (PixelMaxChannelError > ComparisonAttribs.MaxChannelError )
212+ {
213+ ++BadPixelCount;
214+ MaxBadChannelError = std::max (MaxBadChannelError, PixelMaxChannelError);
215+ }
216+ else if (PixelMaxChannelError > 0 )
217+ {
218+ ++ToleratedPixelCount;
219+ MaxToleratedChannelError = std::max (MaxToleratedChannelError, PixelMaxChannelError);
178220 }
179- BadPixelCount += BadPixel ? 1 : 0 ;
180221 }
181222 }
182223
224+ if (ToleratedPixelCount == 0 && BadPixelCount == 0 )
225+ return ;
226+
183227 const Uint64 PixelCount = Uint64{Width} * Height;
228+
229+ std::ostringstream Statistics;
230+ if (ToleratedPixelCount > 0 )
231+ {
232+ Statistics << ToleratedPixelCount << " of " << PixelCount
233+ << " pixels differ but remain within the per-channel error threshold "
234+ << Uint32{ComparisonAttribs.MaxChannelError } << " ; maximum channel error is "
235+ << MaxToleratedChannelError;
236+ }
237+ if (BadPixelCount > 0 )
238+ {
239+ if (ToleratedPixelCount > 0 )
240+ Statistics << ' \n ' ;
241+
242+ const double BadPixelPercentage = static_cast <double >(BadPixelCount) / static_cast <double >(PixelCount) * 100.0 ;
243+ Statistics << BadPixelCount << " of " << PixelCount << " pixels (" << BadPixelPercentage
244+ << " %) exceed the threshold; maximum channel error is " << MaxBadChannelError;
245+ }
246+
184247 if (static_cast <double >(BadPixelCount) <=
185248 static_cast <double >(PixelCount) * ComparisonAttribs.MaxBadPixelRatio )
186249 {
250+ LOG_WARNING_MESSAGE (" Image rendered by the test differs from the reference image, but is within the configured tolerance:\n " ,
251+ Statistics.str ());
187252 return ;
188253 }
189254
@@ -210,34 +275,15 @@ void CompareTestImages(const Uint8* pReferencePixels,
210275 }
211276 }
212277 }
213- const auto * const TestInfo = ::testing::UnitTest::GetInstance ()->current_test_info ();
214-
215- const auto ValidateName = [](const std::string& src) {
216- std::string dst = src;
217- for (char & c : dst)
218- {
219- if (c == ' .' || c == ' \\ ' || c == ' /' )
220- c = ' _' ;
221- }
222- return dst;
223- };
224-
225- std::string FileName{ValidateName (TestInfo->test_suite_name ())};
226- FileName += ' .' ;
227- FileName += ValidateName (TestInfo->name ());
228- auto & FailureCounter = FailureCounters[FileName];
229- FileName += " _FAIL" ;
230- if (FailureCounter > 0 )
231- FileName += std::to_string (FailureCounter);
232- FileName += " _.png" ;
278+ const std::string CounterKey = GetTestImageComparisonFailureFileName ();
279+ auto & FailureCounter = FailureCounters[CounterKey];
280+ const std::string FileName = GetTestImageComparisonFailureFileName (static_cast <Uint32>(FailureCounter));
233281 if (stbi_write_png (FileName.c_str (), Width * 2 , Height * 2 , 3 , ReportImage.data (), (Width * 2 ) * 3 ) == 0 )
234282 {
235283 LOG_ERROR_MESSAGE (" Failed to write " , FileName);
236284 }
237- ADD_FAILURE () << " Image rendered by the test differs from the reference image: "
238- << BadPixelCount << " of " << PixelCount << " pixels exceed the per-channel error threshold "
239- << Uint32{ComparisonAttribs.MaxChannelError } << " ; maximum observed channel error is "
240- << MaxObservedChannelErr;
285+ ADD_FAILURE () << " Image rendered by the test differs from the reference image:\n "
286+ << Statistics.str ();
241287 ++FailureCounter;
242288 }
243289}
0 commit comments