dawn-cmake/src/dawn/native/CopyTextureForBrowserHelper.cpp
Zhaoming Jiang 7ca82ac4d0 dawn: Refactor device creation and add shader-f16 feature
This CL modifies the way adapter creating devices, adds `shader-f16`
feature, and deprecates the `dawn-shader-float16` feature which is no
longer used.
Details:
1. Parse the toggles chained with device descriptor in
`adapter::CreateDeviceInternal`, which are then used to validate
features requirement within `CreateDeviceInternal` and passed to device
constructor as initializer.
2. When creating device, validate features requirement in
`CreateDeviceInternal` with toggles known, make sure to fail the device
creation if a required feature is not supported by adapter or is guarded
by certain toggles which were not enabled/disabled. Feature ShaderF16
and ChromiumExperimentalDp4a are validated in this way. Unittest is
added to check creating devices with toggles-guarded features required.
3. Add `shader-f16` feature, which allow `using f16;` in WGSL code.
End-to-end tests are added to test a trival f16 WGSL shader could be
used if and only if the device has `shader-f16` feature.
4. Deprecate the `dawn-shader-float16` feature, which will be completely
removed after cleaning up Blink code.

Bug: dawn:1510
Change-Id: I6cb2dcbe1ee584fdd6131c62df1ee850b881dbd2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100802
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
2022-09-08 00:11:04 +00:00

625 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/CopyTextureForBrowserHelper.h"
#include <unordered_set>
#include <utility>
#include "dawn/common/Log.h"
#include "dawn/native/BindGroup.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/CommandBuffer.h"
#include "dawn/native/CommandEncoder.h"
#include "dawn/native/CommandValidation.h"
#include "dawn/native/Device.h"
#include "dawn/native/InternalPipelineStore.h"
#include "dawn/native/Queue.h"
#include "dawn/native/RenderPassEncoder.h"
#include "dawn/native/RenderPipeline.h"
#include "dawn/native/Sampler.h"
#include "dawn/native/Texture.h"
#include "dawn/native/ValidationUtils_autogen.h"
#include "dawn/native/utils/WGPUHelpers.h"
namespace dawn::native {
namespace {
static const char sCopyTextureForBrowserShader[] = R"(
struct GammaTransferParams {
G: f32,
A: f32,
B: f32,
C: f32,
D: f32,
E: f32,
F: f32,
padding: u32,
};
struct Uniforms { // offset align size
scale: vec2<f32>, // 0 8 8
offset: vec2<f32>, // 8 8 8
steps_mask: u32, // 16 4 4
// implicit padding; // 20 12
conversion_matrix: mat3x3<f32>, // 32 16 48
gamma_decoding_params: GammaTransferParams, // 80 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;
struct VertexOutputs {
@location(0) texcoords : vec2<f32>,
@builtin(position) position : vec4<f32>,
};
// Chromium uses unified equation to construct gamma decoding function
// and gamma encoding function.
// The logic is:
// if x < D
// linear = C * x + F
// nonlinear = pow(A * x + B, G) + E
// (https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/color_transform.cc;l=541)
// Expand the equation with sign() to make it handle all gamma conversions.
fn gamma_conversion(v: f32, params: GammaTransferParams) -> f32 {
// Linear part: C * x + F
if (abs(v) < params.D) {
return sign(v) * (params.C * abs(v) + params.F);
}
// Gamma part: pow(A * x + B, G) + E
return sign(v) * (pow(params.A * abs(v) + params.B, params.G) + params.E);
}
@vertex
fn vs_main(
@builtin(vertex_index) VertexIndex : u32
) -> VertexOutputs {
var texcoord = array<vec2<f32>, 3>(
vec2<f32>(-0.5, 0.0),
vec2<f32>( 1.5, 0.0),
vec2<f32>( 0.5, 2.0));
var output : VertexOutputs;
output.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 = uniforms.scale.y < 0.0;
// Texture coordinate takes top-left as origin point. We need to map the
// texture to triangle carefully.
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.
output.texcoords = (texcoord[VertexIndex] * uniforms.scale + uniforms.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.
output.texcoords = (texcoord[VertexIndex] *
vec2<f32>(1.0, -1.0) + vec2<f32>(0.0, 1.0)) *
uniforms.scale + uniforms.offset;
}
return output;
}
@binding(1) @group(0) var mySampler: sampler;
@binding(2) @group(0) var myTexture: texture_2d<f32>;
@fragment
fn fs_main(
@location(0) texcoord : vec2<f32>
) -> @location(0) vec4<f32> {
// Clamp the texcoord and discard the out-of-bound pixels.
var clampedTexcoord =
clamp(texcoord, vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0));
// 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.
var color = textureSample(myTexture, mySampler, texcoord);
if (!all(clampedTexcoord == texcoord)) {
discard;
}
let kUnpremultiplyStep = 0x01u;
let kDecodeToLinearStep = 0x02u;
let kConvertToDstGamutStep = 0x04u;
let kEncodeToGammaStep = 0x08u;
let kPremultiplyStep = 0x10u;
let kDecodeForSrgbDstFormat = 0x20u;
let kClearSrcAlphaToOne = 0x40u;
// Unpremultiply step. Appling color space conversion op on premultiplied source texture
// also needs to unpremultiply first.
// This step is exclusive with clear src alpha to one step.
if (bool(uniforms.steps_mask & kUnpremultiplyStep)) {
if (color.a != 0.0) {
color = vec4<f32>(color.rgb / color.a, color.a);
}
}
// Linearize the source color using the source color spaces
// transfer function if it is non-linear.
if (bool(uniforms.steps_mask & kDecodeToLinearStep)) {
color = vec4<f32>(gamma_conversion(color.r, uniforms.gamma_decoding_params),
gamma_conversion(color.g, uniforms.gamma_decoding_params),
gamma_conversion(color.b, uniforms.gamma_decoding_params),
color.a);
}
// Convert unpremultiplied, linear source colors to the destination gamut by
// multiplying by a 3x3 matrix. Calculate transformFromXYZD50 * transformToXYZD50
// in CPU side and upload the final result in uniforms.
if (bool(uniforms.steps_mask & kConvertToDstGamutStep)) {
color = vec4<f32>(uniforms.conversion_matrix * color.rgb, color.a);
}
// Encode that color using the inverse of the destination color
// spaces transfer function if it is non-linear.
if (bool(uniforms.steps_mask & kEncodeToGammaStep)) {
color = vec4<f32>(gamma_conversion(color.r, uniforms.gamma_encoding_params),
gamma_conversion(color.g, uniforms.gamma_encoding_params),
gamma_conversion(color.b, uniforms.gamma_encoding_params),
color.a);
}
// Premultiply step.
// This step is exclusive with clear src alpha to one step.
if (bool(uniforms.steps_mask & kPremultiplyStep)) {
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);
}
// Clear alpha to one step.
// This step is exclusive with premultiply/unpremultiply step.
if (bool(uniforms.steps_mask & kClearSrcAlphaToOne)) {
color.a = 1.0;
}
return color;
}
)";
// Follow the same order of skcms_TransferFunction
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/include/third_party/skcms/skcms.h;l=46;
struct GammaTransferParams {
float G = 0.0;
float A = 0.0;
float B = 0.0;
float C = 0.0;
float D = 0.0;
float E = 0.0;
float F = 0.0;
uint32_t padding = 0;
};
struct Uniform {
float scaleX;
float scaleY;
float offsetX;
float offsetY;
uint32_t stepsMask = 0;
const std::array<uint32_t, 3> padding = {}; // 12 bytes padding
std::array<float, 12> conversionMatrix = {};
GammaTransferParams gammaDecodingParams = {};
GammaTransferParams gammaEncodingParams = {};
GammaTransferParams gammaDecodingForDstSrgbParams = {};
};
static_assert(sizeof(Uniform) == 176);
// TODO(crbug.com/dawn/856): Expand copyTextureForBrowser to support any
// non-depth, non-stencil, non-compressed texture format pair copy.
MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcFormat,
const wgpu::TextureFormat dstFormat) {
switch (srcFormat) {
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA16Float:
break;
default:
return DAWN_VALIDATION_ERROR("Source texture format (%s) is not supported.", srcFormat);
}
switch (dstFormat) {
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG16Float:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA32Float:
break;
default:
return DAWN_VALIDATION_ERROR("Destination texture format (%s) is not supported.",
dstFormat);
}
return {};
}
RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store, wgpu::TextureFormat dstFormat) {
auto pipeline = store->copyTextureForBrowserPipelines.find(dstFormat);
if (pipeline != store->copyTextureForBrowserPipelines.end()) {
return pipeline->second.Get();
}
return nullptr;
}
ResultOrError<RenderPipelineBase*> GetOrCreateCopyTextureForBrowserPipeline(
DeviceBase* device,
wgpu::TextureFormat dstFormat) {
InternalPipelineStore* store = device->GetInternalPipelineStore();
if (GetCachedPipeline(store, dstFormat) == nullptr) {
// Create vertex shader module if not cached before.
if (store->copyTextureForBrowser == nullptr) {
DAWN_TRY_ASSIGN(store->copyTextureForBrowser,
utils::CreateShaderModule(device, sCopyTextureForBrowserShader));
}
ShaderModuleBase* shaderModule = store->copyTextureForBrowser.Get();
// Prepare vertex stage.
VertexState vertex = {};
vertex.module = shaderModule;
vertex.entryPoint = "vs_main";
// Prepare frgament stage.
FragmentState fragment = {};
fragment.module = shaderModule;
fragment.entryPoint = "fs_main";
// Prepare color state.
ColorTargetState target = {};
target.format = dstFormat;
// Create RenderPipeline.
RenderPipelineDescriptor renderPipelineDesc = {};
// Generate the layout based on shader modules.
renderPipelineDesc.layout = nullptr;
renderPipelineDesc.vertex = vertex;
renderPipelineDesc.fragment = &fragment;
renderPipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
fragment.targetCount = 1;
fragment.targets = &target;
Ref<RenderPipelineBase> pipeline;
DAWN_TRY_ASSIGN(pipeline, device->CreateRenderPipeline(&renderPipelineDesc));
store->copyTextureForBrowserPipelines.insert({dstFormat, std::move(pipeline)});
}
return GetCachedPipeline(store, dstFormat);
}
} // anonymous namespace
MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
DAWN_TRY(device->ValidateObject(source->texture));
DAWN_TRY(device->ValidateObject(destination->texture));
DAWN_INVALID_IF(source->texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Source texture %s is destroyed.", source->texture);
DAWN_INVALID_IF(destination->texture->GetTextureState() == TextureBase::TextureState::Destroyed,
"Destination texture %s is destroyed.", destination->texture);
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, *source, *copySize),
"validating the ImageCopyTexture for the source");
DAWN_TRY_CONTEXT(ValidateImageCopyTexture(device, *destination, *copySize),
"validating the ImageCopyTexture for the destination");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, *source, *copySize),
"validating that the copy fits in the source");
DAWN_TRY_CONTEXT(ValidateTextureCopyRange(device, *destination, *copySize),
"validating that the copy fits in the destination");
DAWN_TRY(ValidateTextureToTextureCopyCommonRestrictions(*source, *destination, *copySize));
DAWN_INVALID_IF(source->origin.z > 0, "Source has a non-zero z origin (%u).", source->origin.z);
DAWN_INVALID_IF(copySize->depthOrArrayLayers > 1, "Copy is for more than one array layer (%u)",
copySize->depthOrArrayLayers);
DAWN_INVALID_IF(
source->texture->GetSampleCount() > 1 || destination->texture->GetSampleCount() > 1,
"The source texture sample count (%u) or the destination texture sample count (%u) is "
"not 1.",
source->texture->GetSampleCount(), destination->texture->GetSampleCount());
DAWN_INVALID_IF(
options->internalUsage && !device->HasFeature(Feature::DawnInternalUsages),
"The internalUsage is true while the dawn-internal-usages feature is not enabled.");
UsageValidationMode mode =
options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc, mode));
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::TextureBinding, mode));
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst, mode));
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::RenderAttachment, mode));
DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format,
destination->texture->GetFormat().format));
DAWN_INVALID_IF(options->nextInChain != nullptr, "nextInChain must be nullptr");
DAWN_TRY(ValidateAlphaMode(options->srcAlphaMode));
DAWN_TRY(ValidateAlphaMode(options->dstAlphaMode));
if (options->needsColorSpaceConversion) {
DAWN_INVALID_IF(options->srcTransferFunctionParameters == nullptr,
"srcTransferFunctionParameters is nullptr when doing color conversion");
DAWN_INVALID_IF(options->conversionMatrix == nullptr,
"conversionMatrix is nullptr when doing color conversion");
DAWN_INVALID_IF(options->dstTransferFunctionParameters == nullptr,
"dstTransferFunctionParameters is nullptr when doing color conversion");
}
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,
const ImageCopyTexture* source,
const ImageCopyTexture* destination,
const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) {
// TODO(crbug.com/dawn/856): In D3D12 and Vulkan, compatible texture format can directly
// copy to each other. This can be a potential fast path.
// Noop copy
if (copySize->width == 0 || copySize->height == 0 || copySize->depthOrArrayLayers == 0) {
return {};
}
bool isSrgbDstFormat = IsSrgbDstFormat(destination->texture->GetFormat().format);
RenderPipelineBase* pipeline;
DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyTextureForBrowserPipeline(
device, destination->texture->GetFormat().format));
// Prepare bind group layout.
Ref<BindGroupLayoutBase> layout;
DAWN_TRY_ASSIGN(layout, pipeline->GetBindGroupLayout(0));
Extent3D srcTextureSize = source->texture->GetSize();
// Prepare binding 0 resource: uniform buffer.
Uniform uniformData = {
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. 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->flipY) {
uniformData.scaleY *= -1.0;
uniformData.offsetY += copySize->height / static_cast<float>(srcTextureSize.height);
}
uint32_t stepsMask = 0u;
// Steps to do color space conversion
// From https://skia.org/docs/user/color/
// - unpremultiply if the source color is premultiplied; Alpha is not involved in color
// management, and we need to divide it out if its multiplied in.
// - linearize the source color using the source color spaces transfer function
// - convert those unpremultiplied, linear source colors to XYZ D50 gamut by multiplying by
// a 3x3 matrix.
// - convert those XYZ D50 colors to the destination gamut by multiplying by a 3x3 matrix.
// - encode that color using the inverse of the destination color spaces transfer function.
// - premultiply by alpha if the destination is premultiplied.
// The reason to choose XYZ D50 as intermediate color space:
// From http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html
// "Since the Lab TIFF specification, the ICC profile specification and
// Adobe Photoshop all use a D50"
constexpr uint32_t kUnpremultiplyStep = 0x01;
constexpr uint32_t kDecodeToLinearStep = 0x02;
constexpr uint32_t kConvertToDstGamutStep = 0x04;
constexpr uint32_t kEncodeToGammaStep = 0x08;
constexpr uint32_t kPremultiplyStep = 0x10;
constexpr uint32_t kDecodeForSrgbDstFormat = 0x20;
constexpr uint32_t kClearSrcAlphaToOne = 0x40;
if (options->srcAlphaMode == wgpu::AlphaMode::Premultiplied) {
if (options->needsColorSpaceConversion ||
options->dstAlphaMode == wgpu::AlphaMode::Unpremultiplied) {
stepsMask |= kUnpremultiplyStep;
}
} else if (options->srcAlphaMode == wgpu::AlphaMode::Opaque) {
// Simply clear src alpha channel to 1.0
stepsMask |= kClearSrcAlphaToOne;
}
if (options->needsColorSpaceConversion) {
stepsMask |= kDecodeToLinearStep;
const float* decodingParams = options->srcTransferFunctionParameters;
uniformData.gammaDecodingParams = {decodingParams[0], decodingParams[1], decodingParams[2],
decodingParams[3], decodingParams[4], decodingParams[5],
decodingParams[6]};
stepsMask |= kConvertToDstGamutStep;
const float* matrix = options->conversionMatrix;
uniformData.conversionMatrix = {{
matrix[0],
matrix[1],
matrix[2],
0.0,
matrix[3],
matrix[4],
matrix[5],
0.0,
matrix[6],
matrix[7],
matrix[8],
0.0,
}};
stepsMask |= kEncodeToGammaStep;
const float* encodingParams = options->dstTransferFunctionParameters;
uniformData.gammaEncodingParams = {encodingParams[0], encodingParams[1], encodingParams[2],
encodingParams[3], encodingParams[4], encodingParams[5],
encodingParams[6]};
}
if (options->dstAlphaMode == wgpu::AlphaMode::Premultiplied) {
if (options->needsColorSpaceConversion ||
options->srcAlphaMode == wgpu::AlphaMode::Unpremultiplied) {
stepsMask |= kPremultiplyStep;
}
}
// 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;
Ref<BufferBase> uniformBuffer;
DAWN_TRY_ASSIGN(
uniformBuffer,
utils::CreateBufferFromData(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform,
{uniformData}));
// Prepare binding 1 resource: sampler
// Use default configuration, filterMode set to Nearest for min and mag.
SamplerDescriptor samplerDesc = {};
Ref<SamplerBase> sampler;
DAWN_TRY_ASSIGN(sampler, device->CreateSampler(&samplerDesc));
// Prepare binding 2 resource: sampled texture
TextureViewDescriptor srcTextureViewDesc = {};
srcTextureViewDesc.dimension = wgpu::TextureViewDimension::e2D;
srcTextureViewDesc.baseMipLevel = source->mipLevel;
srcTextureViewDesc.mipLevelCount = 1;
srcTextureViewDesc.arrayLayerCount = 1;
Ref<TextureViewBase> srcTextureView;
DAWN_TRY_ASSIGN(srcTextureView,
device->CreateTextureView(source->texture, &srcTextureViewDesc));
// Create bind group after all binding entries are set.
UsageValidationMode mode =
options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default;
Ref<BindGroupBase> bindGroup;
DAWN_TRY_ASSIGN(bindGroup, utils::MakeBindGroup(
device, layout,
{{0, uniformBuffer}, {1, sampler}, {2, srcTextureView}}, mode));
// Create command encoder.
CommandEncoderDescriptor commandEncoderDesc;
DawnEncoderInternalUsageDescriptor internalUsageDesc;
if (options->internalUsage) {
internalUsageDesc.useInternalUsages = true;
commandEncoderDesc.nextInChain = &internalUsageDesc;
}
Ref<CommandEncoder> encoder;
DAWN_TRY_ASSIGN(encoder, device->CreateCommandEncoder(&commandEncoderDesc));
// Prepare dst texture view as color Attachment.
TextureViewDescriptor dstTextureViewDesc;
dstTextureViewDesc.dimension = wgpu::TextureViewDimension::e2D;
dstTextureViewDesc.baseMipLevel = destination->mipLevel;
dstTextureViewDesc.mipLevelCount = 1;
dstTextureViewDesc.baseArrayLayer = destination->origin.z;
dstTextureViewDesc.arrayLayerCount = 1;
Ref<TextureViewBase> dstView;
DAWN_TRY_ASSIGN(dstView, device->CreateTextureView(destination->texture, &dstTextureViewDesc));
// Prepare render pass color attachment descriptor.
RenderPassColorAttachment colorAttachmentDesc;
colorAttachmentDesc.view = dstView.Get();
colorAttachmentDesc.loadOp = wgpu::LoadOp::Load;
colorAttachmentDesc.storeOp = wgpu::StoreOp::Store;
colorAttachmentDesc.clearValue = {0.0, 0.0, 0.0, 1.0};
// Create render pass.
RenderPassDescriptor renderPassDesc;
renderPassDesc.colorAttachmentCount = 1;
renderPassDesc.colorAttachments = &colorAttachmentDesc;
Ref<RenderPassEncoder> passEncoder = encoder->BeginRenderPass(&renderPassDesc);
// Start pipeline and encode commands to complete
// 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->APIEnd();
// Finsh encoding.
Ref<CommandBufferBase> commandBuffer;
DAWN_TRY_ASSIGN(commandBuffer, encoder->Finish());
CommandBufferBase* submitCommandBuffer = commandBuffer.Get();
// Submit command buffer.
device->GetQueue()->APISubmit(1, &submitCommandBuffer);
return {};
}
} // namespace dawn::native