1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "tests/DawnTest.h"
16
17 #include <d3d11.h>
18 #include <d3d12.h>
19 #include <dxgi1_4.h>
20 #include <wrl/client.h>
21
22 #include "dawn_native/D3D12Backend.h"
23 #include "utils/ComboRenderPipelineDescriptor.h"
24 #include "utils/WGPUHelpers.h"
25
26 using Microsoft::WRL::ComPtr;
27
28 namespace {
29
30 class D3D12ResourceTestBase : public DawnTest {
31 public:
SetUp()32 void SetUp() override {
33 DawnTest::SetUp();
34 if (UsesWire()) {
35 return;
36 }
37
38 // Create the D3D11 device/contexts that will be used in subsequent tests
39 ComPtr<ID3D12Device> d3d12Device = dawn_native::d3d12::GetD3D12Device(device.Get());
40
41 const LUID adapterLuid = d3d12Device->GetAdapterLuid();
42
43 ComPtr<IDXGIFactory4> dxgiFactory;
44 HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
45 ASSERT_EQ(hr, S_OK);
46
47 ComPtr<IDXGIAdapter> dxgiAdapter;
48 hr = dxgiFactory->EnumAdapterByLuid(adapterLuid, IID_PPV_ARGS(&dxgiAdapter));
49 ASSERT_EQ(hr, S_OK);
50
51 ComPtr<ID3D11Device> d3d11Device;
52 D3D_FEATURE_LEVEL d3dFeatureLevel;
53 ComPtr<ID3D11DeviceContext> d3d11DeviceContext;
54 hr = ::D3D11CreateDevice(dxgiAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
55 nullptr, 0, D3D11_SDK_VERSION, &d3d11Device, &d3dFeatureLevel,
56 &d3d11DeviceContext);
57 ASSERT_EQ(hr, S_OK);
58
59 mD3d11Device = std::move(d3d11Device);
60 mD3d11DeviceContext = std::move(d3d11DeviceContext);
61
62 baseDawnDescriptor.dimension = wgpu::TextureDimension::e2D;
63 baseDawnDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
64 baseDawnDescriptor.size = {kTestWidth, kTestHeight, 1};
65 baseDawnDescriptor.sampleCount = 1;
66 baseDawnDescriptor.mipLevelCount = 1;
67 baseDawnDescriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopySrc |
68 wgpu::TextureUsage::RenderAttachment |
69 wgpu::TextureUsage::CopyDst;
70
71 baseD3dDescriptor.Width = kTestWidth;
72 baseD3dDescriptor.Height = kTestHeight;
73 baseD3dDescriptor.MipLevels = 1;
74 baseD3dDescriptor.ArraySize = 1;
75 baseD3dDescriptor.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
76 baseD3dDescriptor.SampleDesc.Count = 1;
77 baseD3dDescriptor.SampleDesc.Quality = 0;
78 baseD3dDescriptor.Usage = D3D11_USAGE_DEFAULT;
79 baseD3dDescriptor.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
80 baseD3dDescriptor.CPUAccessFlags = 0;
81 baseD3dDescriptor.MiscFlags =
82 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
83 }
84
85 protected:
WrapSharedHandle(const wgpu::TextureDescriptor * dawnDesc,const D3D11_TEXTURE2D_DESC * baseD3dDescriptor,wgpu::Texture * dawnTexture,ID3D11Texture2D ** d3d11TextureOut) const86 void WrapSharedHandle(const wgpu::TextureDescriptor* dawnDesc,
87 const D3D11_TEXTURE2D_DESC* baseD3dDescriptor,
88 wgpu::Texture* dawnTexture,
89 ID3D11Texture2D** d3d11TextureOut) const {
90 ComPtr<ID3D11Texture2D> d3d11Texture;
91 HRESULT hr = mD3d11Device->CreateTexture2D(baseD3dDescriptor, nullptr, &d3d11Texture);
92 ASSERT_EQ(hr, S_OK);
93
94 ComPtr<IDXGIResource1> dxgiResource;
95 hr = d3d11Texture.As(&dxgiResource);
96 ASSERT_EQ(hr, S_OK);
97
98 HANDLE sharedHandle;
99 hr = dxgiResource->CreateSharedHandle(
100 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
101 &sharedHandle);
102 ASSERT_EQ(hr, S_OK);
103
104 dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc;
105 externDesc.cTextureDescriptor =
106 reinterpret_cast<const WGPUTextureDescriptor*>(dawnDesc);
107 externDesc.sharedHandle = sharedHandle;
108 externDesc.acquireMutexKey = 0;
109 WGPUTexture texture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc);
110
111 // Now that we've created all of our resources, we can close the handle
112 // since we no longer need it.
113 ::CloseHandle(sharedHandle);
114
115 *dawnTexture = wgpu::Texture::Acquire(texture);
116 *d3d11TextureOut = d3d11Texture.Detach();
117 }
118
119 static constexpr size_t kTestWidth = 10;
120 static constexpr size_t kTestHeight = 10;
121
122 ComPtr<ID3D11Device> mD3d11Device;
123 ComPtr<ID3D11DeviceContext> mD3d11DeviceContext;
124
125 D3D11_TEXTURE2D_DESC baseD3dDescriptor;
126 wgpu::TextureDescriptor baseDawnDescriptor;
127 };
128
129 } // anonymous namespace
130
131 // A small fixture used to initialize default data for the D3D12Resource validation tests.
132 // These tests are skipped if the harness is using the wire.
133 class D3D12SharedHandleValidation : public D3D12ResourceTestBase {};
134
135 // Test a successful wrapping of an D3D12Resource in a texture
TEST_P(D3D12SharedHandleValidation,Success)136 TEST_P(D3D12SharedHandleValidation, Success) {
137 DAWN_SKIP_TEST_IF(UsesWire());
138
139 wgpu::Texture texture;
140 ComPtr<ID3D11Texture2D> d3d11Texture;
141 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture);
142
143 ASSERT_NE(texture.Get(), nullptr);
144 }
145
146 // Test an error occurs if the texture descriptor is invalid
TEST_P(D3D12SharedHandleValidation,InvalidTextureDescriptor)147 TEST_P(D3D12SharedHandleValidation, InvalidTextureDescriptor) {
148 DAWN_SKIP_TEST_IF(UsesWire());
149
150 wgpu::ChainedStruct chainedDescriptor;
151 baseDawnDescriptor.nextInChain = &chainedDescriptor;
152
153 wgpu::Texture texture;
154 ComPtr<ID3D11Texture2D> d3d11Texture;
155 ASSERT_DEVICE_ERROR(
156 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
157
158 ASSERT_EQ(texture.Get(), nullptr);
159 }
160
161 // Test an error occurs if the descriptor mip level count isn't 1
TEST_P(D3D12SharedHandleValidation,InvalidMipLevelCount)162 TEST_P(D3D12SharedHandleValidation, InvalidMipLevelCount) {
163 DAWN_SKIP_TEST_IF(UsesWire());
164 baseDawnDescriptor.mipLevelCount = 2;
165
166 wgpu::Texture texture;
167 ComPtr<ID3D11Texture2D> d3d11Texture;
168 ASSERT_DEVICE_ERROR(
169 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
170
171 ASSERT_EQ(texture.Get(), nullptr);
172 }
173
174 // Test an error occurs if the descriptor depth isn't 1
TEST_P(D3D12SharedHandleValidation,InvalidDepth)175 TEST_P(D3D12SharedHandleValidation, InvalidDepth) {
176 DAWN_SKIP_TEST_IF(UsesWire());
177 baseDawnDescriptor.size.depth = 2;
178
179 wgpu::Texture texture;
180 ComPtr<ID3D11Texture2D> d3d11Texture;
181 ASSERT_DEVICE_ERROR(
182 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
183
184 ASSERT_EQ(texture.Get(), nullptr);
185 }
186
187 // Test an error occurs if the descriptor sample count isn't 1
TEST_P(D3D12SharedHandleValidation,InvalidSampleCount)188 TEST_P(D3D12SharedHandleValidation, InvalidSampleCount) {
189 DAWN_SKIP_TEST_IF(UsesWire());
190 baseDawnDescriptor.sampleCount = 4;
191
192 wgpu::Texture texture;
193 ComPtr<ID3D11Texture2D> d3d11Texture;
194 ASSERT_DEVICE_ERROR(
195 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
196
197 ASSERT_EQ(texture.Get(), nullptr);
198 }
199
200 // Test an error occurs if the descriptor width doesn't match the texture's
TEST_P(D3D12SharedHandleValidation,InvalidWidth)201 TEST_P(D3D12SharedHandleValidation, InvalidWidth) {
202 DAWN_SKIP_TEST_IF(UsesWire());
203 baseDawnDescriptor.size.width = kTestWidth + 1;
204
205 wgpu::Texture texture;
206 ComPtr<ID3D11Texture2D> d3d11Texture;
207 ASSERT_DEVICE_ERROR(
208 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
209
210 ASSERT_EQ(texture.Get(), nullptr);
211 }
212
213 // Test an error occurs if the descriptor height doesn't match the texture's
TEST_P(D3D12SharedHandleValidation,InvalidHeight)214 TEST_P(D3D12SharedHandleValidation, InvalidHeight) {
215 DAWN_SKIP_TEST_IF(UsesWire());
216 baseDawnDescriptor.size.height = kTestHeight + 1;
217
218 wgpu::Texture texture;
219 ComPtr<ID3D11Texture2D> d3d11Texture;
220 ASSERT_DEVICE_ERROR(
221 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
222
223 ASSERT_EQ(texture.Get(), nullptr);
224 }
225
226 // Test an error occurs if the descriptor format isn't compatible with the D3D12 Resource
TEST_P(D3D12SharedHandleValidation,InvalidFormat)227 TEST_P(D3D12SharedHandleValidation, InvalidFormat) {
228 DAWN_SKIP_TEST_IF(UsesWire());
229 baseDawnDescriptor.format = wgpu::TextureFormat::R8Unorm;
230
231 wgpu::Texture texture;
232 ComPtr<ID3D11Texture2D> d3d11Texture;
233 ASSERT_DEVICE_ERROR(
234 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
235
236 ASSERT_EQ(texture.Get(), nullptr);
237 }
238
239 // Test an error occurs if the number of D3D mip levels is greater than 1.
TEST_P(D3D12SharedHandleValidation,InvalidNumD3DMipLevels)240 TEST_P(D3D12SharedHandleValidation, InvalidNumD3DMipLevels) {
241 DAWN_SKIP_TEST_IF(UsesWire());
242 baseD3dDescriptor.MipLevels = 2;
243
244 wgpu::Texture texture;
245 ComPtr<ID3D11Texture2D> d3d11Texture;
246 ASSERT_DEVICE_ERROR(
247 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
248
249 ASSERT_EQ(texture.Get(), nullptr);
250 }
251
252 // Test an error occurs if the number of array levels is greater than 1.
TEST_P(D3D12SharedHandleValidation,InvalidD3DArraySize)253 TEST_P(D3D12SharedHandleValidation, InvalidD3DArraySize) {
254 DAWN_SKIP_TEST_IF(UsesWire());
255 baseD3dDescriptor.ArraySize = 2;
256
257 wgpu::Texture texture;
258 ComPtr<ID3D11Texture2D> d3d11Texture;
259 ASSERT_DEVICE_ERROR(
260 WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture));
261
262 ASSERT_EQ(texture.Get(), nullptr);
263 }
264
265 class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
266 protected:
267 // Submits a 1x1x1 copy from source to destination
SimpleCopyTextureToTexture(wgpu::Texture source,wgpu::Texture destination)268 void SimpleCopyTextureToTexture(wgpu::Texture source, wgpu::Texture destination) {
269 wgpu::TextureCopyView copySrc = utils::CreateTextureCopyView(source, 0, {0, 0, 0});
270 wgpu::TextureCopyView copyDst = utils::CreateTextureCopyView(destination, 0, {0, 0, 0});
271
272 wgpu::Extent3D copySize = {1, 1, 1};
273
274 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
275 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size);
276 wgpu::CommandBuffer commands = encoder.Finish();
277
278 queue.Submit(1, &commands);
279 }
280
281 // Clear a texture on a given device
ClearImage(wgpu::Texture wrappedTexture,const wgpu::Color & clearColor)282 void ClearImage(wgpu::Texture wrappedTexture, const wgpu::Color& clearColor) {
283 wgpu::TextureView wrappedView = wrappedTexture.CreateView();
284
285 // Submit a clear operation
286 utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {});
287 renderPassDescriptor.cColorAttachments[0].clearColor = clearColor;
288
289 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
290 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
291 pass.EndPass();
292
293 wgpu::CommandBuffer commands = encoder.Finish();
294 queue.Submit(1, &commands);
295 }
296
WrapAndClearD3D11Texture(const wgpu::TextureDescriptor * dawnDescriptor,const D3D11_TEXTURE2D_DESC * d3dDescriptor,wgpu::Texture * dawnTextureOut,const wgpu::Color & clearColor,ID3D11Texture2D ** d3d11TextureOut,IDXGIKeyedMutex ** dxgiKeyedMutexOut,bool isInitialized=true) const297 void WrapAndClearD3D11Texture(const wgpu::TextureDescriptor* dawnDescriptor,
298 const D3D11_TEXTURE2D_DESC* d3dDescriptor,
299 wgpu::Texture* dawnTextureOut,
300 const wgpu::Color& clearColor,
301 ID3D11Texture2D** d3d11TextureOut,
302 IDXGIKeyedMutex** dxgiKeyedMutexOut,
303 bool isInitialized = true) const {
304 ComPtr<ID3D11Texture2D> d3d11Texture;
305 HRESULT hr = mD3d11Device->CreateTexture2D(d3dDescriptor, nullptr, &d3d11Texture);
306 ASSERT_EQ(hr, S_OK);
307
308 ComPtr<IDXGIResource1> dxgiResource;
309 hr = d3d11Texture.As(&dxgiResource);
310 ASSERT_EQ(hr, S_OK);
311
312 HANDLE sharedHandle;
313 hr = dxgiResource->CreateSharedHandle(
314 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
315 &sharedHandle);
316 ASSERT_EQ(hr, S_OK);
317
318 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
319 hr = d3d11Texture.As(&dxgiKeyedMutex);
320 ASSERT_EQ(hr, S_OK);
321
322 ComPtr<ID3D11RenderTargetView> d3d11RTV;
323 hr = mD3d11Device->CreateRenderTargetView(d3d11Texture.Get(), nullptr, &d3d11RTV);
324 ASSERT_EQ(hr, S_OK);
325
326 hr = dxgiKeyedMutex->AcquireSync(0, INFINITE);
327 ASSERT_EQ(hr, S_OK);
328
329 const float colorRGBA[] = {
330 static_cast<float>(clearColor.r), static_cast<float>(clearColor.g),
331 static_cast<float>(clearColor.b), static_cast<float>(clearColor.a)};
332 mD3d11DeviceContext->ClearRenderTargetView(d3d11RTV.Get(), colorRGBA);
333
334 hr = dxgiKeyedMutex->ReleaseSync(1);
335 ASSERT_EQ(hr, S_OK);
336
337 dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle externDesc;
338 externDesc.cTextureDescriptor =
339 reinterpret_cast<const WGPUTextureDescriptor*>(dawnDescriptor);
340 externDesc.sharedHandle = sharedHandle;
341 externDesc.acquireMutexKey = 1;
342 externDesc.isInitialized = isInitialized;
343 WGPUTexture dawnTexture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc);
344
345 *dawnTextureOut = wgpu::Texture::Acquire(dawnTexture);
346 *d3d11TextureOut = d3d11Texture.Detach();
347 *dxgiKeyedMutexOut = dxgiKeyedMutex.Detach();
348 }
349
ExpectPixelRGBA8EQ(UINT64 acquireKey,ID3D11Texture2D * d3d11Texture,IDXGIKeyedMutex * dxgiKeyedMutex,const wgpu::Color & color)350 void ExpectPixelRGBA8EQ(UINT64 acquireKey,
351 ID3D11Texture2D* d3d11Texture,
352 IDXGIKeyedMutex* dxgiKeyedMutex,
353 const wgpu::Color& color) {
354 HRESULT hr = dxgiKeyedMutex->AcquireSync(acquireKey, INFINITE);
355 ASSERT_EQ(hr, S_OK);
356
357 D3D11_TEXTURE2D_DESC texture2DDesc;
358 d3d11Texture->GetDesc(&texture2DDesc);
359
360 const CD3D11_TEXTURE2D_DESC texture2DStagingDesc(
361 texture2DDesc.Format, // Format
362 texture2DDesc.Width, // Width
363 texture2DDesc.Height, // Height
364 1, // ArraySize
365 1, // MipLevels
366 0, // BindFlags
367 D3D11_USAGE_STAGING, // Usage
368 D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); // CPUAccessFlags
369
370 ComPtr<ID3D11Texture2D> spD3DTextureStaging;
371 hr = mD3d11Device->CreateTexture2D(&texture2DStagingDesc, nullptr, &spD3DTextureStaging);
372 ASSERT_EQ(hr, S_OK);
373
374 D3D11_BOX d3dRc;
375 d3dRc.back = 1;
376 d3dRc.front = 0;
377 d3dRc.top = 0;
378 d3dRc.left = 0;
379 d3dRc.bottom = texture2DDesc.Height;
380 d3dRc.right = texture2DDesc.Width;
381
382 mD3d11DeviceContext->CopySubresourceRegion(spD3DTextureStaging.Get(), // pDstResource
383 0, // DstSubresource
384 0, // DstX
385 0, // DstY
386 0, // DstZ
387 d3d11Texture, // pSrcResource
388 0, // SrcSubresource
389 &d3dRc); // pSrcBox
390
391 D3D11_MAPPED_SUBRESOURCE mappedResource;
392 hr = mD3d11DeviceContext->Map(spD3DTextureStaging.Get(), 0, D3D11_MAP_READ_WRITE, 0,
393 &mappedResource);
394 ASSERT_EQ(hr, S_OK);
395
396 const uint8_t* colorData = static_cast<uint8_t*>(mappedResource.pData);
397 EXPECT_EQ(colorData[0], color.r * 255u);
398 EXPECT_EQ(colorData[1], color.g * 255u);
399 EXPECT_EQ(colorData[2], color.b * 255u);
400 EXPECT_EQ(colorData[3], color.a * 255u);
401
402 mD3d11DeviceContext->Unmap(spD3DTextureStaging.Get(), 0);
403
404 hr = dxgiKeyedMutex->ReleaseSync(acquireKey + 1);
405 ASSERT_EQ(hr, S_OK);
406 }
407 };
408
409 // 1. Create and clear a D3D11 texture
410 // 2. Copy the wrapped texture to another dawn texture
411 // 3. Readback the copied texture and ensure the color matches the original clear color.
TEST_P(D3D12SharedHandleUsageTests,ClearInD3D11CopyAndReadbackInD3D12)412 TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11CopyAndReadbackInD3D12) {
413 DAWN_SKIP_TEST_IF(UsesWire());
414
415 const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f};
416 wgpu::Texture dawnSrcTexture;
417 ComPtr<ID3D11Texture2D> d3d11Texture;
418 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
419 WrapAndClearD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &dawnSrcTexture, clearColor,
420 &d3d11Texture, &dxgiKeyedMutex);
421
422 // Create a texture on the device and copy the source texture to it.
423 wgpu::Texture dawnCopyDestTexture = device.CreateTexture(&baseDawnDescriptor);
424 SimpleCopyTextureToTexture(dawnSrcTexture, dawnCopyDestTexture);
425
426 // Readback the destination texture and ensure it contains the colors we used
427 // to clear the source texture on the D3D device.
428 EXPECT_PIXEL_RGBA8_EQ(
429 RGBA8(clearColor.r * 255u, clearColor.g * 255u, clearColor.b * 255u, clearColor.a * 255u),
430 dawnCopyDestTexture, 0, 0);
431 }
432
433 // 1. Create and clear a D3D11 texture
434 // 2. Readback the wrapped texture and ensure the color matches the original clear color.
TEST_P(D3D12SharedHandleUsageTests,ClearInD3D11ReadbackInD3D12)435 TEST_P(D3D12SharedHandleUsageTests, ClearInD3D11ReadbackInD3D12) {
436 DAWN_SKIP_TEST_IF(UsesWire());
437
438 const wgpu::Color clearColor{1.0f, 1.0f, 0.0f, 1.0f};
439 wgpu::Texture dawnTexture;
440 ComPtr<ID3D11Texture2D> d3d11Texture;
441 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
442 WrapAndClearD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &dawnTexture, clearColor,
443 &d3d11Texture, &dxgiKeyedMutex);
444
445 // Readback the destination texture and ensure it contains the colors we used
446 // to clear the source texture on the D3D device.
447 EXPECT_PIXEL_RGBA8_EQ(
448 RGBA8(clearColor.r * 255, clearColor.g * 255, clearColor.b * 255, clearColor.a * 255),
449 dawnTexture, 0, 0);
450 }
451
452 // 1. Create and clear a D3D11 texture
453 // 2. Wrap it in a Dawn texture and clear it to a different color
454 // 3. Readback the texture with D3D11 and ensure we receive the color we cleared with Dawn.
TEST_P(D3D12SharedHandleUsageTests,ClearInD3D12ReadbackInD3D11)455 TEST_P(D3D12SharedHandleUsageTests, ClearInD3D12ReadbackInD3D11) {
456 DAWN_SKIP_TEST_IF(UsesWire());
457
458 const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f};
459 wgpu::Texture dawnTexture;
460 ComPtr<ID3D11Texture2D> d3d11Texture;
461 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
462 WrapAndClearD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &dawnTexture, d3d11ClearColor,
463 &d3d11Texture, &dxgiKeyedMutex);
464
465 const wgpu::Color d3d12ClearColor{0.0f, 0.0f, 1.0f, 1.0f};
466 ClearImage(dawnTexture, d3d12ClearColor);
467
468 dawnTexture.Destroy();
469
470 // Now that Dawn (via D3D12) has finished writing to the texture, we should be
471 // able to read it back by copying it to a staging texture and verifying the
472 // color matches the D3D12 clear color.
473 ExpectPixelRGBA8EQ(2, d3d11Texture.Get(), dxgiKeyedMutex.Get(), d3d12ClearColor);
474 }
475
476 // 1. Create and clear a D3D11 texture
477 // 2. Wrap it in a Dawn texture and clear the texture to two different colors.
478 // 3. Readback the texture with D3D11.
479 // 4. Verify the readback color was the final color cleared.
TEST_P(D3D12SharedHandleUsageTests,ClearTwiceInD3D12ReadbackInD3D11)480 TEST_P(D3D12SharedHandleUsageTests, ClearTwiceInD3D12ReadbackInD3D11) {
481 DAWN_SKIP_TEST_IF(UsesWire());
482
483 const wgpu::Color d3d11ClearColor{1.0f, 1.0f, 0.0f, 1.0f};
484 wgpu::Texture dawnTexture;
485 ComPtr<ID3D11Texture2D> d3d11Texture;
486 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
487 WrapAndClearD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &dawnTexture, d3d11ClearColor,
488 &d3d11Texture, &dxgiKeyedMutex);
489
490 const wgpu::Color d3d12ClearColor1{0.0f, 0.0f, 1.0f, 1.0f};
491 ClearImage(dawnTexture, d3d12ClearColor1);
492
493 const wgpu::Color d3d12ClearColor2{0.0f, 1.0f, 1.0f, 1.0f};
494 ClearImage(dawnTexture, d3d12ClearColor2);
495
496 dawnTexture.Destroy();
497
498 // Now that Dawn (via D3D12) has finished writing to the texture, we should be
499 // able to read it back by copying it to a staging texture and verifying the
500 // color matches the last D3D12 clear color.
501 ExpectPixelRGBA8EQ(2, d3d11Texture.Get(), dxgiKeyedMutex.Get(), d3d12ClearColor2);
502 }
503
504 // 1. Create and clear a D3D11 texture with clearColor
505 // 2. Import the texture with isInitialized = false
506 // 3. Verify clearColor is not visible in wrapped texture
TEST_P(D3D12SharedHandleUsageTests,UninitializedTextureIsCleared)507 TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) {
508 DAWN_SKIP_TEST_IF(UsesWire());
509
510 const wgpu::Color clearColor{1.0f, 0.0f, 0.0f, 1.0f};
511 wgpu::Texture dawnTexture;
512 ComPtr<ID3D11Texture2D> d3d11Texture;
513 ComPtr<IDXGIKeyedMutex> dxgiKeyedMutex;
514 WrapAndClearD3D11Texture(&baseDawnDescriptor, &baseD3dDescriptor, &dawnTexture, clearColor,
515 &d3d11Texture, &dxgiKeyedMutex, false);
516
517 // Readback the destination texture and ensure it contains the colors we used
518 // to clear the source texture on the D3D device.
519 EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), dawnTexture, 0, 0);
520 }
521
522 DAWN_INSTANTIATE_TEST(D3D12SharedHandleValidation, D3D12Backend());
523 DAWN_INSTANTIATE_TEST(D3D12SharedHandleUsageTests, D3D12Backend());
524