Reland "CopyTextureForBrowser: Support color format conversion"
This is a reland of f84daa070f05eb80672a9a23e23aed205fe72a5e
Eliminate static initializer(disallowed in Chromium) by replacing
shader string living in anonymous namespace from type "std::string"
to char array.
Original change's description:
> CopyTextureForBrowser: Support color format conversion
>
> This CL enables blit from RGBA8Unorm soruce texture to dst texture that
> |CopyImageBitmapToTexture| supported dst format.
>
> BUG=dawn:465
>
> Change-Id: I99846cf8dc37bc89e0c168a3d86193bb3a0c0ebb
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/44020
> Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
> Reviewed-by: Austin Eng <enga@chromium.org>
Bug: dawn:465
Change-Id: Ic3a156f5a20b217fd2aa5f86b01bad8ce77dc41c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/45443
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index e4ad9e2..b5cfc7c 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -394,9 +394,9 @@
return {};
}
- MaybeError ValidateTextureToTextureCopyRestrictions(const ImageCopyTexture& src,
- const ImageCopyTexture& dst,
- const Extent3D& copySize) {
+ MaybeError ValidateTextureToTextureCopyCommonRestrictions(const ImageCopyTexture& src,
+ const ImageCopyTexture& dst,
+ const Extent3D& copySize) {
const uint32_t srcSamples = src.texture->GetSampleCount();
const uint32_t dstSamples = dst.texture->GetSampleCount();
@@ -405,11 +405,6 @@
"Source and destination textures must have matching sample counts.");
}
- if (src.texture->GetFormat().format != dst.texture->GetFormat().format) {
- // Metal requires texture-to-texture copies be the same format
- return DAWN_VALIDATION_ERROR("Source and destination texture formats must match.");
- }
-
// Metal cannot select a single aspect for texture-to-texture copies.
const Format& format = src.texture->GetFormat();
if (SelectFormatAspects(format, src.aspect) != format.aspects) {
@@ -434,6 +429,34 @@
return {};
}
+ MaybeError ValidateTextureToTextureCopyRestrictions(const ImageCopyTexture& src,
+ const ImageCopyTexture& dst,
+ const Extent3D& copySize) {
+ if (src.texture->GetFormat().format != dst.texture->GetFormat().format) {
+ // Metal requires texture-to-texture copies be the same format
+ return DAWN_VALIDATION_ERROR("Source and destination texture formats must match.");
+ }
+
+ return ValidateTextureToTextureCopyCommonRestrictions(src, dst, copySize);
+ }
+
+ // CopyTextureForBrowser could handle color conversion during the copy and it
+ // requires the source must be sampleable and the destination must be writable
+ // using a render pass
+ MaybeError ValidateCopyTextureForBrowserRestrictions(const ImageCopyTexture& src,
+ const ImageCopyTexture& dst,
+ const Extent3D& copySize) {
+ if (!(src.texture->GetUsage() & wgpu::TextureUsage::Sampled)) {
+ return DAWN_VALIDATION_ERROR("Source texture must have sampled usage");
+ }
+
+ if (!(dst.texture->GetUsage() & wgpu::TextureUsage::OutputAttachment)) {
+ return DAWN_VALIDATION_ERROR("Dest texture must have outputAttachment usage");
+ }
+
+ return ValidateTextureToTextureCopyCommonRestrictions(src, dst, copySize);
+ }
+
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) {
ASSERT(wgpu::HasZeroOrOneBits(usage));
if (!(texture->GetUsage() & usage)) {
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index f6dc60a..5b6290c 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -75,6 +75,10 @@
const ImageCopyTexture& dst,
const Extent3D& copySize);
+ MaybeError ValidateCopyTextureForBrowserRestrictions(const ImageCopyTexture& src,
+ const ImageCopyTexture& dst,
+ const Extent3D& copySize);
+
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage);
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage);
diff --git a/src/dawn_native/CopyTextureForBrowserHelper.cpp b/src/dawn_native/CopyTextureForBrowserHelper.cpp
index dac5f1d..7838450 100644
--- a/src/dawn_native/CopyTextureForBrowserHelper.cpp
+++ b/src/dawn_native/CopyTextureForBrowserHelper.cpp
@@ -32,7 +32,7 @@
namespace dawn_native {
namespace {
- // TODO(shaobo.yan@intel.com) : Support premultiplay-alpha, flipY.
+ // TODO(shaobo.yan@intel.com) : Support premultiplay-alpha
static const char sCopyTextureForBrowserVertex[] = R"(
[[block]] struct Uniforms {
u_scale : vec2<f32>;
@@ -56,25 +56,31 @@
}
)";
- static const char sPassthrough2D4ChannelFrag[] = R"(
+ static const char sCopyTextureForBrowserFragment[] = R"(
[[binding(1), group(0)]] var mySampler: sampler;
[[binding(2), group(0)]] var myTexture: texture_2d<f32>;
[[location(0)]] var<in> v_texcoord : vec2<f32>;
- [[location(0)]] var<out> rgbaColor : vec4<f32>;
+ [[location(0)]] var<out> outputColor : vec4<f32>;
[[stage(fragment)]] fn main() -> void {
// Clamp the texcoord and discard the out-of-bound pixels.
var clampedTexcoord : vec2<f32> =
clamp(v_texcoord, vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0));
if (all(clampedTexcoord == v_texcoord)) {
- rgbaColor = textureSample(myTexture, mySampler, v_texcoord);
+ var srcColor : vec4<f32> = textureSample(myTexture, mySampler, v_texcoord);
+ // Swizzling of texture formats when sampling / rendering is handled by the
+ // hardware so we don't need special logic in this shader. This is covered by tests.
+ outputColor = srcColor;
}
}
)";
- // TODO(shaobo.yan@intel.com): Expand supported texture formats
+ // TODO(shaobo.yan@intel.com): Expand copyTextureForBrowser to support any
+ // non-depth, non-stencil, non-compressed texture format pair copy. Now this API
+ // supports CopyImageBitmapToTexture normal format pairs.
MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcFormat,
const wgpu::TextureFormat dstFormat) {
switch (srcFormat) {
+ case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::RGBA8Unorm:
break;
default:
@@ -84,6 +90,12 @@
switch (dstFormat) {
case wgpu::TextureFormat::RGBA8Unorm:
+ case wgpu::TextureFormat::BGRA8Unorm:
+ case wgpu::TextureFormat::RGBA32Float:
+ case wgpu::TextureFormat::RG8Unorm:
+ case wgpu::TextureFormat::RGBA16Float:
+ case wgpu::TextureFormat::RG16Float:
+ case wgpu::TextureFormat::RGB10A2Unorm:
break;
default:
return DAWN_VALIDATION_ERROR(
@@ -103,10 +115,21 @@
return {};
}
- RenderPipelineBase* GetOrCreateCopyTextureForBrowserPipeline(DeviceBase* device) {
+ RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store,
+ wgpu::TextureFormat dstFormat) {
+ auto pipeline = store->copyTextureForBrowserPipelines.find(dstFormat);
+ if (pipeline != store->copyTextureForBrowserPipelines.end()) {
+ return pipeline->second.Get();
+ }
+ return nullptr;
+ }
+
+ RenderPipelineBase* GetOrCreateCopyTextureForBrowserPipeline(
+ DeviceBase* device,
+ wgpu::TextureFormat dstFormat) {
InternalPipelineStore* store = device->GetInternalPipelineStore();
- if (store->copyTextureForBrowserPipeline == nullptr) {
+ if (GetCachedPipeline(store, dstFormat) == nullptr) {
// Create vertex shader module if not cached before.
if (store->copyTextureForBrowserVS == nullptr) {
ShaderModuleDescriptor descriptor;
@@ -124,7 +147,7 @@
if (store->copyTextureForBrowserFS == nullptr) {
ShaderModuleDescriptor descriptor;
ShaderModuleWGSLDescriptor wgslDesc;
- wgslDesc.source = sPassthrough2D4ChannelFrag;
+ wgslDesc.source = sCopyTextureForBrowserFragment;
descriptor.nextInChain = reinterpret_cast<ChainedStruct*>(&wgslDesc);
store->copyTextureForBrowserFS =
AcquireRef(device->CreateShaderModule(&descriptor));
@@ -144,7 +167,7 @@
// Prepare color state.
ColorTargetState target = {};
- target.format = wgpu::TextureFormat::RGBA8Unorm;
+ target.format = dstFormat;
// Create RenderPipeline.
RenderPipelineDescriptor2 renderPipelineDesc = {};
@@ -160,11 +183,11 @@
fragment.targetCount = 1;
fragment.targets = ⌖
- store->copyTextureForBrowserPipeline =
- AcquireRef(device->CreateRenderPipeline2(&renderPipelineDesc));
+ store->copyTextureForBrowserPipelines.insert(
+ {dstFormat, AcquireRef(device->CreateRenderPipeline2(&renderPipelineDesc))});
}
- return store->copyTextureForBrowserPipeline.Get();
+ return GetCachedPipeline(store, dstFormat);
}
} // anonymous namespace
@@ -180,7 +203,7 @@
DAWN_TRY(ValidateImageCopyTexture(device, *source, *copySize));
DAWN_TRY(ValidateImageCopyTexture(device, *destination, *copySize));
- DAWN_TRY(ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
+ DAWN_TRY(ValidateCopyTextureForBrowserRestrictions(*source, *destination, *copySize));
DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
@@ -214,7 +237,9 @@
const CopyTextureForBrowserOptions* options) {
// TODO(shaobo.yan@intel.com): In D3D12 and Vulkan, compatible texture format can directly
// copy to each other. This can be a potential fast path.
- RenderPipelineBase* pipeline = GetOrCreateCopyTextureForBrowserPipeline(device);
+
+ RenderPipelineBase* pipeline = GetOrCreateCopyTextureForBrowserPipeline(
+ device, destination->texture->GetFormat().format);
// Prepare bind group layout.
Ref<BindGroupLayoutBase> layout = AcquireRef(pipeline->GetBindGroupLayout(0));
@@ -232,7 +257,7 @@
0.0, 0.0 // offset
};
- // Handle flipY.
+ // Handle flipY
if (options && options->flipY) {
uniformData[1] *= -1.0;
uniformData[3] += 1.0;
@@ -282,6 +307,7 @@
// Prepare render pass color attachment descriptor.
RenderPassColorAttachmentDescriptor colorAttachmentDesc;
+
colorAttachmentDesc.attachment = dstView.Get();
colorAttachmentDesc.loadOp = wgpu::LoadOp::Load;
colorAttachmentDesc.storeOp = wgpu::StoreOp::Store;
diff --git a/src/dawn_native/InternalPipelineStore.h b/src/dawn_native/InternalPipelineStore.h
index 5e3462b..1d90159 100644
--- a/src/dawn_native/InternalPipelineStore.h
+++ b/src/dawn_native/InternalPipelineStore.h
@@ -25,7 +25,9 @@
class ShaderModuleBase;
struct InternalPipelineStore {
- Ref<RenderPipelineBase> copyTextureForBrowserPipeline;
+ std::unordered_map<wgpu::TextureFormat, Ref<RenderPipelineBase>>
+ copyTextureForBrowserPipelines;
+
Ref<ShaderModuleBase> copyTextureForBrowserVS;
Ref<ShaderModuleBase> copyTextureForBrowserFS;