542 lines
22 KiB
C++
542 lines
22 KiB
C++
// Copyright 2017 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/d3d12/RenderPipelineD3D12.h"
|
|
|
|
#include <d3dcompiler.h>
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "dawn/common/Assert.h"
|
|
#include "dawn/common/Log.h"
|
|
#include "dawn/native/CreatePipelineAsyncTask.h"
|
|
#include "dawn/native/d3d12/D3D12Error.h"
|
|
#include "dawn/native/d3d12/DeviceD3D12.h"
|
|
#include "dawn/native/d3d12/PipelineLayoutD3D12.h"
|
|
#include "dawn/native/d3d12/PlatformFunctions.h"
|
|
#include "dawn/native/d3d12/ShaderModuleD3D12.h"
|
|
#include "dawn/native/d3d12/TextureD3D12.h"
|
|
#include "dawn/native/d3d12/UtilsD3D12.h"
|
|
|
|
namespace dawn::native::d3d12 {
|
|
|
|
namespace {
|
|
DXGI_FORMAT VertexFormatType(wgpu::VertexFormat format) {
|
|
switch (format) {
|
|
case wgpu::VertexFormat::Uint8x2:
|
|
return DXGI_FORMAT_R8G8_UINT;
|
|
case wgpu::VertexFormat::Uint8x4:
|
|
return DXGI_FORMAT_R8G8B8A8_UINT;
|
|
case wgpu::VertexFormat::Sint8x2:
|
|
return DXGI_FORMAT_R8G8_SINT;
|
|
case wgpu::VertexFormat::Sint8x4:
|
|
return DXGI_FORMAT_R8G8B8A8_SINT;
|
|
case wgpu::VertexFormat::Unorm8x2:
|
|
return DXGI_FORMAT_R8G8_UNORM;
|
|
case wgpu::VertexFormat::Unorm8x4:
|
|
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
case wgpu::VertexFormat::Snorm8x2:
|
|
return DXGI_FORMAT_R8G8_SNORM;
|
|
case wgpu::VertexFormat::Snorm8x4:
|
|
return DXGI_FORMAT_R8G8B8A8_SNORM;
|
|
case wgpu::VertexFormat::Uint16x2:
|
|
return DXGI_FORMAT_R16G16_UINT;
|
|
case wgpu::VertexFormat::Uint16x4:
|
|
return DXGI_FORMAT_R16G16B16A16_UINT;
|
|
case wgpu::VertexFormat::Sint16x2:
|
|
return DXGI_FORMAT_R16G16_SINT;
|
|
case wgpu::VertexFormat::Sint16x4:
|
|
return DXGI_FORMAT_R16G16B16A16_SINT;
|
|
case wgpu::VertexFormat::Unorm16x2:
|
|
return DXGI_FORMAT_R16G16_UNORM;
|
|
case wgpu::VertexFormat::Unorm16x4:
|
|
return DXGI_FORMAT_R16G16B16A16_UNORM;
|
|
case wgpu::VertexFormat::Snorm16x2:
|
|
return DXGI_FORMAT_R16G16_SNORM;
|
|
case wgpu::VertexFormat::Snorm16x4:
|
|
return DXGI_FORMAT_R16G16B16A16_SNORM;
|
|
case wgpu::VertexFormat::Float16x2:
|
|
return DXGI_FORMAT_R16G16_FLOAT;
|
|
case wgpu::VertexFormat::Float16x4:
|
|
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
|
case wgpu::VertexFormat::Float32:
|
|
return DXGI_FORMAT_R32_FLOAT;
|
|
case wgpu::VertexFormat::Float32x2:
|
|
return DXGI_FORMAT_R32G32_FLOAT;
|
|
case wgpu::VertexFormat::Float32x3:
|
|
return DXGI_FORMAT_R32G32B32_FLOAT;
|
|
case wgpu::VertexFormat::Float32x4:
|
|
return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
case wgpu::VertexFormat::Uint32:
|
|
return DXGI_FORMAT_R32_UINT;
|
|
case wgpu::VertexFormat::Uint32x2:
|
|
return DXGI_FORMAT_R32G32_UINT;
|
|
case wgpu::VertexFormat::Uint32x3:
|
|
return DXGI_FORMAT_R32G32B32_UINT;
|
|
case wgpu::VertexFormat::Uint32x4:
|
|
return DXGI_FORMAT_R32G32B32A32_UINT;
|
|
case wgpu::VertexFormat::Sint32:
|
|
return DXGI_FORMAT_R32_SINT;
|
|
case wgpu::VertexFormat::Sint32x2:
|
|
return DXGI_FORMAT_R32G32_SINT;
|
|
case wgpu::VertexFormat::Sint32x3:
|
|
return DXGI_FORMAT_R32G32B32_SINT;
|
|
case wgpu::VertexFormat::Sint32x4:
|
|
return DXGI_FORMAT_R32G32B32A32_SINT;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
D3D12_INPUT_CLASSIFICATION VertexStepModeFunction(wgpu::VertexStepMode mode) {
|
|
switch (mode) {
|
|
case wgpu::VertexStepMode::Vertex:
|
|
return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
|
case wgpu::VertexStepMode::Instance:
|
|
return D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
|
|
case wgpu::VertexStepMode::VertexBufferNotUsed:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
D3D12_PRIMITIVE_TOPOLOGY D3D12PrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology) {
|
|
switch (primitiveTopology) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
D3D12_PRIMITIVE_TOPOLOGY_TYPE D3D12PrimitiveTopologyType(
|
|
wgpu::PrimitiveTopology primitiveTopology) {
|
|
switch (primitiveTopology) {
|
|
case wgpu::PrimitiveTopology::PointList:
|
|
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
|
case wgpu::PrimitiveTopology::LineList:
|
|
case wgpu::PrimitiveTopology::LineStrip:
|
|
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
|
case wgpu::PrimitiveTopology::TriangleList:
|
|
case wgpu::PrimitiveTopology::TriangleStrip:
|
|
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
}
|
|
}
|
|
|
|
D3D12_CULL_MODE D3D12CullMode(wgpu::CullMode mode) {
|
|
switch (mode) {
|
|
case wgpu::CullMode::None:
|
|
return D3D12_CULL_MODE_NONE;
|
|
case wgpu::CullMode::Front:
|
|
return D3D12_CULL_MODE_FRONT;
|
|
case wgpu::CullMode::Back:
|
|
return D3D12_CULL_MODE_BACK;
|
|
}
|
|
}
|
|
|
|
D3D12_BLEND D3D12Blend(wgpu::BlendFactor factor) {
|
|
switch (factor) {
|
|
case wgpu::BlendFactor::Zero:
|
|
return D3D12_BLEND_ZERO;
|
|
case wgpu::BlendFactor::One:
|
|
return D3D12_BLEND_ONE;
|
|
case wgpu::BlendFactor::Src:
|
|
return D3D12_BLEND_SRC_COLOR;
|
|
case wgpu::BlendFactor::OneMinusSrc:
|
|
return D3D12_BLEND_INV_SRC_COLOR;
|
|
case wgpu::BlendFactor::SrcAlpha:
|
|
return D3D12_BLEND_SRC_ALPHA;
|
|
case wgpu::BlendFactor::OneMinusSrcAlpha:
|
|
return D3D12_BLEND_INV_SRC_ALPHA;
|
|
case wgpu::BlendFactor::Dst:
|
|
return D3D12_BLEND_DEST_COLOR;
|
|
case wgpu::BlendFactor::OneMinusDst:
|
|
return D3D12_BLEND_INV_DEST_COLOR;
|
|
case wgpu::BlendFactor::DstAlpha:
|
|
return D3D12_BLEND_DEST_ALPHA;
|
|
case wgpu::BlendFactor::OneMinusDstAlpha:
|
|
return D3D12_BLEND_INV_DEST_ALPHA;
|
|
case wgpu::BlendFactor::SrcAlphaSaturated:
|
|
return D3D12_BLEND_SRC_ALPHA_SAT;
|
|
case wgpu::BlendFactor::Constant:
|
|
return D3D12_BLEND_BLEND_FACTOR;
|
|
case wgpu::BlendFactor::OneMinusConstant:
|
|
return D3D12_BLEND_INV_BLEND_FACTOR;
|
|
}
|
|
}
|
|
|
|
// 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
|
|
D3D12_BLEND D3D12AlphaBlend(wgpu::BlendFactor factor) {
|
|
switch (factor) {
|
|
case wgpu::BlendFactor::Src:
|
|
return D3D12_BLEND_SRC_ALPHA;
|
|
case wgpu::BlendFactor::OneMinusSrc:
|
|
return D3D12_BLEND_INV_SRC_ALPHA;
|
|
case wgpu::BlendFactor::Dst:
|
|
return D3D12_BLEND_DEST_ALPHA;
|
|
case wgpu::BlendFactor::OneMinusDst:
|
|
return D3D12_BLEND_INV_DEST_ALPHA;
|
|
|
|
// Other blend factors translate to the same D3D12 enum as the color blend factors.
|
|
default:
|
|
return D3D12Blend(factor);
|
|
}
|
|
}
|
|
|
|
D3D12_BLEND_OP D3D12BlendOperation(wgpu::BlendOperation operation) {
|
|
switch (operation) {
|
|
case wgpu::BlendOperation::Add:
|
|
return D3D12_BLEND_OP_ADD;
|
|
case wgpu::BlendOperation::Subtract:
|
|
return D3D12_BLEND_OP_SUBTRACT;
|
|
case wgpu::BlendOperation::ReverseSubtract:
|
|
return D3D12_BLEND_OP_REV_SUBTRACT;
|
|
case wgpu::BlendOperation::Min:
|
|
return D3D12_BLEND_OP_MIN;
|
|
case wgpu::BlendOperation::Max:
|
|
return D3D12_BLEND_OP_MAX;
|
|
}
|
|
}
|
|
|
|
uint8_t D3D12RenderTargetWriteMask(wgpu::ColorWriteMask writeMask) {
|
|
static_assert(static_cast<D3D12_COLOR_WRITE_ENABLE>(wgpu::ColorWriteMask::Red) ==
|
|
D3D12_COLOR_WRITE_ENABLE_RED,
|
|
"ColorWriteMask values must match");
|
|
static_assert(static_cast<D3D12_COLOR_WRITE_ENABLE>(wgpu::ColorWriteMask::Green) ==
|
|
D3D12_COLOR_WRITE_ENABLE_GREEN,
|
|
"ColorWriteMask values must match");
|
|
static_assert(static_cast<D3D12_COLOR_WRITE_ENABLE>(wgpu::ColorWriteMask::Blue) ==
|
|
D3D12_COLOR_WRITE_ENABLE_BLUE,
|
|
"ColorWriteMask values must match");
|
|
static_assert(static_cast<D3D12_COLOR_WRITE_ENABLE>(wgpu::ColorWriteMask::Alpha) ==
|
|
D3D12_COLOR_WRITE_ENABLE_ALPHA,
|
|
"ColorWriteMask values must match");
|
|
return static_cast<uint8_t>(writeMask);
|
|
}
|
|
|
|
D3D12_RENDER_TARGET_BLEND_DESC ComputeColorDesc(const ColorTargetState* state) {
|
|
D3D12_RENDER_TARGET_BLEND_DESC blendDesc;
|
|
blendDesc.BlendEnable = state->blend != nullptr;
|
|
if (blendDesc.BlendEnable) {
|
|
blendDesc.SrcBlend = D3D12Blend(state->blend->color.srcFactor);
|
|
blendDesc.DestBlend = D3D12Blend(state->blend->color.dstFactor);
|
|
blendDesc.BlendOp = D3D12BlendOperation(state->blend->color.operation);
|
|
blendDesc.SrcBlendAlpha = D3D12AlphaBlend(state->blend->alpha.srcFactor);
|
|
blendDesc.DestBlendAlpha = D3D12AlphaBlend(state->blend->alpha.dstFactor);
|
|
blendDesc.BlendOpAlpha = D3D12BlendOperation(state->blend->alpha.operation);
|
|
}
|
|
blendDesc.RenderTargetWriteMask = D3D12RenderTargetWriteMask(state->writeMask);
|
|
blendDesc.LogicOpEnable = false;
|
|
blendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
return blendDesc;
|
|
}
|
|
|
|
D3D12_STENCIL_OP StencilOp(wgpu::StencilOperation op) {
|
|
switch (op) {
|
|
case wgpu::StencilOperation::Keep:
|
|
return D3D12_STENCIL_OP_KEEP;
|
|
case wgpu::StencilOperation::Zero:
|
|
return D3D12_STENCIL_OP_ZERO;
|
|
case wgpu::StencilOperation::Replace:
|
|
return D3D12_STENCIL_OP_REPLACE;
|
|
case wgpu::StencilOperation::IncrementClamp:
|
|
return D3D12_STENCIL_OP_INCR_SAT;
|
|
case wgpu::StencilOperation::DecrementClamp:
|
|
return D3D12_STENCIL_OP_DECR_SAT;
|
|
case wgpu::StencilOperation::Invert:
|
|
return D3D12_STENCIL_OP_INVERT;
|
|
case wgpu::StencilOperation::IncrementWrap:
|
|
return D3D12_STENCIL_OP_INCR;
|
|
case wgpu::StencilOperation::DecrementWrap:
|
|
return D3D12_STENCIL_OP_DECR;
|
|
}
|
|
}
|
|
|
|
D3D12_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilFaceState& descriptor) {
|
|
D3D12_DEPTH_STENCILOP_DESC desc;
|
|
|
|
desc.StencilFailOp = StencilOp(descriptor.failOp);
|
|
desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
|
|
desc.StencilPassOp = StencilOp(descriptor.passOp);
|
|
desc.StencilFunc = ToD3D12ComparisonFunc(descriptor.compare);
|
|
|
|
return desc;
|
|
}
|
|
|
|
D3D12_DEPTH_STENCIL_DESC ComputeDepthStencilDesc(const DepthStencilState* descriptor) {
|
|
D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor;
|
|
mDepthStencilDescriptor.DepthEnable =
|
|
(descriptor->depthCompare == wgpu::CompareFunction::Always &&
|
|
!descriptor->depthWriteEnabled)
|
|
? FALSE
|
|
: TRUE;
|
|
mDepthStencilDescriptor.DepthWriteMask =
|
|
descriptor->depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
|
mDepthStencilDescriptor.DepthFunc = ToD3D12ComparisonFunc(descriptor->depthCompare);
|
|
|
|
mDepthStencilDescriptor.StencilEnable = StencilTestEnabled(descriptor) ? TRUE : FALSE;
|
|
mDepthStencilDescriptor.StencilReadMask = static_cast<UINT8>(descriptor->stencilReadMask);
|
|
mDepthStencilDescriptor.StencilWriteMask = static_cast<UINT8>(descriptor->stencilWriteMask);
|
|
|
|
mDepthStencilDescriptor.FrontFace = StencilOpDesc(descriptor->stencilFront);
|
|
mDepthStencilDescriptor.BackFace = StencilOpDesc(descriptor->stencilBack);
|
|
return mDepthStencilDescriptor;
|
|
}
|
|
|
|
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE ComputeIndexBufferStripCutValue(
|
|
wgpu::PrimitiveTopology primitiveTopology,
|
|
wgpu::IndexFormat indexFormat) {
|
|
if (primitiveTopology != wgpu::PrimitiveTopology::TriangleStrip &&
|
|
primitiveTopology != wgpu::PrimitiveTopology::LineStrip) {
|
|
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
|
}
|
|
|
|
switch (indexFormat) {
|
|
case wgpu::IndexFormat::Uint16:
|
|
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
|
case wgpu::IndexFormat::Uint32:
|
|
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
|
|
case wgpu::IndexFormat::Undefined:
|
|
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
|
}
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
|
|
Device* device,
|
|
const RenderPipelineDescriptor* descriptor) {
|
|
return AcquireRef(new RenderPipeline(device, descriptor));
|
|
}
|
|
|
|
MaybeError RenderPipeline::Initialize() {
|
|
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;
|
|
}
|
|
|
|
// SPRIV-cross does matrix multiplication expecting row major matrices
|
|
compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
|
|
|
|
// FXC can miscompile code that depends on special float values (NaN, INF, etc) when IEEE
|
|
// strictness is not enabled. See crbug.com/tint/976.
|
|
compileFlags |= D3DCOMPILE_IEEE_STRICTNESS;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC descriptorD3D12 = {};
|
|
|
|
PerStage<ProgrammableStage> pipelineStages = GetAllStages();
|
|
|
|
PerStage<D3D12_SHADER_BYTECODE*> shaders;
|
|
shaders[SingleShaderStage::Vertex] = &descriptorD3D12.VS;
|
|
shaders[SingleShaderStage::Fragment] = &descriptorD3D12.PS;
|
|
|
|
PerStage<CompiledShader> compiledShader;
|
|
|
|
for (auto stage : IterateStages(GetStageMask())) {
|
|
DAWN_TRY_ASSIGN(compiledShader[stage], ToBackend(pipelineStages[stage].module)
|
|
->Compile(pipelineStages[stage], stage,
|
|
ToBackend(GetLayout()), compileFlags));
|
|
*shaders[stage] = compiledShader[stage].GetD3D12ShaderBytecode();
|
|
}
|
|
|
|
mUsesVertexOrInstanceIndex =
|
|
compiledShader[SingleShaderStage::Vertex].usesVertexOrInstanceIndex;
|
|
|
|
PipelineLayout* layout = ToBackend(GetLayout());
|
|
|
|
descriptorD3D12.pRootSignature = layout->GetRootSignature();
|
|
|
|
// D3D12 logs warnings if any empty input state is used
|
|
std::array<D3D12_INPUT_ELEMENT_DESC, kMaxVertexAttributes> inputElementDescriptors;
|
|
if (GetAttributeLocationsUsed().any()) {
|
|
descriptorD3D12.InputLayout = ComputeInputLayout(&inputElementDescriptors);
|
|
}
|
|
|
|
descriptorD3D12.IBStripCutValue =
|
|
ComputeIndexBufferStripCutValue(GetPrimitiveTopology(), GetStripIndexFormat());
|
|
|
|
descriptorD3D12.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
descriptorD3D12.RasterizerState.CullMode = D3D12CullMode(GetCullMode());
|
|
descriptorD3D12.RasterizerState.FrontCounterClockwise =
|
|
(GetFrontFace() == wgpu::FrontFace::CCW) ? TRUE : FALSE;
|
|
descriptorD3D12.RasterizerState.DepthBias = GetDepthBias();
|
|
descriptorD3D12.RasterizerState.DepthBiasClamp = GetDepthBiasClamp();
|
|
descriptorD3D12.RasterizerState.SlopeScaledDepthBias = GetDepthBiasSlopeScale();
|
|
descriptorD3D12.RasterizerState.DepthClipEnable = TRUE;
|
|
descriptorD3D12.RasterizerState.MultisampleEnable = (GetSampleCount() > 1) ? TRUE : FALSE;
|
|
descriptorD3D12.RasterizerState.AntialiasedLineEnable = FALSE;
|
|
descriptorD3D12.RasterizerState.ForcedSampleCount = 0;
|
|
descriptorD3D12.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
|
|
if (HasDepthStencilAttachment()) {
|
|
descriptorD3D12.DSVFormat = D3D12TextureFormat(GetDepthStencilFormat());
|
|
}
|
|
|
|
static_assert(kMaxColorAttachments == 8);
|
|
for (uint8_t i = 0; i < kMaxColorAttachments; i++) {
|
|
descriptorD3D12.RTVFormats[i] = DXGI_FORMAT_UNKNOWN;
|
|
descriptorD3D12.BlendState.RenderTarget[i].BlendEnable = false;
|
|
descriptorD3D12.BlendState.RenderTarget[i].RenderTargetWriteMask = 0;
|
|
descriptorD3D12.BlendState.RenderTarget[i].LogicOpEnable = false;
|
|
descriptorD3D12.BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
}
|
|
ColorAttachmentIndex highestColorAttachmentIndexPlusOne =
|
|
GetHighestBitIndexPlusOne(GetColorAttachmentsMask());
|
|
for (ColorAttachmentIndex i : IterateBitSet(GetColorAttachmentsMask())) {
|
|
descriptorD3D12.RTVFormats[static_cast<uint8_t>(i)] =
|
|
D3D12TextureFormat(GetColorAttachmentFormat(i));
|
|
descriptorD3D12.BlendState.RenderTarget[static_cast<uint8_t>(i)] =
|
|
ComputeColorDesc(GetColorTargetState(i));
|
|
}
|
|
ASSERT(highestColorAttachmentIndexPlusOne <= kMaxColorAttachmentsTyped);
|
|
descriptorD3D12.NumRenderTargets = static_cast<uint8_t>(highestColorAttachmentIndexPlusOne);
|
|
|
|
descriptorD3D12.BlendState.AlphaToCoverageEnable = IsAlphaToCoverageEnabled();
|
|
descriptorD3D12.BlendState.IndependentBlendEnable = TRUE;
|
|
|
|
descriptorD3D12.DepthStencilState = ComputeDepthStencilDesc(GetDepthStencilState());
|
|
|
|
descriptorD3D12.SampleMask = GetSampleMask();
|
|
descriptorD3D12.PrimitiveTopologyType = D3D12PrimitiveTopologyType(GetPrimitiveTopology());
|
|
descriptorD3D12.SampleDesc.Count = GetSampleCount();
|
|
descriptorD3D12.SampleDesc.Quality = 0;
|
|
|
|
mD3d12PrimitiveTopology = D3D12PrimitiveTopology(GetPrimitiveTopology());
|
|
|
|
mCacheKey.Record(descriptorD3D12, *layout->GetRootSignatureBlob());
|
|
|
|
// Try to see if we have anything in the blob cache.
|
|
CachedBlob blob = device->LoadCachedBlob(GetCacheKey());
|
|
const bool cacheHit = !blob.Empty();
|
|
if (cacheHit) {
|
|
// Cache hits, attach cached blob to descriptor.
|
|
descriptorD3D12.CachedPSO.pCachedBlob = blob.Data();
|
|
descriptorD3D12.CachedPSO.CachedBlobSizeInBytes = blob.Size();
|
|
}
|
|
|
|
DAWN_TRY(CheckHRESULT(device->GetD3D12Device()->CreateGraphicsPipelineState(
|
|
&descriptorD3D12, IID_PPV_ARGS(&mPipelineState)),
|
|
"D3D12 create graphics pipeline state"));
|
|
|
|
if (!cacheHit) {
|
|
// Cache misses, need to get pipeline cached blob and store.
|
|
ComPtr<ID3DBlob> d3dBlob;
|
|
DAWN_TRY(CheckHRESULT(GetPipelineState()->GetCachedBlob(&d3dBlob),
|
|
"D3D12 render pipeline state get cached blob"));
|
|
device->StoreCachedBlob(GetCacheKey(), CachedBlob::Create(std::move(d3dBlob)));
|
|
}
|
|
|
|
SetLabelImpl();
|
|
|
|
return {};
|
|
}
|
|
|
|
RenderPipeline::~RenderPipeline() = default;
|
|
|
|
void RenderPipeline::DestroyImpl() {
|
|
RenderPipelineBase::DestroyImpl();
|
|
ToBackend(GetDevice())->ReferenceUntilUnused(mPipelineState);
|
|
}
|
|
|
|
D3D12_PRIMITIVE_TOPOLOGY RenderPipeline::GetD3D12PrimitiveTopology() const {
|
|
return mD3d12PrimitiveTopology;
|
|
}
|
|
|
|
ID3D12PipelineState* RenderPipeline::GetPipelineState() const {
|
|
return mPipelineState.Get();
|
|
}
|
|
|
|
bool RenderPipeline::UsesVertexOrInstanceIndex() const {
|
|
return mUsesVertexOrInstanceIndex;
|
|
}
|
|
|
|
void RenderPipeline::SetLabelImpl() {
|
|
SetDebugName(ToBackend(GetDevice()), GetPipelineState(), "Dawn_RenderPipeline", GetLabel());
|
|
}
|
|
|
|
ComPtr<ID3D12CommandSignature> RenderPipeline::GetDrawIndirectCommandSignature() {
|
|
if (mUsesVertexOrInstanceIndex) {
|
|
return ToBackend(GetLayout())->GetDrawIndirectCommandSignatureWithInstanceVertexOffsets();
|
|
}
|
|
|
|
return ToBackend(GetDevice())->GetDrawIndirectSignature();
|
|
}
|
|
|
|
ComPtr<ID3D12CommandSignature> RenderPipeline::GetDrawIndexedIndirectCommandSignature() {
|
|
if (mUsesVertexOrInstanceIndex) {
|
|
return ToBackend(GetLayout())
|
|
->GetDrawIndexedIndirectCommandSignatureWithInstanceVertexOffsets();
|
|
}
|
|
|
|
return ToBackend(GetDevice())->GetDrawIndexedIndirectSignature();
|
|
}
|
|
|
|
D3D12_INPUT_LAYOUT_DESC RenderPipeline::ComputeInputLayout(
|
|
std::array<D3D12_INPUT_ELEMENT_DESC, kMaxVertexAttributes>* inputElementDescriptors) {
|
|
unsigned int count = 0;
|
|
for (VertexAttributeLocation loc : IterateBitSet(GetAttributeLocationsUsed())) {
|
|
D3D12_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 = VertexFormatType(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 == D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA) {
|
|
inputElementDescriptor.InstanceDataStepRate = 0;
|
|
} else {
|
|
inputElementDescriptor.InstanceDataStepRate = 1;
|
|
}
|
|
}
|
|
|
|
D3D12_INPUT_LAYOUT_DESC inputLayoutDescriptor;
|
|
inputLayoutDescriptor.pInputElementDescs = &(*inputElementDescriptors)[0];
|
|
inputLayoutDescriptor.NumElements = count;
|
|
return inputLayoutDescriptor;
|
|
}
|
|
|
|
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::d3d12
|