CopyTextureForBrowser: Support Subrect Copy
This CL support subrect copy. Use scale/offset to copy from subrect of source texture and viewport for copy to subrect of dstTexture. BUG=dawn:465 Change-Id: Ice43c0da15f6d9526912879e2e734f6570f2d673 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46422 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
parent
f759264387
commit
dc5d7a1dd9
|
@ -49,11 +49,26 @@ namespace dawn_native {
|
|||
[[stage(vertex)]] fn main() -> void {
|
||||
Position = vec4<f32>((texcoord[VertexIndex] * 2.0 - vec2<f32>(1.0, 1.0)), 0.0, 1.0);
|
||||
|
||||
// Y component of scale is calculated by the copySizeHeight / textureHeight. Only
|
||||
// flipY case can get negative number.
|
||||
var flipY : bool = uniforms.u_scale.y < 0.0;
|
||||
|
||||
// Texture coordinate takes top-left as origin point. We need to map the
|
||||
// texture to triangle carefully.
|
||||
v_texcoord = (texcoord[VertexIndex] * vec2<f32>(1.0, -1.0) + vec2<f32>(0.0, 1.0)) *
|
||||
if (flipY) {
|
||||
// We need to get the mirror positions(mirrored based on y = 0.5) on flip cases.
|
||||
// Adopt transform to src texture and then mapping it to triangle coord which
|
||||
// do a +1 shift on Y dimension will help us got that mirror position perfectly.
|
||||
v_texcoord = (texcoord[VertexIndex] * uniforms.u_scale + uniforms.u_offset) *
|
||||
vec2<f32>(1.0, -1.0) + vec2<f32>(0.0, 1.0);
|
||||
} else {
|
||||
// For the normal case, we need to get the exact position.
|
||||
// So mapping texture to triangle firstly then adopt the transform.
|
||||
v_texcoord = (texcoord[VertexIndex] *
|
||||
vec2<f32>(1.0, -1.0) + vec2<f32>(0.0, 1.0)) *
|
||||
uniforms.u_scale + uniforms.u_offset;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
static const char sCopyTextureForBrowserFragment[] = R"(
|
||||
|
@ -219,17 +234,6 @@ namespace dawn_native {
|
|||
|
||||
DAWN_TRY(ValidateCopyTextureForBrowserOptions(options));
|
||||
|
||||
// TODO(shaobo.yan@intel.com): Support the simplest case for now that source and destination
|
||||
// texture has the same size and do full texture blit. Will address sub texture blit in
|
||||
// future and remove these validations.
|
||||
if (source->origin.x != 0 || source->origin.y != 0 || source->origin.z != 0 ||
|
||||
destination->origin.x != 0 || destination->origin.y != 0 ||
|
||||
destination->origin.z != 0 || source->mipLevel != 0 || destination->mipLevel != 0 ||
|
||||
source->texture->GetWidth() != destination->texture->GetWidth() ||
|
||||
source->texture->GetHeight() != destination->texture->GetHeight()) {
|
||||
return DAWN_VALIDATION_ERROR("Cannot support sub blit now.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -255,16 +259,22 @@ namespace dawn_native {
|
|||
bgDesc.entryCount = 3;
|
||||
bgDesc.entries = bindGroupEntries;
|
||||
|
||||
Extent3D srcTextureSize = source->texture->GetSize();
|
||||
|
||||
// Prepare binding 0 resource: uniform buffer.
|
||||
float uniformData[] = {
|
||||
1.0, 1.0, // scale
|
||||
0.0, 0.0 // offset
|
||||
copySize->width / static_cast<float>(srcTextureSize.width),
|
||||
copySize->height / static_cast<float>(srcTextureSize.height), // scale
|
||||
source->origin.x / static_cast<float>(srcTextureSize.width),
|
||||
source->origin.y / static_cast<float>(srcTextureSize.height) // offset
|
||||
};
|
||||
|
||||
// Handle flipY
|
||||
// Handle flipY. FlipY here means we flip the source texture firstly and then
|
||||
// do copy. This helps on the case which source texture is flipped and the copy
|
||||
// need to unpack the flip.
|
||||
if (options && options->flipY) {
|
||||
uniformData[1] *= -1.0;
|
||||
uniformData[3] += 1.0;
|
||||
uniformData[3] += copySize->height / static_cast<float>(srcTextureSize.height);
|
||||
}
|
||||
|
||||
BufferDescriptor uniformDesc = {};
|
||||
|
@ -336,6 +346,8 @@ namespace dawn_native {
|
|||
// the copy from src texture to dst texture with transformation.
|
||||
passEncoder->APISetPipeline(pipeline);
|
||||
passEncoder->APISetBindGroup(0, bindGroup.Get());
|
||||
passEncoder->APISetViewport(destination->origin.x, destination->origin.y, copySize->width,
|
||||
copySize->height, 0.0, 1.0);
|
||||
passEncoder->APIDraw(3);
|
||||
passEncoder->APIEndPass();
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ namespace {
|
|||
wgpu::TextureFormat::RGBA32Float, wgpu::TextureFormat::RG8Unorm,
|
||||
wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RG16Float,
|
||||
wgpu::TextureFormat::RGB10A2Unorm};
|
||||
|
||||
static const wgpu::Origin3D kOrigins[] = {{1, 1}, {1, 2}, {2, 1}};
|
||||
|
||||
static const wgpu::Extent3D kCopySize[] = {{1, 1}, {2, 1}, {1, 2}, {2, 2}};
|
||||
} // anonymous namespace
|
||||
|
||||
class CopyTextureForBrowserTests : public DawnTest {
|
||||
|
@ -72,17 +76,33 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
return sourceTextureData;
|
||||
}
|
||||
|
||||
static std::vector<RGBA8> GetSourceTextureData(const utils::TextureDataCopyLayout& layout) {
|
||||
enum class TextureCopyRole {
|
||||
SOURCE,
|
||||
DEST,
|
||||
};
|
||||
|
||||
// Source texture contains red pixels and dst texture contains green pixels at start.
|
||||
static std::vector<RGBA8> GetTextureData(const utils::TextureDataCopyLayout& layout,
|
||||
TextureCopyRole textureRole) {
|
||||
std::vector<RGBA8> textureData(layout.texelBlockCount);
|
||||
for (uint32_t layer = 0; layer < layout.mipSize.depthOrArrayLayers; ++layer) {
|
||||
const uint32_t sliceOffset = layout.texelBlocksPerImage * layer;
|
||||
for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
|
||||
const uint32_t rowOffset = layout.texelBlocksPerRow * y;
|
||||
for (uint32_t x = 0; x < layout.mipSize.width; ++x) {
|
||||
// Source textures will have variable pixel data to cover cases like
|
||||
// flipY.
|
||||
if (textureRole == TextureCopyRole::SOURCE) {
|
||||
textureData[sliceOffset + rowOffset + x] =
|
||||
RGBA8(static_cast<uint8_t>((x + layer * x) % 256),
|
||||
static_cast<uint8_t>((y + layer * y) % 256),
|
||||
static_cast<uint8_t>(x % 256), static_cast<uint8_t>(x % 256));
|
||||
} else { // Dst textures will have be init as `green` to ensure subrect
|
||||
// copy not cross bound.
|
||||
textureData[sliceOffset + rowOffset + x] =
|
||||
RGBA8(static_cast<uint8_t>(0), static_cast<uint8_t>(255),
|
||||
static_cast<uint8_t>(0), static_cast<uint8_t>(255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +121,9 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
uint32_t uniformBufferData[] = {
|
||||
0, // copy have flipY option
|
||||
4, // channelCount
|
||||
0, 0, // uvec2, subrect copy src origin
|
||||
0, 0, // uvec2, subrect copy dst origin
|
||||
0, 0, // uvec2, subrect copy size
|
||||
};
|
||||
|
||||
wgpu::BufferDescriptor uniformBufferDesc = {};
|
||||
|
@ -117,6 +140,9 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
[[block]] struct Uniforms {
|
||||
dstTextureFlipY : u32;
|
||||
channelCount : u32;
|
||||
srcCopyOrigin : vec2<u32>;
|
||||
dstCopyOrigin : vec2<u32>;
|
||||
copySize : vec2<u32>;
|
||||
};
|
||||
[[block]] struct OutputBuf {
|
||||
result : array<u32>;
|
||||
|
@ -131,19 +157,33 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
return abs(value - expect) < 0.001;
|
||||
}
|
||||
[[stage(compute), workgroup_size(1, 1, 1)]] fn main() -> void {
|
||||
// Current CopyTextureForBrowser only support full copy now.
|
||||
// TODO(crbug.com/dawn/465): Refactor this after CopyTextureForBrowser
|
||||
// support sub-rect copy.
|
||||
var size : vec2<i32> = textureDimensions(src);
|
||||
var dstTexCoord : vec2<i32> = vec2<i32>(GlobalInvocationID.xy);
|
||||
var srcTexCoord : vec2<i32> = dstTexCoord;
|
||||
var srcSize : vec2<i32> = textureDimensions(src);
|
||||
var dstSize : vec2<i32> = textureDimensions(dst);
|
||||
var dstTexCoord : vec2<u32> = vec2<u32>(GlobalInvocationID.xy);
|
||||
var nonCoveredColor : vec4<f32> =
|
||||
vec4<f32>(0.0, 1.0, 0.0, 1.0); // should be green
|
||||
|
||||
var success : bool = true;
|
||||
if (dstTexCoord.x < uniforms.dstCopyOrigin.x ||
|
||||
dstTexCoord.y < uniforms.dstCopyOrigin.y ||
|
||||
dstTexCoord.x >= uniforms.dstCopyOrigin.x + uniforms.copySize.x ||
|
||||
dstTexCoord.y >= uniforms.dstCopyOrigin.y + uniforms.copySize.y) {
|
||||
success = success &&
|
||||
all(textureLoad(dst, vec2<i32>(dstTexCoord), 0) == nonCoveredColor);
|
||||
} else {
|
||||
// Calculate source texture coord.
|
||||
var srcTexCoord : vec2<u32> = dstTexCoord - uniforms.dstCopyOrigin +
|
||||
uniforms.srcCopyOrigin;
|
||||
// Note that |flipY| equals flip src texture firstly and then do copy from src
|
||||
// subrect to dst subrect. This helps on blink part to handle some input texture
|
||||
// which is flipped and need to unpack flip during the copy.
|
||||
// We need to calculate the expect y coord based on this rule.
|
||||
if (uniforms.dstTextureFlipY == 1u) {
|
||||
srcTexCoord.y = size.y - dstTexCoord.y - 1;
|
||||
srcTexCoord.y = u32(srcSize.y) - srcTexCoord.y - 1u;
|
||||
}
|
||||
|
||||
var srcColor : vec4<f32> = textureLoad(src, srcTexCoord, 0);
|
||||
var dstColor : vec4<f32> = textureLoad(dst, dstTexCoord, 0);
|
||||
var success : bool = true;
|
||||
var srcColor : vec4<f32> = textureLoad(src, vec2<i32>(srcTexCoord), 0);
|
||||
var dstColor : vec4<f32> = textureLoad(dst, vec2<i32>(dstTexCoord), 0);
|
||||
|
||||
// Not use loop and variable index format to workaround
|
||||
// crbug.com/tint/638.
|
||||
|
@ -158,8 +198,9 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
aboutEqual(dstColor.b, srcColor.b) &&
|
||||
aboutEqual(dstColor.a, srcColor.a);
|
||||
}
|
||||
|
||||
var outputIndex : u32 = GlobalInvocationID.y * u32(size.x) + GlobalInvocationID.x;
|
||||
}
|
||||
var outputIndex : u32 = GlobalInvocationID.y * u32(dstSize.x) +
|
||||
GlobalInvocationID.x;
|
||||
if (success) {
|
||||
output.result[outputIndex] = 1u;
|
||||
} else {
|
||||
|
@ -199,6 +240,7 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
const wgpu::Extent3D& copySize = {kDefaultTextureWidth, kDefaultTextureHeight},
|
||||
const wgpu::CopyTextureForBrowserOptions options = {},
|
||||
bool useFixedTestValue = false) {
|
||||
// Create and initialize src texture.
|
||||
wgpu::TextureDescriptor srcDescriptor;
|
||||
srcDescriptor.size = srcSpec.textureSize;
|
||||
srcDescriptor.format = srcSpec.format;
|
||||
|
@ -207,6 +249,41 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled;
|
||||
wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
|
||||
|
||||
const utils::TextureDataCopyLayout srcCopyLayout =
|
||||
utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
kTextureFormat,
|
||||
{srcSpec.textureSize.width, srcSpec.textureSize.height,
|
||||
copySize.depthOrArrayLayers},
|
||||
srcSpec.level);
|
||||
|
||||
std::vector<RGBA8> srcTextureArrayCopyData;
|
||||
if (useFixedTestValue) { // Use fixed value for color conversion tests.
|
||||
srcTextureArrayCopyData = GetFixedSourceTextureData();
|
||||
} else { // For other tests, the input format is always kTextureFormat.
|
||||
|
||||
srcTextureArrayCopyData = GetTextureData(srcCopyLayout, TextureCopyRole::SOURCE);
|
||||
}
|
||||
|
||||
wgpu::ImageCopyTexture srcImageTextureInit =
|
||||
utils::CreateImageCopyTexture(srcTexture, srcSpec.level, {0, 0});
|
||||
|
||||
wgpu::TextureDataLayout srcTextureDataLayout;
|
||||
srcTextureDataLayout.offset = 0;
|
||||
srcTextureDataLayout.bytesPerRow = srcCopyLayout.bytesPerRow;
|
||||
srcTextureDataLayout.rowsPerImage = srcCopyLayout.rowsPerImage;
|
||||
|
||||
device.GetQueue().WriteTexture(&srcImageTextureInit, srcTextureArrayCopyData.data(),
|
||||
srcTextureArrayCopyData.size() * sizeof(RGBA8),
|
||||
&srcTextureDataLayout, &srcCopyLayout.mipSize);
|
||||
|
||||
bool testSubRectCopy = srcSpec.copyOrigin.x > 0 || srcSpec.copyOrigin.y > 0 ||
|
||||
dstSpec.copyOrigin.x > 0 || dstSpec.copyOrigin.y > 0 ||
|
||||
srcSpec.textureSize.width > copySize.width ||
|
||||
srcSpec.textureSize.height > copySize.height ||
|
||||
dstSpec.textureSize.width > copySize.width ||
|
||||
dstSpec.textureSize.height > copySize.height;
|
||||
|
||||
// Create and init dst texture.
|
||||
wgpu::Texture dstTexture;
|
||||
wgpu::TextureDescriptor dstDescriptor;
|
||||
dstDescriptor.size = dstSpec.textureSize;
|
||||
|
@ -216,52 +293,57 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
|
||||
dstTexture = device.CreateTexture(&dstDescriptor);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
|
||||
const utils::TextureDataCopyLayout copyLayout =
|
||||
if (testSubRectCopy) {
|
||||
// For subrect copy tests, dst texture use kTextureFormat always.
|
||||
const utils::TextureDataCopyLayout dstCopyLayout =
|
||||
utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
kTextureFormat,
|
||||
{srcSpec.textureSize.width, srcSpec.textureSize.height,
|
||||
{dstSpec.textureSize.width, dstSpec.textureSize.height,
|
||||
copySize.depthOrArrayLayers},
|
||||
srcSpec.level);
|
||||
dstSpec.level);
|
||||
|
||||
const std::vector<RGBA8> textureArrayCopyData =
|
||||
useFixedTestValue ? GetFixedSourceTextureData() : GetSourceTextureData(copyLayout);
|
||||
wgpu::ImageCopyTexture imageCopyTexture =
|
||||
utils::CreateImageCopyTexture(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z});
|
||||
const std::vector<RGBA8> dstTextureArrayCopyData =
|
||||
GetTextureData(dstCopyLayout, TextureCopyRole::DEST);
|
||||
|
||||
wgpu::TextureDataLayout textureDataLayout;
|
||||
textureDataLayout.offset = 0;
|
||||
textureDataLayout.bytesPerRow = copyLayout.bytesPerRow;
|
||||
textureDataLayout.rowsPerImage = copyLayout.rowsPerImage;
|
||||
wgpu::TextureDataLayout dstTextureDataLayout;
|
||||
dstTextureDataLayout.offset = 0;
|
||||
dstTextureDataLayout.bytesPerRow = dstCopyLayout.bytesPerRow;
|
||||
dstTextureDataLayout.rowsPerImage = dstCopyLayout.rowsPerImage;
|
||||
|
||||
device.GetQueue().WriteTexture(&imageCopyTexture, textureArrayCopyData.data(),
|
||||
textureArrayCopyData.size() * sizeof(RGBA8),
|
||||
&textureDataLayout, ©Layout.mipSize);
|
||||
wgpu::ImageCopyTexture dstImageTextureInit =
|
||||
utils::CreateImageCopyTexture(dstTexture, dstSpec.level, {0, 0});
|
||||
|
||||
device.GetQueue().WriteTexture(&dstImageTextureInit, dstTextureArrayCopyData.data(),
|
||||
dstTextureArrayCopyData.size() * sizeof(RGBA8),
|
||||
&dstTextureDataLayout, &dstCopyLayout.mipSize);
|
||||
}
|
||||
|
||||
// Perform the texture to texture copy
|
||||
wgpu::ImageCopyTexture srcImageCopyTexture =
|
||||
utils::CreateImageCopyTexture(srcTexture, srcSpec.level, srcSpec.copyOrigin);
|
||||
wgpu::ImageCopyTexture dstImageCopyTexture =
|
||||
utils::CreateImageCopyTexture(dstTexture, dstSpec.level, dstSpec.copyOrigin);
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
device.GetQueue().CopyTextureForBrowser(&srcImageCopyTexture, &dstImageCopyTexture,
|
||||
©Size, &options);
|
||||
|
||||
// Update uniform buffer based on test config
|
||||
uint32_t uniformBufferData[] = {
|
||||
options.flipY, // copy have flipY option
|
||||
GetTextureFormatComponentCount(dstSpec.format)}; // channelCount
|
||||
GetTextureFormatComponentCount(dstSpec.format), // channelCount
|
||||
srcSpec.copyOrigin.x,
|
||||
srcSpec.copyOrigin.y, // src texture copy origin
|
||||
dstSpec.copyOrigin.x,
|
||||
dstSpec.copyOrigin.y, // dst texture copy origin
|
||||
copySize.width,
|
||||
copySize.height // copy size
|
||||
};
|
||||
|
||||
device.GetQueue().WriteBuffer(uniformBuffer, 0, uniformBufferData,
|
||||
sizeof(uniformBufferData));
|
||||
|
||||
// Create output buffer to store result
|
||||
wgpu::BufferDescriptor outputDesc;
|
||||
outputDesc.size = copySize.width * copySize.height * sizeof(uint32_t);
|
||||
outputDesc.size = dstSpec.textureSize.width * dstSpec.textureSize.height * sizeof(uint32_t);
|
||||
outputDesc.usage =
|
||||
wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||
wgpu::Buffer outputBuffer = device.CreateBuffer(&outputDesc);
|
||||
|
@ -278,10 +360,7 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
// Create bind group based on the config.
|
||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
||||
device, testPipeline.GetBindGroupLayout(0),
|
||||
{{0, srcTextureView},
|
||||
{1, dstTextureView},
|
||||
{2, outputBuffer, 0, copySize.width * copySize.height * sizeof(uint32_t)},
|
||||
{3, uniformBuffer, 0, sizeof(uniformBufferData)}});
|
||||
{{0, srcTextureView}, {1, dstTextureView}, {2, outputBuffer}, {3, uniformBuffer}});
|
||||
|
||||
// Start a pipeline to check pixel value in bit form.
|
||||
wgpu::CommandEncoder testEncoder = device.CreateCommandEncoder();
|
||||
|
@ -292,16 +371,18 @@ class CopyTextureForBrowserTests : public DawnTest {
|
|||
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
pass.SetPipeline(testPipeline);
|
||||
pass.SetBindGroup(0, bindGroup);
|
||||
pass.Dispatch(copySize.width, copySize.height);
|
||||
pass.Dispatch(dstSpec.textureSize.width,
|
||||
dstSpec.textureSize.height); // Verify dst texture content
|
||||
pass.EndPass();
|
||||
|
||||
testCommands = encoder.Finish();
|
||||
}
|
||||
queue.Submit(1, &testCommands);
|
||||
|
||||
std::vector<uint32_t> expectResult(copySize.width * copySize.height, 1);
|
||||
std::vector<uint32_t> expectResult(dstSpec.textureSize.width * dstSpec.textureSize.height,
|
||||
1);
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(expectResult.data(), outputBuffer, 0,
|
||||
copySize.width * copySize.height);
|
||||
dstSpec.textureSize.width * dstSpec.textureSize.height);
|
||||
}
|
||||
|
||||
wgpu::Buffer uniformBuffer; // Uniform buffer to store dst texture meta info.
|
||||
|
@ -431,6 +512,35 @@ TEST_P(CopyTextureForBrowserTests, FromBGRA8UnormCopy) {
|
|||
}
|
||||
}
|
||||
|
||||
// Verify |CopyTextureForBrowser| doing subrect copy.
|
||||
// Source texture is a full red texture and dst texture is a full
|
||||
// green texture originally. After the subrect copy, affected part
|
||||
// in dst texture should be red and other part should remain green.
|
||||
TEST_P(CopyTextureForBrowserTests, CopySubRect) {
|
||||
// Tests skip due to crbug.com/dawn/592.
|
||||
DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
|
||||
|
||||
for (wgpu::Origin3D srcOrigin : kOrigins) {
|
||||
for (wgpu::Origin3D dstOrigin : kOrigins) {
|
||||
for (wgpu::Extent3D copySize : kCopySize) {
|
||||
for (bool flipY : {true, false}) {
|
||||
TextureSpec srcTextureSpec;
|
||||
srcTextureSpec.copyOrigin = srcOrigin;
|
||||
srcTextureSpec.textureSize = {6, 7};
|
||||
|
||||
TextureSpec dstTextureSpec;
|
||||
dstTextureSpec.copyOrigin = dstOrigin;
|
||||
dstTextureSpec.textureSize = {8, 5};
|
||||
wgpu::CopyTextureForBrowserOptions options = {};
|
||||
options.flipY = flipY;
|
||||
|
||||
DoTest(srcTextureSpec, dstTextureSpec, copySize, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(CopyTextureForBrowserTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
|
|
Loading…
Reference in New Issue