• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 "common/Constants.h"
18 #include "common/Math.h"
19 #include "utils/ComboRenderPipelineDescriptor.h"
20 #include "utils/TestUtils.h"
21 #include "utils/TextureUtils.h"
22 #include "utils/WGPUHelpers.h"
23 
24 namespace {
25     static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
26 
27     // Set default texture size to single line texture for color conversion tests.
28     static constexpr uint64_t kDefaultTextureWidth = 10;
29     static constexpr uint64_t kDefaultTextureHeight = 1;
30 
31     using Alpha = wgpu::AlphaOp;
32     DAWN_TEST_PARAM_STRUCT(AlphaTestParams, Alpha);
33 
34     using SrcFormat = wgpu::TextureFormat;
35     using DstFormat = wgpu::TextureFormat;
36     using SrcOrigin = wgpu::Origin3D;
37     using DstOrigin = wgpu::Origin3D;
38     using CopySize = wgpu::Extent3D;
39     using FlipY = bool;
40 
operator <<(std::ostream & o,wgpu::Origin3D origin)41     std::ostream& operator<<(std::ostream& o, wgpu::Origin3D origin) {
42         o << origin.x << ", " << origin.y << ", " << origin.z;
43         return o;
44     }
45 
operator <<(std::ostream & o,wgpu::Extent3D copySize)46     std::ostream& operator<<(std::ostream& o, wgpu::Extent3D copySize) {
47         o << copySize.width << ", " << copySize.height << ", " << copySize.depthOrArrayLayers;
48         return o;
49     }
50 
51     DAWN_TEST_PARAM_STRUCT(FormatTestParams, SrcFormat, DstFormat);
52     DAWN_TEST_PARAM_STRUCT(SubRectTestParams, SrcOrigin, DstOrigin, CopySize, FlipY);
53 
54 }  // anonymous namespace
55 
56 template <typename Parent>
57 class CopyTextureForBrowserTests : public Parent {
58   protected:
59     struct TextureSpec {
60         wgpu::Origin3D copyOrigin = {};
61         wgpu::Extent3D textureSize = {kDefaultTextureWidth, kDefaultTextureHeight};
62         uint32_t level = 0;
63         wgpu::TextureFormat format = kTextureFormat;
64     };
65 
66     enum class TextureCopyRole {
67         SOURCE,
68         DEST,
69     };
70 
71     // Source texture contains red pixels and dst texture contains green pixels at start.
GetTextureData(const utils::TextureDataCopyLayout & layout,TextureCopyRole textureRole,wgpu::AlphaOp alphaOp=wgpu::AlphaOp::DontChange)72     static std::vector<RGBA8> GetTextureData(const utils::TextureDataCopyLayout& layout,
73                                              TextureCopyRole textureRole,
74                                              wgpu::AlphaOp alphaOp = wgpu::AlphaOp::DontChange) {
75         std::array<uint8_t, 4> alpha = {0, 102, 153, 255};  // 0.0, 0.4, 0.6, 1.0
76         std::vector<RGBA8> textureData(layout.texelBlockCount);
77         for (uint32_t layer = 0; layer < layout.mipSize.depthOrArrayLayers; ++layer) {
78             const uint32_t sliceOffset = layout.texelBlocksPerImage * layer;
79             for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
80                 const uint32_t rowOffset = layout.texelBlocksPerRow * y;
81                 for (uint32_t x = 0; x < layout.mipSize.width; ++x) {
82                     // Source textures will have variable pixel data to cover cases like
83                     // flipY.
84                     if (textureRole == TextureCopyRole::SOURCE) {
85                         switch (alphaOp) {
86                             case wgpu::AlphaOp::DontChange:
87                                 textureData[sliceOffset + rowOffset + x] = RGBA8(
88                                     static_cast<uint8_t>((x + layer * x) % 256),
89                                     static_cast<uint8_t>((y + layer * y) % 256),
90                                     static_cast<uint8_t>(x % 256), static_cast<uint8_t>(x % 256));
91                                 break;
92                             case wgpu::AlphaOp::Premultiply:
93                                 // For premultiply alpha test cases, we expect each channel in dst
94                                 // texture will equal to the alpha channel value.
95                                 textureData[sliceOffset + rowOffset + x] = RGBA8(
96                                     static_cast<uint8_t>(255), static_cast<uint8_t>(255),
97                                     static_cast<uint8_t>(255), static_cast<uint8_t>(alpha[x % 4]));
98                                 break;
99                             case wgpu::AlphaOp::Unpremultiply:
100                                 // For unpremultiply alpha test cases, we expect each channel in dst
101                                 // texture will equal to 1.0.
102                                 textureData[sliceOffset + rowOffset + x] =
103                                     RGBA8(static_cast<uint8_t>(alpha[x % 4]),
104                                           static_cast<uint8_t>(alpha[x % 4]),
105                                           static_cast<uint8_t>(alpha[x % 4]),
106                                           static_cast<uint8_t>(alpha[x % 4]));
107                                 break;
108                             default:
109                                 UNREACHABLE();
110                                 break;
111                         }
112                     } else {  // Dst textures will have be init as `green` to ensure subrect
113                               // copy not cross bound.
114                         textureData[sliceOffset + rowOffset + x] =
115                             RGBA8(static_cast<uint8_t>(0), static_cast<uint8_t>(255),
116                                   static_cast<uint8_t>(0), static_cast<uint8_t>(255));
117                     }
118                 }
119             }
120         }
121 
122         return textureData;
123     }
124 
SetUp()125     void SetUp() override {
126         Parent::SetUp();
127         pipeline = MakeTestPipeline();
128 
129         uint32_t uniformBufferData[] = {
130             0,  // copy have flipY option
131             4,  // channelCount
132             0,
133             0,  // uvec2, subrect copy src origin
134             0,
135             0,  // uvec2, subrect copy dst origin
136             0,
137             0,                                                 // uvec2, subrect copy size
138             static_cast<uint32_t>(wgpu::AlphaOp::DontChange),  // AlphaOp: DontChange
139         };
140 
141         wgpu::BufferDescriptor uniformBufferDesc = {};
142         uniformBufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
143         uniformBufferDesc.size = sizeof(uniformBufferData);
144         uniformBuffer = this->device.CreateBuffer(&uniformBufferDesc);
145     }
146 
147     // Do the bit-by-bit comparison between the source and destination texture with GPU (compute
148     // shader) instead of CPU after executing CopyTextureForBrowser() to avoid the errors caused by
149     // comparing a value generated on CPU to the one generated on GPU.
MakeTestPipeline()150     wgpu::ComputePipeline MakeTestPipeline() {
151         wgpu::ShaderModule csModule = utils::CreateShaderModule(this->device, R"(
152             [[block]] struct Uniforms {
153                 dstTextureFlipY : u32;
154                 channelCount    : u32;
155                 srcCopyOrigin   : vec2<u32>;
156                 dstCopyOrigin   : vec2<u32>;
157                 copySize        : vec2<u32>;
158                 alphaOp         : u32;
159             };
160             [[block]] struct OutputBuf {
161                 result : array<u32>;
162             };
163             [[group(0), binding(0)]] var src : texture_2d<f32>;
164             [[group(0), binding(1)]] var dst : texture_2d<f32>;
165             [[group(0), binding(2)]] var<storage, read_write> output : OutputBuf;
166             [[group(0), binding(3)]] var<uniform> uniforms : Uniforms;
167             fn aboutEqual(value : f32, expect : f32) -> bool {
168                 // The value diff should be smaller than the hard coded tolerance.
169                 return abs(value - expect) < 0.01;
170             }
171             [[stage(compute), workgroup_size(1, 1, 1)]]
172             fn main([[builtin(global_invocation_id)]] GlobalInvocationID : vec3<u32>) {
173                 let srcSize = textureDimensions(src);
174                 let dstSize = textureDimensions(dst);
175                 let dstTexCoord = vec2<u32>(GlobalInvocationID.xy);
176                 let nonCoveredColor = vec4<f32>(0.0, 1.0, 0.0, 1.0); // should be green
177 
178                 var success : bool = true;
179                 if (dstTexCoord.x < uniforms.dstCopyOrigin.x ||
180                     dstTexCoord.y < uniforms.dstCopyOrigin.y ||
181                     dstTexCoord.x >= uniforms.dstCopyOrigin.x + uniforms.copySize.x ||
182                     dstTexCoord.y >= uniforms.dstCopyOrigin.y + uniforms.copySize.y) {
183                     success = success &&
184                               all(textureLoad(dst, vec2<i32>(dstTexCoord), 0) == nonCoveredColor);
185                 } else {
186                     // Calculate source texture coord.
187                     var srcTexCoord = dstTexCoord - uniforms.dstCopyOrigin +
188                                                   uniforms.srcCopyOrigin;
189                     // Note that |flipY| equals flip src texture firstly and then do copy from src
190                     // subrect to dst subrect. This helps on blink part to handle some input texture
191                     // which is flipped and need to unpack flip during the copy.
192                     // We need to calculate the expect y coord based on this rule.
193                     if (uniforms.dstTextureFlipY == 1u) {
194                         srcTexCoord.y = u32(srcSize.y) - srcTexCoord.y - 1u;
195                     }
196 
197                     var srcColor = textureLoad(src, vec2<i32>(srcTexCoord), 0);
198                     var dstColor = textureLoad(dst, vec2<i32>(dstTexCoord), 0);
199 
200                     // Expect the dst texture channels should be all equal to alpha value
201                     // after premultiply.
202                     // TODO(crbug.com/1217153): if wgsl support `constexpr` and allow it
203                     // to be case selector, Replace 0u/1u/2u with a constexpr variable with
204                     // meaningful name.
205                     switch(uniforms.alphaOp) {
206                         case 0u: { // AlphaOp: DontChange
207                             break;
208                         }
209                         case 1u: { // AlphaOp: Premultiply
210                             srcColor = vec4<f32>(srcColor.rgb * srcColor.a, srcColor.a);
211                             break;
212                         }
213                         case 2u: { // AlphaOp: Unpremultiply
214                             if (srcColor.a != 0.0) {
215                                 srcColor = vec4<f32>(srcColor.rgb / srcColor.a, srcColor.a);
216                             }
217                             break;
218                         }
219                         default: {
220                             break;
221                         }
222                     }
223 
224                     // Not use loop and variable index format to workaround
225                     // crbug.com/tint/638.
226                     switch(uniforms.channelCount) {
227                         case 1u: {
228                             success = success && aboutEqual(dstColor.r, srcColor.r);
229                             break;
230                         }
231                         case 2u: {
232                             success = success &&
233                                       aboutEqual(dstColor.r, srcColor.r) &&
234                                       aboutEqual(dstColor.g, srcColor.g);
235                             break;
236                         }
237                         case 4u: {
238                             success = success &&
239                                       aboutEqual(dstColor.r, srcColor.r) &&
240                                       aboutEqual(dstColor.g, srcColor.g) &&
241                                       aboutEqual(dstColor.b, srcColor.b) &&
242                                       aboutEqual(dstColor.a, srcColor.a);
243                             break;
244                         }
245                         default: {
246                             break;
247                         }
248                     }
249                 }
250                 let outputIndex = GlobalInvocationID.y * u32(dstSize.x) + GlobalInvocationID.x;
251                 if (success) {
252                     output.result[outputIndex] = 1u;
253                 } else {
254                     output.result[outputIndex] = 0u;
255                 }
256             }
257          )");
258 
259         wgpu::ComputePipelineDescriptor csDesc;
260         csDesc.compute.module = csModule;
261         csDesc.compute.entryPoint = "main";
262 
263         return this->device.CreateComputePipeline(&csDesc);
264     }
GetTextureFormatComponentCount(wgpu::TextureFormat format)265     static uint32_t GetTextureFormatComponentCount(wgpu::TextureFormat format) {
266         switch (format) {
267             case wgpu::TextureFormat::RGBA8Unorm:
268             case wgpu::TextureFormat::RGBA8UnormSrgb:
269             case wgpu::TextureFormat::BGRA8Unorm:
270             case wgpu::TextureFormat::BGRA8UnormSrgb:
271             case wgpu::TextureFormat::RGB10A2Unorm:
272             case wgpu::TextureFormat::RGBA16Float:
273             case wgpu::TextureFormat::RGBA32Float:
274                 return 4;
275             case wgpu::TextureFormat::RG8Unorm:
276             case wgpu::TextureFormat::RG16Float:
277             case wgpu::TextureFormat::RG32Float:
278                 return 2;
279             case wgpu::TextureFormat::R8Unorm:
280             case wgpu::TextureFormat::R16Float:
281             case wgpu::TextureFormat::R32Float:
282                 return 1;
283             default:
284                 UNREACHABLE();
285         }
286     }
287 
CreateTexture(const TextureSpec & spec,wgpu::TextureUsage usage)288     wgpu::Texture CreateTexture(const TextureSpec& spec, wgpu::TextureUsage usage) {
289         // Create and initialize src texture.
290         wgpu::TextureDescriptor descriptor;
291         descriptor.size = spec.textureSize;
292         descriptor.format = spec.format;
293         descriptor.mipLevelCount = spec.level + 1;
294         descriptor.usage = usage;
295         wgpu::Texture texture = this->device.CreateTexture(&descriptor);
296         return texture;
297     }
298 
CreateAndInitTexture(const TextureSpec & spec,wgpu::TextureUsage usage,utils::TextureDataCopyLayout copyLayout,void const * init,uint32_t initBytes)299     wgpu::Texture CreateAndInitTexture(const TextureSpec& spec,
300                                        wgpu::TextureUsage usage,
301                                        utils::TextureDataCopyLayout copyLayout,
302                                        void const* init,
303                                        uint32_t initBytes) {
304         wgpu::Texture texture = CreateTexture(spec, usage);
305 
306         wgpu::ImageCopyTexture imageTextureInit =
307             utils::CreateImageCopyTexture(texture, spec.level, {0, 0});
308 
309         wgpu::TextureDataLayout textureDataLayout;
310         textureDataLayout.offset = 0;
311         textureDataLayout.bytesPerRow = copyLayout.bytesPerRow;
312         textureDataLayout.rowsPerImage = copyLayout.rowsPerImage;
313 
314         this->device.GetQueue().WriteTexture(&imageTextureInit, init, initBytes, &textureDataLayout,
315                                              &copyLayout.mipSize);
316         return texture;
317     }
318 
RunCopyExternalImageToTexture(const TextureSpec & srcSpec,wgpu::Texture srcTexture,const TextureSpec & dstSpec,wgpu::Texture dstTexture,const wgpu::Extent3D & copySize,const wgpu::CopyTextureForBrowserOptions options)319     void RunCopyExternalImageToTexture(const TextureSpec& srcSpec,
320                                        wgpu::Texture srcTexture,
321                                        const TextureSpec& dstSpec,
322                                        wgpu::Texture dstTexture,
323                                        const wgpu::Extent3D& copySize,
324                                        const wgpu::CopyTextureForBrowserOptions options) {
325         wgpu::ImageCopyTexture srcImageCopyTexture =
326             utils::CreateImageCopyTexture(srcTexture, srcSpec.level, srcSpec.copyOrigin);
327         wgpu::ImageCopyTexture dstImageCopyTexture =
328             utils::CreateImageCopyTexture(dstTexture, dstSpec.level, dstSpec.copyOrigin);
329         this->device.GetQueue().CopyTextureForBrowser(&srcImageCopyTexture, &dstImageCopyTexture,
330                                                       &copySize, &options);
331     }
332 
CheckResultInBuiltInComputePipeline(const TextureSpec & srcSpec,wgpu::Texture srcTexture,const TextureSpec & dstSpec,wgpu::Texture dstTexture,const wgpu::Extent3D & copySize,const wgpu::CopyTextureForBrowserOptions options)333     void CheckResultInBuiltInComputePipeline(const TextureSpec& srcSpec,
334                                              wgpu::Texture srcTexture,
335                                              const TextureSpec& dstSpec,
336                                              wgpu::Texture dstTexture,
337                                              const wgpu::Extent3D& copySize,
338                                              const wgpu::CopyTextureForBrowserOptions options) {
339         // Update uniform buffer based on test config
340         uint32_t uniformBufferData[] = {
341             options.flipY,                                   // copy have flipY option
342             GetTextureFormatComponentCount(dstSpec.format),  // channelCount
343             srcSpec.copyOrigin.x,
344             srcSpec.copyOrigin.y,  // src texture copy origin
345             dstSpec.copyOrigin.x,
346             dstSpec.copyOrigin.y,  // dst texture copy origin
347             copySize.width,
348             copySize.height,                        // copy size
349             static_cast<uint32_t>(options.alphaOp)  // alphaOp
350         };
351 
352         this->device.GetQueue().WriteBuffer(uniformBuffer, 0, uniformBufferData,
353                                             sizeof(uniformBufferData));
354 
355         // Create output buffer to store result
356         wgpu::BufferDescriptor outputDesc;
357         outputDesc.size = dstSpec.textureSize.width * dstSpec.textureSize.height * sizeof(uint32_t);
358         outputDesc.usage =
359             wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
360         wgpu::Buffer outputBuffer = this->device.CreateBuffer(&outputDesc);
361 
362         // Create texture views for test.
363         wgpu::TextureViewDescriptor srcTextureViewDesc = {};
364         srcTextureViewDesc.baseMipLevel = srcSpec.level;
365         wgpu::TextureView srcTextureView = srcTexture.CreateView(&srcTextureViewDesc);
366 
367         wgpu::TextureViewDescriptor dstTextureViewDesc = {};
368         dstTextureViewDesc.baseMipLevel = dstSpec.level;
369         wgpu::TextureView dstTextureView = dstTexture.CreateView(&dstTextureViewDesc);
370 
371         // Create bind group based on the config.
372         wgpu::BindGroup bindGroup = utils::MakeBindGroup(
373             this->device, pipeline.GetBindGroupLayout(0),
374             {{0, srcTextureView}, {1, dstTextureView}, {2, outputBuffer}, {3, uniformBuffer}});
375 
376         // Start a pipeline to check pixel value in bit form.
377         wgpu::CommandEncoder testEncoder = this->device.CreateCommandEncoder();
378 
379         wgpu::CommandBuffer testCommands;
380         {
381             wgpu::CommandEncoder encoder = this->device.CreateCommandEncoder();
382             wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
383             pass.SetPipeline(pipeline);
384             pass.SetBindGroup(0, bindGroup);
385             pass.Dispatch(dstSpec.textureSize.width,
386                           dstSpec.textureSize.height);  // Verify dst texture content
387             pass.EndPass();
388 
389             testCommands = encoder.Finish();
390         }
391         this->device.GetQueue().Submit(1, &testCommands);
392 
393         std::vector<uint32_t> expectResult(dstSpec.textureSize.width * dstSpec.textureSize.height,
394                                            1);
395         EXPECT_BUFFER_U32_RANGE_EQ(expectResult.data(), outputBuffer, 0,
396                                    dstSpec.textureSize.width * dstSpec.textureSize.height);
397     }
398 
DoTest(const TextureSpec & srcSpec,const TextureSpec & dstSpec,const wgpu::Extent3D & copySize={kDefaultTextureWidth, kDefaultTextureHeight},const wgpu::CopyTextureForBrowserOptions options={})399     void DoTest(const TextureSpec& srcSpec,
400                 const TextureSpec& dstSpec,
401                 const wgpu::Extent3D& copySize = {kDefaultTextureWidth, kDefaultTextureHeight},
402                 const wgpu::CopyTextureForBrowserOptions options = {}) {
403         // Create and initialize src texture.
404         const utils::TextureDataCopyLayout srcCopyLayout =
405             utils::GetTextureDataCopyLayoutForTextureAtLevel(
406                 kTextureFormat,
407                 {srcSpec.textureSize.width, srcSpec.textureSize.height,
408                  copySize.depthOrArrayLayers},
409                 srcSpec.level);
410 
411         std::vector<RGBA8> srcTextureArrayCopyData =
412             GetTextureData(srcCopyLayout, TextureCopyRole::SOURCE, options.alphaOp);
413 
414         wgpu::TextureUsage srcUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
415                                       wgpu::TextureUsage::TextureBinding;
416         wgpu::Texture srcTexture =
417             CreateAndInitTexture(srcSpec, srcUsage, srcCopyLayout, srcTextureArrayCopyData.data(),
418                                  srcTextureArrayCopyData.size() * sizeof(RGBA8));
419 
420         bool testSubRectCopy = srcSpec.copyOrigin.x > 0 || srcSpec.copyOrigin.y > 0 ||
421                                dstSpec.copyOrigin.x > 0 || dstSpec.copyOrigin.y > 0 ||
422                                srcSpec.textureSize.width > copySize.width ||
423                                srcSpec.textureSize.height > copySize.height ||
424                                dstSpec.textureSize.width > copySize.width ||
425                                dstSpec.textureSize.height > copySize.height;
426 
427         // Create and init dst texture.
428         wgpu::Texture dstTexture;
429         wgpu::TextureUsage dstUsage =
430             wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
431             wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
432 
433         if (testSubRectCopy) {
434             // For subrect copy tests, dst texture use kTextureFormat always.
435             const utils::TextureDataCopyLayout dstCopyLayout =
436                 utils::GetTextureDataCopyLayoutForTextureAtLevel(
437                     kTextureFormat,
438                     {dstSpec.textureSize.width, dstSpec.textureSize.height,
439                      copySize.depthOrArrayLayers},
440                     dstSpec.level);
441 
442             const std::vector<RGBA8> dstTextureArrayCopyData =
443                 GetTextureData(dstCopyLayout, TextureCopyRole::DEST);
444             dstTexture = CreateAndInitTexture(dstSpec, dstUsage, dstCopyLayout,
445                                               dstTextureArrayCopyData.data(),
446                                               dstTextureArrayCopyData.size() * sizeof(RGBA8));
447         } else {
448             dstTexture = CreateTexture(dstSpec, dstUsage);
449         }
450 
451         // Perform the texture to texture copy
452         RunCopyExternalImageToTexture(srcSpec, srcTexture, dstSpec, dstTexture, copySize, options);
453 
454         // Check Result
455         CheckResultInBuiltInComputePipeline(srcSpec, srcTexture, dstSpec, dstTexture, copySize,
456                                             options);
457     }
458 
459     wgpu::Buffer uniformBuffer;
460     wgpu::ComputePipeline pipeline;
461 };
462 
463 class CopyTextureForBrowser_Basic : public CopyTextureForBrowserTests<DawnTest> {
464   protected:
DoBasicCopyTest(const wgpu::Extent3D & copySize,const wgpu::CopyTextureForBrowserOptions options={})465     void DoBasicCopyTest(const wgpu::Extent3D& copySize,
466                          const wgpu::CopyTextureForBrowserOptions options = {}) {
467         TextureSpec textureSpec;
468         textureSpec.textureSize = copySize;
469 
470         DoTest(textureSpec, textureSpec, copySize, options);
471     }
472 };
473 
474 class CopyTextureForBrowser_Formats
475     : public CopyTextureForBrowserTests<DawnTestWithParams<FormatTestParams>> {
476   protected:
IsDstFormatSrgbFormats()477     bool IsDstFormatSrgbFormats() {
478         return GetParam().mDstFormat == wgpu::TextureFormat::RGBA8UnormSrgb ||
479                GetParam().mDstFormat == wgpu::TextureFormat::BGRA8UnormSrgb;
480     }
481 
DoColorConversionTest()482     void DoColorConversionTest() {
483         TextureSpec srcTextureSpec;
484         srcTextureSpec.format = GetParam().mSrcFormat;
485 
486         TextureSpec dstTextureSpec;
487         dstTextureSpec.format = GetParam().mDstFormat;
488 
489         wgpu::Extent3D copySize = {kDefaultTextureWidth, kDefaultTextureHeight};
490         wgpu::CopyTextureForBrowserOptions options = {};
491 
492         // Create and init source texture.
493         // This fixed source texture data is for color conversion tests.
494         // The source data can fill a texture in default width and height.
495         std::vector<RGBA8> srcTextureArrayCopyData{
496             // Take RGBA8Unorm as example:
497             // R channel has different values
498             RGBA8(0, 255, 255, 255),    // r = 0.0
499             RGBA8(102, 255, 255, 255),  // r = 0.4
500             RGBA8(153, 255, 255, 255),  // r = 0.6
501 
502             // G channel has different values
503             RGBA8(255, 0, 255, 255),    // g = 0.0
504             RGBA8(255, 102, 255, 255),  // g = 0.4
505             RGBA8(255, 153, 255, 255),  // g = 0.6
506 
507             // B channel has different values
508             RGBA8(255, 255, 0, 255),    // b = 0.0
509             RGBA8(255, 255, 102, 255),  // b = 0.4
510             RGBA8(255, 255, 153, 255),  // b = 0.6
511 
512             // A channel set to 0
513             RGBA8(255, 255, 255, 0)  // a = 0
514         };
515 
516         const utils::TextureDataCopyLayout srcCopyLayout =
517             utils::GetTextureDataCopyLayoutForTextureAtLevel(
518                 kTextureFormat,
519                 {srcTextureSpec.textureSize.width, srcTextureSpec.textureSize.height,
520                  copySize.depthOrArrayLayers},
521                 srcTextureSpec.level);
522 
523         wgpu::TextureUsage srcUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
524                                       wgpu::TextureUsage::TextureBinding;
525         wgpu::Texture srcTexture = CreateAndInitTexture(
526             srcTextureSpec, srcUsage, srcCopyLayout, srcTextureArrayCopyData.data(),
527             srcTextureArrayCopyData.size() * sizeof(RGBA8));
528 
529         // Create dst texture.
530         wgpu::Texture dstTexture = CreateTexture(
531             dstTextureSpec, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
532                                 wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
533 
534         // Perform the texture to texture copy
535         RunCopyExternalImageToTexture(srcTextureSpec, srcTexture, dstTextureSpec, dstTexture,
536                                       copySize, options);
537 
538         // Check Result
539         CheckResultInBuiltInComputePipeline(srcTextureSpec, srcTexture, dstTextureSpec, dstTexture,
540                                             copySize, options);
541     }
542 };
543 
544 class CopyTextureForBrowser_SubRects
545     : public CopyTextureForBrowserTests<DawnTestWithParams<SubRectTestParams>> {
546   protected:
DoCopySubRectTest()547     void DoCopySubRectTest() {
548         TextureSpec srcTextureSpec;
549         srcTextureSpec.copyOrigin = GetParam().mSrcOrigin;
550         srcTextureSpec.textureSize = {6, 7};
551 
552         TextureSpec dstTextureSpec;
553         dstTextureSpec.copyOrigin = GetParam().mDstOrigin;
554         dstTextureSpec.textureSize = {8, 5};
555         wgpu::CopyTextureForBrowserOptions options = {};
556         options.flipY = GetParam().mFlipY;
557 
558         wgpu::Extent3D copySize = GetParam().mCopySize;
559 
560         DoTest(srcTextureSpec, dstTextureSpec, copySize, options);
561     }
562 };
563 
564 class CopyTextureForBrowser_AlphaOps
565     : public CopyTextureForBrowserTests<DawnTestWithParams<AlphaTestParams>> {
566   protected:
DoAlphaOpTest()567     void DoAlphaOpTest() {
568         constexpr uint32_t kWidth = 10;
569         constexpr uint32_t kHeight = 10;
570 
571         TextureSpec textureSpec;
572         textureSpec.textureSize = {kWidth, kHeight};
573 
574         wgpu::CopyTextureForBrowserOptions options = {};
575         options.alphaOp = GetParam().mAlpha;
576 
577         DoTest(textureSpec, textureSpec, {kWidth, kHeight}, options);
578     }
579 };
580 
581 // Verify CopyTextureForBrowserTests works with internal pipeline.
582 // The case do copy without any transform.
TEST_P(CopyTextureForBrowser_Basic,PassthroughCopy)583 TEST_P(CopyTextureForBrowser_Basic, PassthroughCopy) {
584     DoBasicCopyTest({10, 1});
585 }
586 
TEST_P(CopyTextureForBrowser_Basic,VerifyCopyOnXDirection)587 TEST_P(CopyTextureForBrowser_Basic, VerifyCopyOnXDirection) {
588     DoBasicCopyTest({1000, 1});
589 }
590 
TEST_P(CopyTextureForBrowser_Basic,VerifyCopyOnYDirection)591 TEST_P(CopyTextureForBrowser_Basic, VerifyCopyOnYDirection) {
592     DoBasicCopyTest({1, 1000});
593 }
594 
TEST_P(CopyTextureForBrowser_Basic,VerifyCopyFromLargeTexture)595 TEST_P(CopyTextureForBrowser_Basic, VerifyCopyFromLargeTexture) {
596     // TODO(crbug.com/dawn/1070): Flaky VK_DEVICE_LOST
597     DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
598 
599     DoBasicCopyTest({899, 999});
600 }
601 
TEST_P(CopyTextureForBrowser_Basic,VerifyFlipY)602 TEST_P(CopyTextureForBrowser_Basic, VerifyFlipY) {
603     wgpu::CopyTextureForBrowserOptions options = {};
604     options.flipY = true;
605 
606     DoBasicCopyTest({901, 1001}, options);
607 }
608 
TEST_P(CopyTextureForBrowser_Basic,VerifyFlipYInSlimTexture)609 TEST_P(CopyTextureForBrowser_Basic, VerifyFlipYInSlimTexture) {
610     wgpu::CopyTextureForBrowserOptions options = {};
611     options.flipY = true;
612 
613     DoBasicCopyTest({1, 1001}, options);
614 }
615 
616 DAWN_INSTANTIATE_TEST(CopyTextureForBrowser_Basic,
617                       D3D12Backend(),
618                       MetalBackend(),
619                       OpenGLBackend(),
620                       OpenGLESBackend(),
621                       VulkanBackend());
622 
623 // Verify |CopyTextureForBrowser| doing color conversion correctly when
624 // the source texture is RGBA8Unorm format.
TEST_P(CopyTextureForBrowser_Formats,ColorConversion)625 TEST_P(CopyTextureForBrowser_Formats, ColorConversion) {
626     // Skip OpenGLES backend because it fails on using RGBA8Unorm as
627     // source texture format.
628     DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
629 
630     // Skip OpenGL backend on linux because it fails on using *-srgb format as
631     // dst texture format
632     DAWN_SUPPRESS_TEST_IF(IsOpenGL() && IsLinux() && IsDstFormatSrgbFormats());
633 
634     DoColorConversionTest();
635 }
636 
637 DAWN_INSTANTIATE_TEST_P(
638     CopyTextureForBrowser_Formats,
639     {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
640     std::vector<wgpu::TextureFormat>({wgpu::TextureFormat::RGBA8Unorm,
641                                       wgpu::TextureFormat::BGRA8Unorm}),
642     std::vector<wgpu::TextureFormat>(
643         {wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R16Float, wgpu::TextureFormat::R32Float,
644          wgpu::TextureFormat::RG8Unorm, wgpu::TextureFormat::RG16Float,
645          wgpu::TextureFormat::RG32Float, wgpu::TextureFormat::RGBA8Unorm,
646          wgpu::TextureFormat::BGRA8Unorm, wgpu::TextureFormat::RGB10A2Unorm,
647          wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RGBA32Float}));
648 
649 // Verify |CopyTextureForBrowser| doing subrect copy.
650 // Source texture is a full red texture and dst texture is a full
651 // green texture originally. After the subrect copy, affected part
652 // in dst texture should be red and other part should remain green.
TEST_P(CopyTextureForBrowser_SubRects,CopySubRect)653 TEST_P(CopyTextureForBrowser_SubRects, CopySubRect) {
654     // Tests skip due to crbug.com/dawn/592.
655     DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
656 
657     // Tests skip due to crbug.com/dawn/1104.
658     DAWN_SUPPRESS_TEST_IF(IsWARP());
659 
660     DoCopySubRectTest();
661 }
662 
663 DAWN_INSTANTIATE_TEST_P(CopyTextureForBrowser_SubRects,
664                         {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
665                          VulkanBackend()},
666                         std::vector<wgpu::Origin3D>({{1, 1}, {1, 2}, {2, 1}}),
667                         std::vector<wgpu::Origin3D>({{1, 1}, {1, 2}, {2, 1}}),
668                         std::vector<wgpu::Extent3D>({{1, 1}, {2, 1}, {1, 2}, {2, 2}}),
669                         std::vector<bool>({true, false}));
670 
671 // Verify |CopyTextureForBrowser| doing alphaOp.
672 // Test alpha ops: DontChange, Premultiply, Unpremultiply.
TEST_P(CopyTextureForBrowser_AlphaOps,alphaOp)673 TEST_P(CopyTextureForBrowser_AlphaOps, alphaOp) {
674     // Skip OpenGLES backend because it fails on using RGBA8Unorm as
675     // source texture format.
676     DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
677 
678     // Tests skip due to crbug.com/dawn/1104.
679     DAWN_SUPPRESS_TEST_IF(IsWARP());
680 
681     DoAlphaOpTest();
682 }
683 
684 DAWN_INSTANTIATE_TEST_P(
685     CopyTextureForBrowser_AlphaOps,
686     {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
687     std::vector<wgpu::AlphaOp>({wgpu::AlphaOp::DontChange, wgpu::AlphaOp::Premultiply,
688                                 wgpu::AlphaOp::Unpremultiply}));
689