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(&copySrc, &copyDst, &copySize);
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