blob: 77bcc7ff22cd76e36c6bc83ee4305f51aa53c56e [file] [log] [blame]
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dawn/native/d3d11/RenderPipelineD3D11.h"
#include <d3dcompiler.h>
#include <array>
#include <memory>
#include <optional>
#include <utility>
#include "dawn/common/Range.h"
#include "dawn/native/CreatePipelineAsyncTask.h"
#include "dawn/native/d3d/D3DError.h"
#include "dawn/native/d3d/ShaderUtils.h"
#include "dawn/native/d3d11/DeviceD3D11.h"
#include "dawn/native/d3d11/Forward.h"
#include "dawn/native/d3d11/PipelineLayoutD3D11.h"
#include "dawn/native/d3d11/ShaderModuleD3D11.h"
#include "dawn/native/d3d11/UtilsD3D11.h"
namespace dawn::native::d3d11 {
namespace {
D3D11_INPUT_CLASSIFICATION VertexStepModeFunction(wgpu::VertexStepMode mode) {
switch (mode) {
case wgpu::VertexStepMode::Vertex:
return D3D11_INPUT_PER_VERTEX_DATA;
case wgpu::VertexStepMode::Instance:
return D3D11_INPUT_PER_INSTANCE_DATA;
case wgpu::VertexStepMode::VertexBufferNotUsed:
case wgpu::VertexStepMode::Undefined:
break;
}
DAWN_UNREACHABLE();
}
D3D_PRIMITIVE_TOPOLOGY D3DPrimitiveTopology(wgpu::PrimitiveTopology topology) {
switch (topology) {
case wgpu::PrimitiveTopology::PointList:
return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
case wgpu::PrimitiveTopology::LineList:
return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
case wgpu::PrimitiveTopology::LineStrip:
return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
case wgpu::PrimitiveTopology::TriangleList:
return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
case wgpu::PrimitiveTopology::TriangleStrip:
return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
case wgpu::PrimitiveTopology::Undefined:
break;
}
DAWN_UNREACHABLE();
}
D3D11_CULL_MODE D3DCullMode(wgpu::CullMode cullMode) {
switch (cullMode) {
case wgpu::CullMode::None:
return D3D11_CULL_NONE;
case wgpu::CullMode::Front:
return D3D11_CULL_FRONT;
case wgpu::CullMode::Back:
return D3D11_CULL_BACK;
case wgpu::CullMode::Undefined:
break;
}
DAWN_UNREACHABLE();
}
D3D11_BLEND D3DBlendFactor(wgpu::BlendFactor blendFactor) {
switch (blendFactor) {
case wgpu::BlendFactor::Zero:
return D3D11_BLEND_ZERO;
case wgpu::BlendFactor::One:
return D3D11_BLEND_ONE;
case wgpu::BlendFactor::Src:
return D3D11_BLEND_SRC_COLOR;
case wgpu::BlendFactor::OneMinusSrc:
return D3D11_BLEND_INV_SRC_COLOR;
case wgpu::BlendFactor::SrcAlpha:
return D3D11_BLEND_SRC_ALPHA;
case wgpu::BlendFactor::OneMinusSrcAlpha:
return D3D11_BLEND_INV_SRC_ALPHA;
case wgpu::BlendFactor::Dst:
return D3D11_BLEND_DEST_COLOR;
case wgpu::BlendFactor::OneMinusDst:
return D3D11_BLEND_INV_DEST_COLOR;
case wgpu::BlendFactor::DstAlpha:
return D3D11_BLEND_DEST_ALPHA;
case wgpu::BlendFactor::OneMinusDstAlpha:
return D3D11_BLEND_INV_DEST_ALPHA;
case wgpu::BlendFactor::SrcAlphaSaturated:
return D3D11_BLEND_SRC_ALPHA_SAT;
case wgpu::BlendFactor::Constant:
return D3D11_BLEND_BLEND_FACTOR;
case wgpu::BlendFactor::OneMinusConstant:
return D3D11_BLEND_INV_BLEND_FACTOR;
case wgpu::BlendFactor::Src1:
return D3D11_BLEND_SRC1_COLOR;
case wgpu::BlendFactor::OneMinusSrc1:
return D3D11_BLEND_INV_SRC1_COLOR;
case wgpu::BlendFactor::Src1Alpha:
return D3D11_BLEND_SRC1_ALPHA;
case wgpu::BlendFactor::OneMinusSrc1Alpha:
return D3D11_BLEND_INV_SRC1_ALPHA;
case wgpu::BlendFactor::Undefined:
break;
}
DAWN_UNREACHABLE();
}
// When a blend factor is defined for the alpha channel, any of the factors that don't
// explicitly state that they apply to alpha should be treated as their explicitly-alpha
// equivalents. See: https://github.com/gpuweb/gpuweb/issues/65
D3D11_BLEND D3DBlendAlphaFactor(wgpu::BlendFactor factor) {
switch (factor) {
case wgpu::BlendFactor::Src:
return D3D11_BLEND_SRC_ALPHA;
case wgpu::BlendFactor::OneMinusSrc:
return D3D11_BLEND_INV_SRC_ALPHA;
case wgpu::BlendFactor::Dst:
return D3D11_BLEND_DEST_ALPHA;
case wgpu::BlendFactor::OneMinusDst:
return D3D11_BLEND_INV_DEST_ALPHA;
case wgpu::BlendFactor::Src1:
return D3D11_BLEND_SRC1_ALPHA;
case wgpu::BlendFactor::OneMinusSrc1:
return D3D11_BLEND_INV_SRC1_ALPHA;
// Other blend factors translate to the same D3D11 enum as the color blend factors.
default:
return D3DBlendFactor(factor);
}
}
D3D11_BLEND_OP D3DBlendOperation(wgpu::BlendOperation blendOperation) {
switch (blendOperation) {
case wgpu::BlendOperation::Add:
return D3D11_BLEND_OP_ADD;
case wgpu::BlendOperation::Subtract:
return D3D11_BLEND_OP_SUBTRACT;
case wgpu::BlendOperation::ReverseSubtract:
return D3D11_BLEND_OP_REV_SUBTRACT;
case wgpu::BlendOperation::Min:
return D3D11_BLEND_OP_MIN;
case wgpu::BlendOperation::Max:
return D3D11_BLEND_OP_MAX;
case wgpu::BlendOperation::Undefined:
break;
}
DAWN_UNREACHABLE();
}
UINT D3DColorWriteMask(wgpu::ColorWriteMask colorWriteMask) {
static_assert(static_cast<UINT>(wgpu::ColorWriteMask::Red) == D3D11_COLOR_WRITE_ENABLE_RED);
static_assert(static_cast<UINT>(wgpu::ColorWriteMask::Green) == D3D11_COLOR_WRITE_ENABLE_GREEN);
static_assert(static_cast<UINT>(wgpu::ColorWriteMask::Blue) == D3D11_COLOR_WRITE_ENABLE_BLUE);
static_assert(static_cast<UINT>(wgpu::ColorWriteMask::Alpha) == D3D11_COLOR_WRITE_ENABLE_ALPHA);
return static_cast<UINT>(colorWriteMask);
}
D3D11_STENCIL_OP StencilOp(wgpu::StencilOperation op) {
switch (op) {
case wgpu::StencilOperation::Keep:
return D3D11_STENCIL_OP_KEEP;
case wgpu::StencilOperation::Zero:
return D3D11_STENCIL_OP_ZERO;
case wgpu::StencilOperation::Replace:
return D3D11_STENCIL_OP_REPLACE;
case wgpu::StencilOperation::IncrementClamp:
return D3D11_STENCIL_OP_INCR_SAT;
case wgpu::StencilOperation::DecrementClamp:
return D3D11_STENCIL_OP_DECR_SAT;
case wgpu::StencilOperation::Invert:
return D3D11_STENCIL_OP_INVERT;
case wgpu::StencilOperation::IncrementWrap:
return D3D11_STENCIL_OP_INCR;
case wgpu::StencilOperation::DecrementWrap:
return D3D11_STENCIL_OP_DECR;
case wgpu::StencilOperation::Undefined:
break;
}
DAWN_UNREACHABLE();
}
D3D11_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilFaceState& descriptor) {
D3D11_DEPTH_STENCILOP_DESC desc = {};
desc.StencilFailOp = StencilOp(descriptor.failOp);
desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
desc.StencilPassOp = StencilOp(descriptor.passOp);
desc.StencilFunc = ToD3D11ComparisonFunc(descriptor.compare);
return desc;
}
} // namespace
// static
Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
Device* device,
const UnpackedPtr<RenderPipelineDescriptor>& descriptor) {
return AcquireRef(new RenderPipeline(device, descriptor));
}
RenderPipeline::RenderPipeline(Device* device,
const UnpackedPtr<RenderPipelineDescriptor>& descriptor)
: RenderPipelineBase(device, descriptor),
mD3DPrimitiveTopology(D3DPrimitiveTopology(GetPrimitiveTopology())) {}
MaybeError RenderPipeline::Initialize() {
DAWN_TRY(InitializeRasterizerState());
DAWN_TRY(InitializeBlendState());
DAWN_TRY(InitializeShaders());
DAWN_TRY(InitializeDepthStencilState());
// RTVs and UAVs share the same resoure slots. Make sure here we are not going to run out of
// slots.
uint32_t colorAttachments =
static_cast<uint8_t>(GetHighestBitIndexPlusOne(GetColorAttachmentsMask()));
uint32_t unusedUAVs = ToBackend(GetLayout())->GetUnusedUAVBindingCount();
uint32_t usedUAVs = ToBackend(GetLayout())->GetTotalUAVBindingCount() - unusedUAVs;
// TODO(dawn:1814): Move the validation to the frontend, if we eventually regard it as a compat
// restriction.
DAWN_INVALID_IF(colorAttachments > unusedUAVs,
"The pipeline uses up to color attachment %u, but there are only %u remaining "
"slots because the pipeline uses %u UAVs",
colorAttachments, unusedUAVs, usedUAVs);
SetLabelImpl();
return {};
}
RenderPipeline::~RenderPipeline() = default;
void RenderPipeline::ApplyNow(const ScopedSwapStateCommandRecordingContext* commandContext,
const std::array<float, 4>& blendColor,
uint32_t stencilReference) {
auto* d3d11DeviceContext = commandContext->GetD3D11DeviceContext4();
d3d11DeviceContext->IASetPrimitiveTopology(mD3DPrimitiveTopology);
// TODO(dawn:1753): deduplicate these objects in the backend eventually, and to avoid redundant
// state setting.
d3d11DeviceContext->IASetInputLayout(mInputLayout.Get());
d3d11DeviceContext->RSSetState(mRasterizerState.Get());
d3d11DeviceContext->VSSetShader(mVertexShader.Get(), nullptr, 0);
d3d11DeviceContext->PSSetShader(mPixelShader.Get(), nullptr, 0);
ApplyBlendState(commandContext, blendColor);
ApplyDepthStencilState(commandContext, stencilReference);
}
void RenderPipeline::ApplyBlendState(const ScopedSwapStateCommandRecordingContext* commandContext,
const std::array<float, 4>& blendColor) {
auto* d3d11DeviceContext = commandContext->GetD3D11DeviceContext4();
d3d11DeviceContext->OMSetBlendState(mBlendState.Get(), blendColor.data(), GetSampleMask());
}
void RenderPipeline::ApplyDepthStencilState(
const ScopedSwapStateCommandRecordingContext* commandContext,
uint32_t stencilReference) {
auto* d3d11DeviceContext = commandContext->GetD3D11DeviceContext4();
d3d11DeviceContext->OMSetDepthStencilState(mDepthStencilState.Get(), stencilReference);
}
void RenderPipeline::SetLabelImpl() {
SetDebugName(ToBackend(GetDevice()), mRasterizerState.Get(), "Dawn_RenderPipeline", GetLabel());
SetDebugName(ToBackend(GetDevice()), mInputLayout.Get(), "Dawn_RenderPipeline", GetLabel());
SetDebugName(ToBackend(GetDevice()), mVertexShader.Get(), "Dawn_RenderPipeline", GetLabel());
SetDebugName(ToBackend(GetDevice()), mPixelShader.Get(), "Dawn_RenderPipeline", GetLabel());
SetDebugName(ToBackend(GetDevice()), mBlendState.Get(), "Dawn_RenderPipeline", GetLabel());
SetDebugName(ToBackend(GetDevice()), mDepthStencilState.Get(), "Dawn_RenderPipeline",
GetLabel());
}
MaybeError RenderPipeline::InitializeRasterizerState() {
Device* device = ToBackend(GetDevice());
D3D11_RASTERIZER_DESC rasterizerDesc;
rasterizerDesc.FillMode = D3D11_FILL_SOLID;
rasterizerDesc.CullMode = D3DCullMode(GetCullMode());
rasterizerDesc.FrontCounterClockwise = (GetFrontFace() == wgpu::FrontFace::CCW) ? TRUE : FALSE;
rasterizerDesc.DepthBias = GetDepthBias();
rasterizerDesc.DepthBiasClamp = GetDepthBiasClamp();
rasterizerDesc.SlopeScaledDepthBias = GetDepthBiasSlopeScale();
rasterizerDesc.DepthClipEnable = !HasUnclippedDepth();
rasterizerDesc.ScissorEnable = TRUE;
rasterizerDesc.MultisampleEnable = (GetSampleCount() > 1) ? TRUE : FALSE;
rasterizerDesc.AntialiasedLineEnable = FALSE;
DAWN_TRY(CheckHRESULT(
device->GetD3D11Device()->CreateRasterizerState(&rasterizerDesc, &mRasterizerState),
"ID3D11Device::CreateRasterizerState"));
return {};
}
MaybeError RenderPipeline::InitializeInputLayout(const Blob& vertexShader) {
if (!GetAttributeLocationsUsed().any()) {
return {};
}
std::array<D3D11_INPUT_ELEMENT_DESC, kMaxVertexAttributes> inputElementDescriptors;
UINT count = 0;
for (VertexAttributeLocation loc : IterateBitSet(GetAttributeLocationsUsed())) {
D3D11_INPUT_ELEMENT_DESC& inputElementDescriptor = inputElementDescriptors[count++];
const VertexAttributeInfo& attribute = GetAttribute(loc);
// If the HLSL semantic is TEXCOORDN the SemanticName should be "TEXCOORD" and the
// SemanticIndex N
inputElementDescriptor.SemanticName = "TEXCOORD";
inputElementDescriptor.SemanticIndex = static_cast<uint8_t>(loc);
inputElementDescriptor.Format = d3d::DXGIVertexFormat(attribute.format);
inputElementDescriptor.InputSlot = static_cast<uint8_t>(attribute.vertexBufferSlot);
const VertexBufferInfo& input = GetVertexBuffer(attribute.vertexBufferSlot);
inputElementDescriptor.AlignedByteOffset = attribute.offset;
inputElementDescriptor.InputSlotClass = VertexStepModeFunction(input.stepMode);
if (inputElementDescriptor.InputSlotClass == D3D11_INPUT_PER_VERTEX_DATA) {
inputElementDescriptor.InstanceDataStepRate = 0;
} else {
inputElementDescriptor.InstanceDataStepRate = 1;
}
}
ID3D11Device* d3d11Device = ToBackend(GetDevice())->GetD3D11Device();
DAWN_TRY(CheckHRESULT(
d3d11Device->CreateInputLayout(inputElementDescriptors.data(), count, vertexShader.Data(),
vertexShader.Size(), &mInputLayout),
"ID3D11Device::CreateInputLayout"));
return {};
}
MaybeError RenderPipeline::InitializeBlendState() {
Device* device = ToBackend(GetDevice());
CD3D11_BLEND_DESC blendDesc(D3D11_DEFAULT);
blendDesc.AlphaToCoverageEnable = IsAlphaToCoverageEnabled();
blendDesc.IndependentBlendEnable = TRUE;
static_assert(kMaxColorAttachments == std::size(blendDesc.RenderTarget));
for (auto i : Range(kMaxColorAttachmentsTyped)) {
D3D11_RENDER_TARGET_BLEND_DESC& rtBlendDesc =
blendDesc.RenderTarget[static_cast<uint8_t>(i)];
const ColorTargetState* descriptor = GetColorTargetState(i);
rtBlendDesc.BlendEnable = descriptor->blend != nullptr;
if (rtBlendDesc.BlendEnable) {
rtBlendDesc.SrcBlend = D3DBlendFactor(descriptor->blend->color.srcFactor);
if (device->GetValidInternalFormat(descriptor->format).componentCount < 4 &&
rtBlendDesc.SrcBlend == D3D11_BLEND_DEST_ALPHA) {
// According to the D3D SPEC, the default value for missing components in an element
// format is "0" for any component except A, which gets "1". So here
// D3D11_BLEND_DEST_ALPHA should have same effect as D3D11_BLEND_ONE.
// Note that this replacement can be an optimization as using D3D11_BLEND_ONE means
// the GPU hardware no longer needs to get pixels from the destination texture. It
// can also be served as a workaround against an Intel driver issue about alpha
// blending (see http://crbug.com/dawn/1579 for more details).
rtBlendDesc.SrcBlend = D3D11_BLEND_ONE;
}
rtBlendDesc.DestBlend = D3DBlendFactor(descriptor->blend->color.dstFactor);
rtBlendDesc.BlendOp = D3DBlendOperation(descriptor->blend->color.operation);
rtBlendDesc.SrcBlendAlpha = D3DBlendAlphaFactor(descriptor->blend->alpha.srcFactor);
rtBlendDesc.DestBlendAlpha = D3DBlendAlphaFactor(descriptor->blend->alpha.dstFactor);
rtBlendDesc.BlendOpAlpha = D3DBlendOperation(descriptor->blend->alpha.operation);
}
rtBlendDesc.RenderTargetWriteMask = D3DColorWriteMask(descriptor->writeMask);
}
DAWN_TRY(CheckHRESULT(device->GetD3D11Device()->CreateBlendState(&blendDesc, &mBlendState),
"ID3D11Device::CreateBlendState"));
return {};
}
MaybeError RenderPipeline::InitializeDepthStencilState() {
Device* device = ToBackend(GetDevice());
const DepthStencilState* state = GetDepthStencilState();
D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {};
depthStencilDesc.DepthEnable =
(state->depthCompare == wgpu::CompareFunction::Always && !state->depthWriteEnabled) ? FALSE
: TRUE;
depthStencilDesc.DepthWriteMask =
state->depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depthStencilDesc.DepthFunc = ToD3D11ComparisonFunc(state->depthCompare);
depthStencilDesc.StencilEnable = StencilTestEnabled(state) ? TRUE : FALSE;
depthStencilDesc.StencilReadMask = static_cast<UINT8>(state->stencilReadMask);
depthStencilDesc.StencilWriteMask = static_cast<UINT8>(state->stencilWriteMask);
depthStencilDesc.FrontFace = StencilOpDesc(state->stencilFront);
depthStencilDesc.BackFace = StencilOpDesc(state->stencilBack);
DAWN_TRY(CheckHRESULT(
device->GetD3D11Device()->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState),
"ID3D11Device::CreateDepthStencilState"));
return {};
}
MaybeError RenderPipeline::InitializeShaders() {
Device* device = ToBackend(GetDevice());
uint32_t compileFlags = 0;
if (!device->IsToggleEnabled(Toggle::UseDXC) &&
!device->IsToggleEnabled(Toggle::FxcOptimizations)) {
compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL0;
}
if (device->IsToggleEnabled(Toggle::EmitHLSLDebugSymbols)) {
compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
}
// Tint does matrix multiplication expecting row major matrices
compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
if (!device->IsToggleEnabled(Toggle::D3DDisableIEEEStrictness)) {
compileFlags |= D3DCOMPILE_IEEE_STRICTNESS;
}
PerStage<d3d::CompiledShader> compiledShader;
std::optional<dawn::native::d3d::InterStageShaderVariablesMask> usedInterstageVariables;
dawn::native::EntryPointMetadata fragmentEntryPoint;
if (GetStageMask() & wgpu::ShaderStage::Fragment) {
// Now that only fragment shader can have inter-stage inputs.
const ProgrammableStage& programmableStage = GetStage(SingleShaderStage::Fragment);
fragmentEntryPoint = programmableStage.module->GetEntryPoint(programmableStage.entryPoint);
usedInterstageVariables = dawn::native::d3d::ToInterStageShaderVariablesMask(
fragmentEntryPoint.usedInterStageVariables);
}
if (GetStageMask() & wgpu::ShaderStage::Vertex) {
const ProgrammableStage& programmableStage = GetStage(SingleShaderStage::Vertex);
DAWN_TRY_ASSIGN(
compiledShader[SingleShaderStage::Vertex],
ToBackend(programmableStage.module)
->Compile(programmableStage, SingleShaderStage::Vertex, ToBackend(GetLayout()),
compileFlags, usedInterstageVariables));
const Blob& shaderBlob = compiledShader[SingleShaderStage::Vertex].shaderBlob;
DAWN_TRY(CheckHRESULT(device->GetD3D11Device()->CreateVertexShader(
shaderBlob.Data(), shaderBlob.Size(), nullptr, &mVertexShader),
"D3D11 create vertex shader"));
DAWN_TRY(InitializeInputLayout(shaderBlob));
mUsesVertexIndex = compiledShader[SingleShaderStage::Vertex].usesVertexIndex;
mUsesInstanceIndex = compiledShader[SingleShaderStage::Vertex].usesInstanceIndex;
}
std::optional<tint::PixelLocalOptions> pixelLocalOptions;
if (GetStageMask() & wgpu::ShaderStage::Fragment) {
pixelLocalOptions = tint::PixelLocalOptions();
// HLSL SM5.0 doesn't support groups, so we set group index to 0.
pixelLocalOptions->pixel_local_group_index = 0;
if (GetAttachmentState()->HasPixelLocalStorage()) {
const std::vector<wgpu::TextureFormat>& storageAttachmentSlots =
GetAttachmentState()->GetStorageAttachmentSlots();
DAWN_ASSERT(ToBackend(GetLayout())->GetTotalUAVBindingCount() >
storageAttachmentSlots.size());
// Currently all the pixel local storage UAVs are allocated at the last several UAV
// slots. For example, when there are 4 pixel local storage attachments, we will
// allocate register u60 to u63 for them.
uint32_t basePixelLocalAttachmentIndex =
ToBackend(GetLayout())->GetTotalUAVBindingCount() -
static_cast<uint32_t>(storageAttachmentSlots.size());
for (size_t i = 0; i < storageAttachmentSlots.size(); i++) {
pixelLocalOptions->attachments[i] = basePixelLocalAttachmentIndex + i;
static_assert(
RenderPipelineBase::kImplicitPLSSlotFormat == wgpu::TextureFormat::R32Uint,
"The implicit Pixel Local Storage format should be R32Uint.");
switch (storageAttachmentSlots[i]) {
// We use R32Uint as default pixel local storage attachment format
case wgpu::TextureFormat::Undefined:
case wgpu::TextureFormat::R32Uint:
pixelLocalOptions->attachment_formats[i] =
tint::PixelLocalOptions::TexelFormat::kR32Uint;
break;
case wgpu::TextureFormat::R32Sint:
pixelLocalOptions->attachment_formats[i] =
tint::PixelLocalOptions::TexelFormat::kR32Sint;
break;
case wgpu::TextureFormat::R32Float:
pixelLocalOptions->attachment_formats[i] =
tint::PixelLocalOptions::TexelFormat::kR32Float;
break;
default:
DAWN_UNREACHABLE();
break;
}
}
}
const ProgrammableStage& programmableStage = GetStage(SingleShaderStage::Fragment);
DAWN_TRY_ASSIGN(
compiledShader[SingleShaderStage::Fragment],
ToBackend(programmableStage.module)
->Compile(programmableStage, SingleShaderStage::Fragment, ToBackend(GetLayout()),
compileFlags, usedInterstageVariables, pixelLocalOptions));
DAWN_TRY(CheckHRESULT(device->GetD3D11Device()->CreatePixelShader(
compiledShader[SingleShaderStage::Fragment].shaderBlob.Data(),
compiledShader[SingleShaderStage::Fragment].shaderBlob.Size(),
nullptr, &mPixelShader),
"D3D11 create pixel shader"));
}
return {};
}
void RenderPipeline::InitializeAsync(Ref<RenderPipelineBase> renderPipeline,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) {
std::unique_ptr<CreateRenderPipelineAsyncTask> asyncTask =
std::make_unique<CreateRenderPipelineAsyncTask>(std::move(renderPipeline), callback,
userdata);
CreateRenderPipelineAsyncTask::RunAsync(std::move(asyncTask));
}
} // namespace dawn::native::d3d11