Support *-srgb format as dst formats in CopyTextureForBrowser

Dawn allows texture-to-texture copy happens between the textures that
formats only have diff on srgb-ness.

CopyTextureForBrowser could align on this rule to achieve copying to
*-srgb dst texture and keep the bytes the same as copying to non-srgb
formats.

This CL add support for *-srgb textures as dst textures and using an
extra gamma decoding step for this.

Bug: dawn:1195
Change-Id: I665dbca473aa84b9d87b7a35c4f90ce1897ade7b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/74580
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
Shaobo Yan 2022-01-07 03:05:27 +00:00 committed by Dawn LUCI CQ
parent e009ad7edd
commit c40f04b85b
2 changed files with 101 additions and 13 deletions

View File

@ -48,14 +48,15 @@ namespace dawn_native {
padding: u32; padding: u32;
}; };
struct Uniforms { // offset align size struct Uniforms { // offset align size
scale: vec2<f32>; // 0 8 8 scale: vec2<f32>; // 0 8 8
offset: vec2<f32>; // 8 8 8 offset: vec2<f32>; // 8 8 8
steps_mask: u32; // 16 4 4 steps_mask: u32; // 16 4 4
// implicit padding; // 20 12 // implicit padding; // 20 12
conversion_matrix: mat3x3<f32>; // 32 16 48 conversion_matrix: mat3x3<f32>; // 32 16 48
gamma_decoding_params: GammaTransferParams; // 80 4 32 gamma_decoding_params: GammaTransferParams; // 80 4 32
gamma_encoding_params: GammaTransferParams; // 112 4 32 gamma_encoding_params: GammaTransferParams; // 112 4 32
gamma_decoding_for_dst_srgb_params: GammaTransferParams; // 144 4 32
}; };
[[binding(0), group(0)]] var<uniform> uniforms : Uniforms; [[binding(0), group(0)]] var<uniform> uniforms : Uniforms;
@ -141,6 +142,7 @@ namespace dawn_native {
let kConvertToDstGamutStep = 0x04u; let kConvertToDstGamutStep = 0x04u;
let kEncodeToGammaStep = 0x08u; let kEncodeToGammaStep = 0x08u;
let kPremultiplyStep = 0x10u; let kPremultiplyStep = 0x10u;
let kDecodeForSrgbDstFormat = 0x20u;
// Unpremultiply step. Appling color space conversion op on premultiplied source texture // Unpremultiply step. Appling color space conversion op on premultiplied source texture
// also needs to unpremultiply first. // also needs to unpremultiply first.
@ -180,6 +182,14 @@ namespace dawn_native {
color = vec4<f32>(color.rgb * color.a, color.a); color = vec4<f32>(color.rgb * color.a, color.a);
} }
// Decode for copying from non-srgb formats to srgb formats
if (bool(uniforms.steps_mask & kDecodeForSrgbDstFormat)) {
color = vec4<f32>(gamma_conversion(color.r, uniforms.gamma_decoding_for_dst_srgb_params),
gamma_conversion(color.g, uniforms.gamma_decoding_for_dst_srgb_params),
gamma_conversion(color.b, uniforms.gamma_decoding_for_dst_srgb_params),
color.a);
}
return color; return color;
} }
)"; )";
@ -207,8 +217,9 @@ namespace dawn_native {
std::array<float, 12> conversionMatrix = {}; std::array<float, 12> conversionMatrix = {};
GammaTransferParams gammaDecodingParams = {}; GammaTransferParams gammaDecodingParams = {};
GammaTransferParams gammaEncodingParams = {}; GammaTransferParams gammaEncodingParams = {};
GammaTransferParams gammaDecodingForDstSrgbParams = {};
}; };
static_assert(sizeof(Uniform) == 144, ""); static_assert(sizeof(Uniform) == 176, "");
// TODO(crbug.com/dawn/856): Expand copyTextureForBrowser to support any // TODO(crbug.com/dawn/856): Expand copyTextureForBrowser to support any
// non-depth, non-stencil, non-compressed texture format pair copy. Now this API // non-depth, non-stencil, non-compressed texture format pair copy. Now this API
@ -232,7 +243,9 @@ namespace dawn_native {
case wgpu::TextureFormat::RG16Float: case wgpu::TextureFormat::RG16Float:
case wgpu::TextureFormat::RG32Float: case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RGBA8Unorm: case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::BGRA8Unorm: case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
case wgpu::TextureFormat::RGB10A2Unorm: case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGBA16Float: case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA32Float: case wgpu::TextureFormat::RGBA32Float:
@ -362,6 +375,17 @@ namespace dawn_native {
return {}; return {};
} }
// Whether the format of dst texture of CopyTextureForBrowser() is srgb or non-srgb.
bool IsSrgbDstFormat(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::BGRA8UnormSrgb:
return true;
default:
return false;
}
}
MaybeError DoCopyTextureForBrowser(DeviceBase* device, MaybeError DoCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source, const ImageCopyTexture* source,
const ImageCopyTexture* destination, const ImageCopyTexture* destination,
@ -375,6 +399,7 @@ namespace dawn_native {
return {}; return {};
} }
bool isSrgbDstFormat = IsSrgbDstFormat(destination->texture->GetFormat().format);
RenderPipelineBase* pipeline; RenderPipelineBase* pipeline;
DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyTextureForBrowserPipeline( DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyTextureForBrowserPipeline(
device, destination->texture->GetFormat().format)); device, destination->texture->GetFormat().format));
@ -422,6 +447,7 @@ namespace dawn_native {
constexpr uint32_t kConvertToDstGamutStep = 0x04; constexpr uint32_t kConvertToDstGamutStep = 0x04;
constexpr uint32_t kEncodeToGammaStep = 0x08; constexpr uint32_t kEncodeToGammaStep = 0x08;
constexpr uint32_t kPremultiplyStep = 0x10; constexpr uint32_t kPremultiplyStep = 0x10;
constexpr uint32_t kDecodeForSrgbDstFormat = 0x20;
if (options->srcAlphaMode == wgpu::AlphaMode::Premultiplied) { if (options->srcAlphaMode == wgpu::AlphaMode::Premultiplied) {
if (options->needsColorSpaceConversion || if (options->needsColorSpaceConversion ||
@ -470,6 +496,25 @@ namespace dawn_native {
} }
} }
// Copy to *-srgb texture should keep the bytes exactly the same as copy
// to non-srgb texture. Add an extra decode-to-linear step so that after the
// sampler of *-srgb format texture applying encoding, the bytes keeps the same
// as non-srgb format texture.
// NOTE: CopyTextureForBrowser() doesn't need to accept *-srgb format texture as
// source input. But above operation also valid for *-srgb format texture input and
// non-srgb format dst texture.
// TODO(crbug.com/dawn/1195): Reinterpret to non-srgb texture view on *-srgb texture
// and use it as render attachment when possible.
// TODO(crbug.com/dawn/1195): Opt the condition for this extra step. It is possible to
// bypass this extra step in some cases.
if (isSrgbDstFormat) {
stepsMask |= kDecodeForSrgbDstFormat;
// Get gamma-linear conversion params from https://en.wikipedia.org/wiki/SRGB with some
// mathematics. Order: {G, A, B, C, D, E, F, }
uniformData.gammaDecodingForDstSrgbParams = {
2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 4.045e-02, 0.0, 0.0};
}
uniformData.stepsMask = stepsMask; uniformData.stepsMask = stepsMask;
Ref<BufferBase> uniformBuffer; Ref<BufferBase> uniformBuffer;
@ -511,9 +556,9 @@ namespace dawn_native {
dstTextureViewDesc.baseArrayLayer = destination->origin.z; dstTextureViewDesc.baseArrayLayer = destination->origin.z;
dstTextureViewDesc.arrayLayerCount = 1; dstTextureViewDesc.arrayLayerCount = 1;
Ref<TextureViewBase> dstView; Ref<TextureViewBase> dstView;
DAWN_TRY_ASSIGN(dstView, DAWN_TRY_ASSIGN(dstView,
device->CreateTextureView(destination->texture, &dstTextureViewDesc)); device->CreateTextureView(destination->texture, &dstTextureViewDesc));
// Prepare render pass color attachment descriptor. // Prepare render pass color attachment descriptor.
RenderPassColorAttachment colorAttachmentDesc; RenderPassColorAttachment colorAttachmentDesc;
@ -546,7 +591,6 @@ namespace dawn_native {
// Submit command buffer. // Submit command buffer.
device->GetQueue()->APISubmit(1, &submitCommandBuffer); device->GetQueue()->APISubmit(1, &submitCommandBuffer);
return {}; return {};
} }

View File

@ -571,6 +571,17 @@ class CopyTextureForBrowser_Formats
GetParam().mDstFormat == wgpu::TextureFormat::BGRA8UnormSrgb; GetParam().mDstFormat == wgpu::TextureFormat::BGRA8UnormSrgb;
} }
wgpu::TextureFormat GetNonSrgbFormat(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::RGBA8UnormSrgb:
return wgpu::TextureFormat::RGBA8Unorm;
case wgpu::TextureFormat::BGRA8UnormSrgb:
return wgpu::TextureFormat::BGRA8Unorm;
default:
return format;
}
}
void DoColorConversionTest() { void DoColorConversionTest() {
TextureSpec srcTextureSpec; TextureSpec srcTextureSpec;
srcTextureSpec.format = GetParam().mSrcFormat; srcTextureSpec.format = GetParam().mSrcFormat;
@ -627,8 +638,40 @@ class CopyTextureForBrowser_Formats
RunCopyExternalImageToTexture(srcTextureSpec, srcTexture, dstTextureSpec, dstTexture, RunCopyExternalImageToTexture(srcTextureSpec, srcTexture, dstTextureSpec, dstTexture,
copySize, options); copySize, options);
wgpu::Texture result;
TextureSpec resultSpec = dstTextureSpec;
// To construct the expected value for the case that dst texture is srgb format,
// we need to ensure it is byte level equal to the comparable non-srgb format texture.
// We schedule an copy from srgb texture to non-srgb texture which keeps the bytes
// same and bypass the sampler to do gamma correction when comparing the expected values
// in compute shader.
if (IsDstFormatSrgbFormats()) {
resultSpec.format = GetNonSrgbFormat(dstTextureSpec.format);
wgpu::Texture intermediateTexture = CreateTexture(
resultSpec, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
// Perform the texture to texture copy
wgpu::ImageCopyTexture dstImageCopyTexture =
utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0});
wgpu::ImageCopyTexture intermediateImageCopyTexture =
utils::CreateImageCopyTexture(intermediateTexture, 0, {0, 0, 0});
encoder.CopyTextureToTexture(&dstImageCopyTexture, &intermediateImageCopyTexture,
&(dstTextureSpec.textureSize));
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
result = intermediateTexture;
} else {
result = dstTexture;
}
// Check Result // Check Result
CheckResultInBuiltInComputePipeline(srcTextureSpec, srcTexture, dstTextureSpec, dstTexture, CheckResultInBuiltInComputePipeline(srcTextureSpec, srcTexture, resultSpec, result,
copySize, options); copySize, options);
} }
}; };
@ -1045,7 +1088,8 @@ DAWN_INSTANTIATE_TEST_P(
{wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R16Float, wgpu::TextureFormat::R32Float, {wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R16Float, wgpu::TextureFormat::R32Float,
wgpu::TextureFormat::RG8Unorm, wgpu::TextureFormat::RG16Float, wgpu::TextureFormat::RG8Unorm, wgpu::TextureFormat::RG16Float,
wgpu::TextureFormat::RG32Float, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::RG32Float, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureFormat::BGRA8Unorm, wgpu::TextureFormat::RGB10A2Unorm, wgpu::TextureFormat::RGBA8UnormSrgb, wgpu::TextureFormat::BGRA8Unorm,
wgpu::TextureFormat::BGRA8UnormSrgb, wgpu::TextureFormat::RGB10A2Unorm,
wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RGBA32Float})); wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RGBA32Float}));
// Verify |CopyTextureForBrowser| doing subrect copy. // Verify |CopyTextureForBrowser| doing subrect copy.