| // 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: |
| 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; |
| default: |
| 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; |
| default: |
| 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; |
| default: |
| 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; |
| default: |
| 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; |
| } |
| } |
| |
| 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 RenderPipelineDescriptor* descriptor) { |
| return AcquireRef(new RenderPipeline(device, descriptor)); |
| } |
| |
| RenderPipeline::RenderPipeline(Device* device, const 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 |