Skip to content

Commit 01addec

Browse files
GPUTestFramework: distinguish image and snapshot alpha handling
1 parent 76de008 commit 01addec

9 files changed

Lines changed: 247 additions & 62 deletions

File tree

Tests/DiligentCoreAPITest/src/TestingSwapChainBaseTest.cpp

Lines changed: 173 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,101 @@ TEST(TestingSwapChainBaseTest, ToleratesConfiguredImageDifferences)
9393

9494
#if !PLATFORM_WEB
9595

96+
class ComparisonFailureImageGuard
97+
{
98+
public:
99+
ComparisonFailureImageGuard()
100+
{
101+
const testing::TestInfo* const TestInfo = testing::UnitTest::GetInstance()->current_test_info();
102+
VERIFY_EXPR(TestInfo != nullptr);
103+
if (TestInfo != nullptr)
104+
m_FileName = std::string{TestInfo->test_suite_name()} + "." + TestInfo->name() + "_FAIL_.png";
105+
}
106+
107+
~ComparisonFailureImageGuard()
108+
{
109+
if (!m_FileName.empty())
110+
FileSystem::DeleteFile(m_FileName.c_str());
111+
}
112+
113+
// clang-format off
114+
ComparisonFailureImageGuard(const ComparisonFailureImageGuard&) = delete;
115+
ComparisonFailureImageGuard& operator=(const ComparisonFailureImageGuard&) = delete;
116+
// clang-format on
117+
118+
private:
119+
std::string m_FileName;
120+
};
121+
122+
void TestSnapshotComparisonFailure(Uint32 Channel)
123+
{
124+
ASSERT_LT(Channel, 4u);
125+
126+
GPUTestingEnvironment::ScopedReset AutoReset;
127+
128+
GPUTestingEnvironment* const pEnvironment = GPUTestingEnvironment::GetInstance();
129+
IDeviceContext* const pContext = pEnvironment->GetDeviceContext();
130+
ISwapChain* const pSwapChain = pEnvironment->GetSwapChain();
131+
ASSERT_NE(pContext, nullptr);
132+
ASSERT_NE(pSwapChain, nullptr);
133+
134+
RefCntAutoPtr<ITestingSwapChain> pTestingSwapChain{pSwapChain, IID_TestingSwapChain};
135+
ASSERT_NE(pTestingSwapChain, nullptr);
136+
137+
const SwapChainDesc& SwapChainDesc = pSwapChain->GetDesc();
138+
std::vector<Uint8> ReferencePixels(static_cast<size_t>(SwapChainDesc.Width) * SwapChainDesc.Height * 4, 255);
139+
pTestingSwapChain->SetReferenceData(ReferencePixels.data());
140+
141+
float ClearColor[] = {1, 1, 1, 1};
142+
ClearColor[Channel] = 0;
143+
ITextureView* pRTV = pSwapChain->GetCurrentBackBufferRTV();
144+
pContext->SetRenderTargets(1, &pRTV, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
145+
pContext->ClearRenderTarget(pRTV, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
146+
147+
ComparisonFailureImageGuard FailureImageGuard;
148+
EXPECT_NONFATAL_FAILURE(
149+
pTestingSwapChain->CompareWithSnapshot(nullptr),
150+
"Image rendered by the test differs from the reference image");
151+
}
152+
153+
void TestImageComparisonFailure(Uint32 Channel)
154+
{
155+
ASSERT_LT(Channel, 3u);
156+
157+
GPUTestingEnvironment::ScopedReset AutoReset;
158+
159+
GPUTestingEnvironment* const pEnvironment = GPUTestingEnvironment::GetInstance();
160+
IDeviceContext* const pContext = pEnvironment->GetDeviceContext();
161+
ISwapChain* const pSwapChain = pEnvironment->GetSwapChain();
162+
ASSERT_NE(pContext, nullptr);
163+
ASSERT_NE(pSwapChain, nullptr);
164+
165+
RefCntAutoPtr<ITestingSwapChain> pTestingSwapChain{pSwapChain, IID_TestingSwapChain};
166+
ASSERT_NE(pTestingSwapChain, nullptr);
167+
168+
const SwapChainDesc& SwapChainDesc = pSwapChain->GetDesc();
169+
std::vector<Uint8> ReferencePixels(static_cast<size_t>(SwapChainDesc.Width) * SwapChainDesc.Height * 4, 255);
170+
171+
TempDirectory TempDir{"TestingSwapChainBaseTest"};
172+
const std::string ImageName = TempDir.Get() + "/Reference";
173+
const std::string ImagePath = ImageName + ".png";
174+
DumpTestImage(ReferencePixels.data(), Uint64{SwapChainDesc.Width} * 4,
175+
SwapChainDesc.Width, SwapChainDesc.Height,
176+
TEX_FORMAT_RGBA8_UNORM, ImageName.c_str(), false);
177+
ASSERT_TRUE(pTestingSwapChain->LoadReferenceImage(ImagePath.c_str()));
178+
179+
float ClearColor[] = {1, 1, 1, 1};
180+
ClearColor[Channel] = 0;
181+
ITextureView* pRTV = pSwapChain->GetCurrentBackBufferRTV();
182+
pContext->SetRenderTargets(1, &pRTV, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
183+
pContext->ClearRenderTarget(pRTV, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
184+
185+
ComparisonFailureImageGuard FailureImageGuard;
186+
EXPECT_NONFATAL_FAILURE(
187+
pTestingSwapChain->CompareWithSnapshot(nullptr),
188+
"Image rendered by the test differs from the reference image");
189+
}
190+
96191
TEST(TestingSwapChainBaseTest, LoadsPNGAsRGBA8)
97192
{
98193
constexpr Uint32 Width = 2;
@@ -105,11 +200,11 @@ TEST(TestingSwapChainBaseTest, LoadsPNGAsRGBA8)
105200
0,
106201
255,
107202
0,
108-
64,
203+
85,
109204
0,
110205
0,
111206
255,
112-
128,
207+
170,
113208
255,
114209
255,
115210
255,
@@ -122,6 +217,51 @@ TEST(TestingSwapChainBaseTest, LoadsPNGAsRGBA8)
122217
DumpTestImage(SourcePixels.data(), Width * 4, Width, Height,
123218
TEX_FORMAT_RGBA8_UNORM, ImageName.c_str(), false);
124219

220+
std::vector<Uint8> LoadedPixels;
221+
Uint32 LoadedWidth = 0;
222+
Uint32 LoadedHeight = 0;
223+
ASSERT_TRUE(LoadTestImage(ImagePath.c_str(), LoadedPixels, LoadedWidth, LoadedHeight));
224+
EXPECT_EQ(LoadedWidth, Width);
225+
EXPECT_EQ(LoadedHeight, Height);
226+
EXPECT_EQ(LoadedPixels.size(), SourcePixels.size());
227+
for (size_t Pixel = 0; Pixel < SourcePixels.size(); Pixel += 4)
228+
{
229+
EXPECT_TRUE(std::equal(LoadedPixels.begin() + Pixel,
230+
LoadedPixels.begin() + Pixel + 3,
231+
SourcePixels.begin() + Pixel));
232+
EXPECT_EQ(LoadedPixels[Pixel + 3], 255);
233+
}
234+
}
235+
236+
TEST(TestingSwapChainBaseTest, PreservesImageAlphaWhenRequested)
237+
{
238+
constexpr Uint32 Width = 2;
239+
constexpr Uint32 Height = 2;
240+
constexpr std::array<Uint8, Width * Height * 4> SourcePixels{
241+
255,
242+
0,
243+
0,
244+
0,
245+
0,
246+
255,
247+
0,
248+
85,
249+
0,
250+
0,
251+
255,
252+
170,
253+
255,
254+
255,
255+
255,
256+
255,
257+
};
258+
259+
TempDirectory TempDir{"TestingSwapChainBaseTest"};
260+
const std::string ImageName = TempDir.Get() + "/ReferenceWithAlpha";
261+
const std::string ImagePath = ImageName + ".png";
262+
DumpTestImage(SourcePixels.data(), Width * 4, Width, Height,
263+
TEX_FORMAT_RGBA8_UNORM, ImageName.c_str(), false, true);
264+
125265
std::vector<Uint8> LoadedPixels;
126266
Uint32 LoadedWidth = 0;
127267
Uint32 LoadedHeight = 0;
@@ -132,7 +272,7 @@ TEST(TestingSwapChainBaseTest, LoadsPNGAsRGBA8)
132272
EXPECT_TRUE(std::equal(LoadedPixels.begin(), LoadedPixels.end(), SourcePixels.begin()));
133273
}
134274

135-
TEST(TestingSwapChainBaseTest, LoadsReferenceImageIntoSwapChain)
275+
TEST(TestingSwapChainBaseTest, ImageComparisonIgnoresAlphaDifference)
136276
{
137277
GPUTestingEnvironment::ScopedReset AutoReset;
138278

@@ -146,14 +286,7 @@ TEST(TestingSwapChainBaseTest, LoadsReferenceImageIntoSwapChain)
146286
ASSERT_NE(pTestingSwapChain, nullptr);
147287

148288
const SwapChainDesc& SwapChainDesc = pSwapChain->GetDesc();
149-
std::vector<Uint8> ReferencePixels(static_cast<size_t>(SwapChainDesc.Width) * SwapChainDesc.Height * 4);
150-
for (size_t Pixel = 0; Pixel < ReferencePixels.size(); Pixel += 4)
151-
{
152-
ReferencePixels[Pixel + 0] = 255;
153-
ReferencePixels[Pixel + 1] = 0;
154-
ReferencePixels[Pixel + 2] = 0;
155-
ReferencePixels[Pixel + 3] = 255;
156-
}
289+
std::vector<Uint8> ReferencePixels(static_cast<size_t>(SwapChainDesc.Width) * SwapChainDesc.Height * 4, 255);
157290

158291
TempDirectory TempDir{"TestingSwapChainBaseTest"};
159292
const std::string ImageName = TempDir.Get() + "/Reference";
@@ -163,50 +296,49 @@ TEST(TestingSwapChainBaseTest, LoadsReferenceImageIntoSwapChain)
163296
TEX_FORMAT_RGBA8_UNORM, ImageName.c_str(), false);
164297
ASSERT_TRUE(pTestingSwapChain->LoadReferenceImage(ImagePath.c_str()));
165298

166-
constexpr float ClearColor[] = {1, 0, 0, 1};
299+
// File references describe visible RGB output; render-target alpha is not
300+
// part of the comparison.
301+
constexpr float ClearColor[] = {1, 1, 1, 0};
167302
ITextureView* pRTV = pSwapChain->GetCurrentBackBufferRTV();
168303
pContext->SetRenderTargets(1, &pRTV, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
169304
pContext->ClearRenderTarget(pRTV, ClearColor,
170305
RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
171306
pTestingSwapChain->CompareWithSnapshot(nullptr);
172307
}
173308

174-
TEST(TestingSwapChainBaseTest, ReportsComparisonFailure)
309+
TEST(TestingSwapChainBaseTest, ReportsSnapshotRedComparisonFailure)
175310
{
176-
GPUTestingEnvironment::ScopedReset AutoReset;
177-
178-
GPUTestingEnvironment* const pEnvironment = GPUTestingEnvironment::GetInstance();
179-
IDeviceContext* const pContext = pEnvironment->GetDeviceContext();
180-
ISwapChain* const pSwapChain = pEnvironment->GetSwapChain();
181-
ASSERT_NE(pContext, nullptr);
182-
ASSERT_NE(pSwapChain, nullptr);
311+
TestSnapshotComparisonFailure(0);
312+
}
183313

184-
RefCntAutoPtr<ITestingSwapChain> pTestingSwapChain{pSwapChain, IID_TestingSwapChain};
185-
ASSERT_NE(pTestingSwapChain, nullptr);
314+
TEST(TestingSwapChainBaseTest, ReportsSnapshotGreenComparisonFailure)
315+
{
316+
TestSnapshotComparisonFailure(1);
317+
}
186318

187-
const SwapChainDesc& SwapChainDesc = pSwapChain->GetDesc();
188-
std::vector<Uint8> ReferencePixels(static_cast<size_t>(SwapChainDesc.Width) * SwapChainDesc.Height * 4, 0);
189-
for (size_t Pixel = 3; Pixel < ReferencePixels.size(); Pixel += 4)
190-
ReferencePixels[Pixel] = 255;
319+
TEST(TestingSwapChainBaseTest, ReportsSnapshotBlueComparisonFailure)
320+
{
321+
TestSnapshotComparisonFailure(2);
322+
}
191323

192-
TempDirectory TempDir{"TestingSwapChainBaseTest"};
193-
const std::string ImageName = TempDir.Get() + "/Reference";
194-
const std::string ImagePath = ImageName + ".png";
195-
DumpTestImage(ReferencePixels.data(), Uint64{SwapChainDesc.Width} * 4,
196-
SwapChainDesc.Width, SwapChainDesc.Height,
197-
TEX_FORMAT_RGBA8_UNORM, ImageName.c_str(), false);
198-
ASSERT_TRUE(pTestingSwapChain->LoadReferenceImage(ImagePath.c_str()));
324+
TEST(TestingSwapChainBaseTest, ReportsSnapshotAlphaComparisonFailure)
325+
{
326+
TestSnapshotComparisonFailure(3);
327+
}
199328

200-
constexpr float ClearColor[] = {1, 1, 1, 1};
201-
ITextureView* pRTV = pSwapChain->GetCurrentBackBufferRTV();
202-
pContext->SetRenderTargets(1, &pRTV, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
203-
pContext->ClearRenderTarget(pRTV, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
329+
TEST(TestingSwapChainBaseTest, ReportsImageRedComparisonFailure)
330+
{
331+
TestImageComparisonFailure(0);
332+
}
204333

205-
EXPECT_NONFATAL_FAILURE(
206-
pTestingSwapChain->CompareWithSnapshot(nullptr),
207-
"Image rendered by the test differs from the reference image");
334+
TEST(TestingSwapChainBaseTest, ReportsImageGreenComparisonFailure)
335+
{
336+
TestImageComparisonFailure(1);
337+
}
208338

209-
FileSystem::DeleteFile("TestingSwapChainBaseTest.ReportsComparisonFailure_FAIL_.png");
339+
TEST(TestingSwapChainBaseTest, ReportsImageBlueComparisonFailure)
340+
{
341+
TestImageComparisonFailure(2);
210342
}
211343

212344
#endif

Tests/GPUTestFramework/include/TestingSwapChainBase.hpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,24 @@ void CompareTestImages(const Uint8* pReferencePixels,
6565
Uint32 Height,
6666
TEXTURE_FORMAT Format,
6767
std::unordered_map<std::string, int>& FailureCounters,
68-
const TestImageComparisonAttribs& ComparisonAttribs = {});
68+
const TestImageComparisonAttribs& ComparisonAttribs = {},
69+
bool CompareAlpha = true);
6970

7071
/// Loads an RGBA8 reference image from a PNG file.
7172
bool LoadTestImage(const char* FilePath,
7273
std::vector<Uint8>& Pixels,
7374
Uint32& Width,
7475
Uint32& Height);
7576

77+
/// Writes the image to a PNG file. Alpha is omitted by default.
7678
void DumpTestImage(const Uint8* pPixels,
7779
Uint64 PixelsStride,
7880
Uint32 Width,
7981
Uint32 Height,
8082
TEXTURE_FORMAT Format,
8183
const char* DumpName,
82-
bool bIsOpenGL);
84+
bool bIsOpenGL,
85+
bool KeepAlpha = false);
8386

8487
// {41BF4655-9B33-4E6C-9300-0CB45FBFE104}
8588
static constexpr INTERFACE_ID IID_TestingSwapChain =
@@ -94,15 +97,17 @@ class ITestingSwapChain : public IObject
9497
/// Data must contain rows matching the swap-chain dimensions and color format.
9598
virtual void SetReferenceData(const void* pData, size_t Stride = 0) = 0;
9699

97-
/// Loads the reference image used by Present()/CompareWithSnapshot() from a PNG file.
100+
/// Loads the RGB reference image used by Present()/CompareWithSnapshot() from a PNG file.
101+
/// The alpha channel is ignored when comparing file-based references.
98102
virtual bool LoadReferenceImage(const char* FilePath) = 0;
99103

100104
/// Sets image comparison settings. Exact comparison is used by default.
101105
virtual void SetImageComparisonAttribs(const TestImageComparisonAttribs& Attribs) = 0;
102106

103107
virtual ITextureView* GetCurrentBackBufferUAV() = 0;
104108

105-
virtual void DumpBackBuffer(const char* FileName) = 0;
109+
/// Writes the back buffer to a PNG file. Alpha is omitted by default.
110+
virtual void DumpBackBuffer(const char* FileName, bool KeepAlpha = false) = 0;
106111

107112
virtual void CompareWithSnapshot(ITexture* pTexture) = 0;
108113
};
@@ -185,6 +190,7 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
185190
pSrcData + row * Stride,
186191
RowSize);
187192
}
193+
m_ReferenceSource = ReferenceSource::Snapshot;
188194
}
189195

190196
virtual bool LoadReferenceImage(const char* FilePath) override final
@@ -223,6 +229,10 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
223229
SetReferenceData(Pixels.data(), RowStride);
224230
}
225231

232+
// Golden PNGs represent the visible framebuffer. DumpTestImage() omits
233+
// alpha so image viewers display the complete rendered background.
234+
m_ReferenceSource = ReferenceSource::Image;
235+
226236
return true;
227237
}
228238

@@ -293,7 +303,7 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
293303
return m_SwapChainDesc;
294304
}
295305

296-
virtual void DumpBackBuffer(const char* FileName) override final
306+
virtual void DumpBackBuffer(const char* FileName, bool KeepAlpha = false) override final
297307
{
298308
m_pContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_NONE);
299309

@@ -318,7 +328,7 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
318328
}
319329

320330
m_pContext->MapTextureSubresource(m_pStagingTexture, 0, 0, MAP_READ, MapFlag, nullptr, MapData);
321-
DumpTestImage(static_cast<const Uint8*>(MapData.pData), MapData.Stride, m_SwapChainDesc.Width, m_SwapChainDesc.Height, m_SwapChainDesc.ColorBufferFormat, FileName, m_pDevice->GetDeviceInfo().IsGLDevice());
331+
DumpTestImage(static_cast<const Uint8*>(MapData.pData), MapData.Stride, m_SwapChainDesc.Width, m_SwapChainDesc.Height, m_SwapChainDesc.ColorBufferFormat, FileName, m_pDevice->GetDeviceInfo().IsGLDevice(), KeepAlpha);
322332
m_pContext->UnmapTextureSubresource(m_pStagingTexture, 0, 0);
323333
}
324334

@@ -355,12 +365,18 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
355365
m_pContext->MapTextureSubresource(m_pStagingTexture, 0, 0, MAP_READ, MapFlag, nullptr, MapData);
356366
CompareTestImages(m_ReferenceData.data(), m_ReferenceDataPitch, static_cast<const Uint8*>(MapData.pData), MapData.Stride,
357367
m_SwapChainDesc.Width, m_SwapChainDesc.Height, m_SwapChainDesc.ColorBufferFormat, m_FailureCounters,
358-
m_ImageComparisonAttribs);
368+
m_ImageComparisonAttribs, m_ReferenceSource == ReferenceSource::Snapshot);
359369

360370
m_pContext->UnmapTextureSubresource(m_pStagingTexture, 0, 0);
361371
}
362372

363373
protected:
374+
enum class ReferenceSource
375+
{
376+
Snapshot,
377+
Image
378+
};
379+
364380
virtual void ResizeBackendResources() = 0;
365381

366382
void CreateResources()
@@ -446,6 +462,7 @@ class TestingSwapChainBase : public RefCountedObject<SwapChainCombinedBaseInterf
446462

447463
std::vector<Uint8> m_ReferenceData;
448464
Uint32 m_ReferenceDataPitch = 0;
465+
ReferenceSource m_ReferenceSource = ReferenceSource::Snapshot;
449466

450467
TestImageComparisonAttribs m_ImageComparisonAttribs;
451468
};

Tests/GPUTestFramework/src/D3D11/TestingSwapChainD3D11.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ void TestingSwapChainD3D11::ResizeBackendResources()
114114

115115
void TestingSwapChainD3D11::TakeSnapshot(ITexture* pCopyFrom)
116116
{
117+
m_ReferenceSource = ReferenceSource::Snapshot;
118+
117119
ID3D11Texture2D* pSrcRT = m_pd3d11RenderTarget;
118120
if (pCopyFrom != nullptr)
119121
{

0 commit comments

Comments
 (0)