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 ©Layout.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 ©Size, &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