• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "dawn_native/MetalBackend.h"
18 #include "utils/ComboRenderPipelineDescriptor.h"
19 #include "utils/WGPUHelpers.h"
20 
21 #include <CoreFoundation/CoreFoundation.h>
22 #include <CoreVideo/CVPixelBuffer.h>
23 #include <IOSurface/IOSurface.h>
24 
25 namespace {
26 
AddIntegerValue(CFMutableDictionaryRef dictionary,const CFStringRef key,int32_t value)27     void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value) {
28         CFNumberRef number = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value);
29         CFDictionaryAddValue(dictionary, key, number);
30         CFRelease(number);
31     }
32 
33     class ScopedIOSurfaceRef {
34       public:
ScopedIOSurfaceRef()35         ScopedIOSurfaceRef() : mSurface(nullptr) {
36         }
ScopedIOSurfaceRef(IOSurfaceRef surface)37         explicit ScopedIOSurfaceRef(IOSurfaceRef surface) : mSurface(surface) {
38         }
39 
~ScopedIOSurfaceRef()40         ~ScopedIOSurfaceRef() {
41             if (mSurface != nullptr) {
42                 CFRelease(mSurface);
43                 mSurface = nullptr;
44             }
45         }
46 
get() const47         IOSurfaceRef get() const {
48             return mSurface;
49         }
50 
ScopedIOSurfaceRef(ScopedIOSurfaceRef && other)51         ScopedIOSurfaceRef(ScopedIOSurfaceRef&& other) {
52             if (mSurface != nullptr) {
53                 CFRelease(mSurface);
54             }
55             mSurface = other.mSurface;
56             other.mSurface = nullptr;
57         }
58 
operator =(ScopedIOSurfaceRef && other)59         ScopedIOSurfaceRef& operator=(ScopedIOSurfaceRef&& other) {
60             if (mSurface != nullptr) {
61                 CFRelease(mSurface);
62             }
63             mSurface = other.mSurface;
64             other.mSurface = nullptr;
65 
66             return *this;
67         }
68 
69         ScopedIOSurfaceRef(const ScopedIOSurfaceRef&) = delete;
70         ScopedIOSurfaceRef& operator=(const ScopedIOSurfaceRef&) = delete;
71 
72       private:
73         IOSurfaceRef mSurface = nullptr;
74     };
75 
CreateSinglePlaneIOSurface(uint32_t width,uint32_t height,uint32_t format,uint32_t bytesPerElement)76     ScopedIOSurfaceRef CreateSinglePlaneIOSurface(uint32_t width,
77                                                   uint32_t height,
78                                                   uint32_t format,
79                                                   uint32_t bytesPerElement) {
80         CFMutableDictionaryRef dict =
81             CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
82                                       &kCFTypeDictionaryValueCallBacks);
83         AddIntegerValue(dict, kIOSurfaceWidth, width);
84         AddIntegerValue(dict, kIOSurfaceHeight, height);
85         AddIntegerValue(dict, kIOSurfacePixelFormat, format);
86         AddIntegerValue(dict, kIOSurfaceBytesPerElement, bytesPerElement);
87 
88         IOSurfaceRef ioSurface = IOSurfaceCreate(dict);
89         EXPECT_NE(nullptr, ioSurface);
90         CFRelease(dict);
91 
92         return ScopedIOSurfaceRef(ioSurface);
93     }
94 
95     class IOSurfaceTestBase : public DawnTest {
96       public:
WrapIOSurface(const wgpu::TextureDescriptor * descriptor,IOSurfaceRef ioSurface,uint32_t plane,bool isInitialized=true)97         wgpu::Texture WrapIOSurface(const wgpu::TextureDescriptor* descriptor,
98                                     IOSurfaceRef ioSurface,
99                                     uint32_t plane,
100                                     bool isInitialized = true) {
101             dawn_native::metal::ExternalImageDescriptorIOSurface externDesc;
102             externDesc.cTextureDescriptor =
103                 reinterpret_cast<const WGPUTextureDescriptor*>(descriptor);
104             externDesc.ioSurface = ioSurface;
105             externDesc.plane = plane;
106             externDesc.isInitialized = isInitialized;
107             WGPUTexture texture = dawn_native::metal::WrapIOSurface(device.Get(), &externDesc);
108             return wgpu::Texture::Acquire(texture);
109         }
110     };
111 
112 }  // anonymous namespace
113 
114 // A small fixture used to initialize default data for the IOSurface validation tests.
115 // These tests are skipped if the harness is using the wire.
116 class IOSurfaceValidationTests : public IOSurfaceTestBase {
117   public:
IOSurfaceValidationTests()118     IOSurfaceValidationTests() {
119         defaultIOSurface = CreateSinglePlaneIOSurface(10, 10, kCVPixelFormatType_32BGRA, 4);
120 
121         descriptor.dimension = wgpu::TextureDimension::e2D;
122         descriptor.format = wgpu::TextureFormat::BGRA8Unorm;
123         descriptor.size = {10, 10, 1};
124         descriptor.sampleCount = 1;
125         descriptor.mipLevelCount = 1;
126         descriptor.usage = wgpu::TextureUsage::RenderAttachment;
127     }
128 
129   protected:
130     wgpu::TextureDescriptor descriptor;
131     ScopedIOSurfaceRef defaultIOSurface;
132 };
133 
134 // Test a successful wrapping of an IOSurface in a texture
TEST_P(IOSurfaceValidationTests,Success)135 TEST_P(IOSurfaceValidationTests, Success) {
136     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
137     wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get(), 0);
138     ASSERT_NE(texture.Get(), nullptr);
139 }
140 
141 // Test an error occurs if the texture descriptor is invalid
TEST_P(IOSurfaceValidationTests,InvalidTextureDescriptor)142 TEST_P(IOSurfaceValidationTests, InvalidTextureDescriptor) {
143     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
144 
145     wgpu::ChainedStruct chainedDescriptor;
146     descriptor.nextInChain = &chainedDescriptor;
147 
148     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
149                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
150     ASSERT_EQ(texture.Get(), nullptr);
151 }
152 
153 // Test an error occurs if the plane is too large
TEST_P(IOSurfaceValidationTests,PlaneTooLarge)154 TEST_P(IOSurfaceValidationTests, PlaneTooLarge) {
155     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
156     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
157                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 1));
158     ASSERT_EQ(texture.Get(), nullptr);
159 }
160 
161 // Test an error occurs if the descriptor dimension isn't 2D
162 // TODO(crbug.com/dawn/814): Test 1D textures when implemented
TEST_P(IOSurfaceValidationTests,InvalidTextureDimension)163 TEST_P(IOSurfaceValidationTests, InvalidTextureDimension) {
164     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
165     descriptor.dimension = wgpu::TextureDimension::e3D;
166 
167     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
168                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
169     ASSERT_EQ(texture.Get(), nullptr);
170 }
171 
172 // Test an error occurs if the descriptor mip level count isn't 1
TEST_P(IOSurfaceValidationTests,InvalidMipLevelCount)173 TEST_P(IOSurfaceValidationTests, InvalidMipLevelCount) {
174     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
175     descriptor.mipLevelCount = 2;
176 
177     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
178                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
179     ASSERT_EQ(texture.Get(), nullptr);
180 }
181 
182 // Test an error occurs if the descriptor depth isn't 1
TEST_P(IOSurfaceValidationTests,InvalidDepth)183 TEST_P(IOSurfaceValidationTests, InvalidDepth) {
184     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
185     descriptor.size.depthOrArrayLayers = 2;
186 
187     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
188                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
189     ASSERT_EQ(texture.Get(), nullptr);
190 }
191 
192 // Test an error occurs if the descriptor sample count isn't 1
TEST_P(IOSurfaceValidationTests,InvalidSampleCount)193 TEST_P(IOSurfaceValidationTests, InvalidSampleCount) {
194     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
195     descriptor.sampleCount = 4;
196 
197     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
198                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
199     ASSERT_EQ(texture.Get(), nullptr);
200 }
201 
202 // Test an error occurs if the descriptor width doesn't match the surface's
TEST_P(IOSurfaceValidationTests,InvalidWidth)203 TEST_P(IOSurfaceValidationTests, InvalidWidth) {
204     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
205     descriptor.size.width = 11;
206 
207     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
208                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
209     ASSERT_EQ(texture.Get(), nullptr);
210 }
211 
212 // Test an error occurs if the descriptor height doesn't match the surface's
TEST_P(IOSurfaceValidationTests,InvalidHeight)213 TEST_P(IOSurfaceValidationTests, InvalidHeight) {
214     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
215     descriptor.size.height = 11;
216 
217     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
218                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
219     ASSERT_EQ(texture.Get(), nullptr);
220 }
221 
222 // Test an error occurs if the descriptor format isn't compatible with the IOSurface's
TEST_P(IOSurfaceValidationTests,InvalidFormat)223 TEST_P(IOSurfaceValidationTests, InvalidFormat) {
224     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
225     descriptor.format = wgpu::TextureFormat::R8Unorm;
226 
227     ASSERT_DEVICE_ERROR(wgpu::Texture texture =
228                             WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
229     ASSERT_EQ(texture.Get(), nullptr);
230 }
231 
232 // Fixture to test using IOSurfaces through different usages.
233 // These tests are skipped if the harness is using the wire.
234 class IOSurfaceUsageTests : public IOSurfaceTestBase {
235   public:
236     // Test that sampling a 1x1 works.
DoSampleTest(IOSurfaceRef ioSurface,wgpu::TextureFormat format,void * data,size_t dataSize,RGBA8 expectedColor)237     void DoSampleTest(IOSurfaceRef ioSurface,
238                       wgpu::TextureFormat format,
239                       void* data,
240                       size_t dataSize,
241                       RGBA8 expectedColor) {
242         // Write the data to the IOSurface
243         IOSurfaceLock(ioSurface, 0, nullptr);
244         memcpy(IOSurfaceGetBaseAddress(ioSurface), data, dataSize);
245         IOSurfaceUnlock(ioSurface, 0, nullptr);
246 
247         // The simplest texture sampling pipeline.
248         wgpu::RenderPipeline pipeline;
249         {
250             wgpu::ShaderModule vs = utils::CreateShaderModule(device, R"(
251                 struct VertexOut {
252                     [[location(0)]] texCoord : vec2<f32>;
253                     [[builtin(position)]] position : vec4<f32>;
254                 };
255 
256                 [[stage(vertex)]]
257                 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> VertexOut {
258                     var pos = array<vec2<f32>, 6>(
259                         vec2<f32>(-2.0, -2.0),
260                         vec2<f32>(-2.0,  2.0),
261                         vec2<f32>( 2.0, -2.0),
262                         vec2<f32>(-2.0,  2.0),
263                         vec2<f32>( 2.0, -2.0),
264                         vec2<f32>( 2.0,  2.0));
265 
266                     var texCoord = array<vec2<f32>, 6>(
267                         vec2<f32>(0.0, 0.0),
268                         vec2<f32>(0.0, 1.0),
269                         vec2<f32>(1.0, 0.0),
270                         vec2<f32>(0.0, 1.0),
271                         vec2<f32>(1.0, 0.0),
272                         vec2<f32>(1.0, 1.0));
273 
274                     var output : VertexOut;
275                     output.position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
276                     output.texCoord = texCoord[VertexIndex];
277                     return output;
278                 }
279             )");
280             wgpu::ShaderModule fs = utils::CreateShaderModule(device, R"(
281                 [[group(0), binding(0)]] var sampler0 : sampler;
282                 [[group(0), binding(1)]] var texture0 : texture_2d<f32>;
283 
284                 [[stage(fragment)]]
285                 fn main([[location(0)]] texCoord : vec2<f32>) -> [[location(0)]] vec4<f32> {
286                     return textureSample(texture0, sampler0, texCoord);
287                 }
288             )");
289 
290             utils::ComboRenderPipelineDescriptor descriptor;
291             descriptor.vertex.module = vs;
292             descriptor.cFragment.module = fs;
293             descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
294 
295             pipeline = device.CreateRenderPipeline(&descriptor);
296         }
297 
298         // The bindgroup containing the texture view for the ioSurface as well as the sampler.
299         wgpu::BindGroup bindGroup;
300         {
301             wgpu::TextureDescriptor textureDescriptor;
302             textureDescriptor.dimension = wgpu::TextureDimension::e2D;
303             textureDescriptor.format = format;
304             textureDescriptor.size = {1, 1, 1};
305             textureDescriptor.sampleCount = 1;
306             textureDescriptor.mipLevelCount = 1;
307             textureDescriptor.usage = wgpu::TextureUsage::TextureBinding;
308             wgpu::Texture wrappingTexture = WrapIOSurface(&textureDescriptor, ioSurface, 0);
309 
310             wgpu::TextureView textureView = wrappingTexture.CreateView();
311 
312             wgpu::Sampler sampler = device.CreateSampler();
313 
314             bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
315                                              {{0, sampler}, {1, textureView}});
316         }
317 
318         // Submit commands samping from the ioSurface and writing the result to renderPass.color
319         utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
320         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
321         {
322             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
323             pass.SetPipeline(pipeline);
324             pass.SetBindGroup(0, bindGroup);
325             pass.Draw(6);
326             pass.EndPass();
327         }
328 
329         wgpu::CommandBuffer commands = encoder.Finish();
330         queue.Submit(1, &commands);
331 
332         EXPECT_PIXEL_RGBA8_EQ(expectedColor, renderPass.color, 0, 0);
333     }
334 
335     // Test that clearing using BeginRenderPass writes correct data in the ioSurface.
DoClearTest(IOSurfaceRef ioSurface,wgpu::TextureFormat format,void * data,size_t dataSize)336     void DoClearTest(IOSurfaceRef ioSurface,
337                      wgpu::TextureFormat format,
338                      void* data,
339                      size_t dataSize) {
340         // Get a texture view for the ioSurface
341         wgpu::TextureDescriptor textureDescriptor;
342         textureDescriptor.dimension = wgpu::TextureDimension::e2D;
343         textureDescriptor.format = format;
344         textureDescriptor.size = {1, 1, 1};
345         textureDescriptor.sampleCount = 1;
346         textureDescriptor.mipLevelCount = 1;
347         textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
348         wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface, 0);
349 
350         wgpu::TextureView ioSurfaceView = ioSurfaceTexture.CreateView();
351 
352         utils::ComboRenderPassDescriptor renderPassDescriptor({ioSurfaceView}, {});
353         renderPassDescriptor.cColorAttachments[0].clearColor = {1 / 255.0f, 2 / 255.0f, 3 / 255.0f,
354                                                                 4 / 255.0f};
355 
356         // Execute commands to clear the ioSurface
357         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
358         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
359         pass.EndPass();
360 
361         wgpu::CommandBuffer commands = encoder.Finish();
362         queue.Submit(1, &commands);
363 
364         // Wait for the commands touching the IOSurface to be scheduled
365         dawn_native::metal::WaitForCommandsToBeScheduled(device.Get());
366 
367         // Check the correct data was written
368         IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
369         ASSERT_EQ(0, memcmp(IOSurfaceGetBaseAddress(ioSurface), data, dataSize));
370         IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
371     }
372 };
373 
374 // Test sampling from a R8 IOSurface
TEST_P(IOSurfaceUsageTests,SampleFromR8IOSurface)375 TEST_P(IOSurfaceUsageTests, SampleFromR8IOSurface) {
376     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
377     ScopedIOSurfaceRef ioSurface =
378         CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1);
379 
380     uint8_t data = 0x01;
381     DoSampleTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data),
382                  RGBA8(1, 0, 0, 255));
383 }
384 
385 // Test clearing a R8 IOSurface
TEST_P(IOSurfaceUsageTests,ClearR8IOSurface)386 TEST_P(IOSurfaceUsageTests, ClearR8IOSurface) {
387     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
388     ScopedIOSurfaceRef ioSurface =
389         CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1);
390 
391     uint8_t data = 0x01;
392     DoClearTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data));
393 }
394 
395 // Test sampling from a RG8 IOSurface
TEST_P(IOSurfaceUsageTests,SampleFromRG8IOSurface)396 TEST_P(IOSurfaceUsageTests, SampleFromRG8IOSurface) {
397     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
398     ScopedIOSurfaceRef ioSurface =
399         CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2);
400 
401     uint16_t data = 0x0102;  // Stored as (G, R)
402     DoSampleTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data),
403                  RGBA8(2, 1, 0, 255));
404 }
405 
406 // Test clearing a RG8 IOSurface
TEST_P(IOSurfaceUsageTests,ClearRG8IOSurface)407 TEST_P(IOSurfaceUsageTests, ClearRG8IOSurface) {
408     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
409     ScopedIOSurfaceRef ioSurface =
410         CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2);
411 
412     uint16_t data = 0x0201;
413     DoClearTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data));
414 }
415 
416 // Test sampling from a BGRA8 IOSurface
TEST_P(IOSurfaceUsageTests,SampleFromBGRA8IOSurface)417 TEST_P(IOSurfaceUsageTests, SampleFromBGRA8IOSurface) {
418     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
419     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32BGRA, 4);
420 
421     uint32_t data = 0x01020304;  // Stored as (A, R, G, B)
422     DoSampleTest(ioSurface.get(), wgpu::TextureFormat::BGRA8Unorm, &data, sizeof(data),
423                  RGBA8(2, 3, 4, 1));
424 }
425 
426 // Test clearing a BGRA8 IOSurface
TEST_P(IOSurfaceUsageTests,ClearBGRA8IOSurface)427 TEST_P(IOSurfaceUsageTests, ClearBGRA8IOSurface) {
428     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
429     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32BGRA, 4);
430 
431     uint32_t data = 0x04010203;
432     DoClearTest(ioSurface.get(), wgpu::TextureFormat::BGRA8Unorm, &data, sizeof(data));
433 }
434 
435 // Test sampling from an RGBA8 IOSurface
TEST_P(IOSurfaceUsageTests,SampleFromRGBA8IOSurface)436 TEST_P(IOSurfaceUsageTests, SampleFromRGBA8IOSurface) {
437     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
438     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32RGBA, 4);
439 
440     uint32_t data = 0x01020304;  // Stored as (A, B, G, R)
441     DoSampleTest(ioSurface.get(), wgpu::TextureFormat::RGBA8Unorm, &data, sizeof(data),
442                  RGBA8(4, 3, 2, 1));
443 }
444 
445 // Test clearing an RGBA8 IOSurface
TEST_P(IOSurfaceUsageTests,ClearRGBA8IOSurface)446 TEST_P(IOSurfaceUsageTests, ClearRGBA8IOSurface) {
447     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
448     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32RGBA, 4);
449 
450     uint32_t data = 0x04030201;
451     DoClearTest(ioSurface.get(), wgpu::TextureFormat::RGBA8Unorm, &data, sizeof(data));
452 }
453 
454 // Test that texture with color is cleared when isInitialized = false
TEST_P(IOSurfaceUsageTests,UninitializedTextureIsCleared)455 TEST_P(IOSurfaceUsageTests, UninitializedTextureIsCleared) {
456     DAWN_TEST_UNSUPPORTED_IF(UsesWire());
457 
458     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32RGBA, 4);
459     uint32_t data = 0x04030201;
460 
461     IOSurfaceLock(ioSurface.get(), 0, nullptr);
462     memcpy(IOSurfaceGetBaseAddress(ioSurface.get()), &data, sizeof(data));
463     IOSurfaceUnlock(ioSurface.get(), 0, nullptr);
464 
465     wgpu::TextureDescriptor textureDescriptor;
466     textureDescriptor.dimension = wgpu::TextureDimension::e2D;
467     textureDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
468     textureDescriptor.size = {1, 1, 1};
469     textureDescriptor.sampleCount = 1;
470     textureDescriptor.mipLevelCount = 1;
471     textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
472 
473     // wrap ioSurface and ensure color is not visible when isInitialized set to false
474     wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface.get(), 0, false);
475     EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), ioSurfaceTexture, 0, 0);
476 }
477 
478 DAWN_INSTANTIATE_TEST(IOSurfaceValidationTests, MetalBackend());
479 DAWN_INSTANTIATE_TEST(IOSurfaceUsageTests, MetalBackend());
480