/* * Copyright 2020 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/gpu/d3d/GrD3DRootSignature.h" #include "src/gpu/GrSPIRVUniformHandler.h" #include "src/gpu/d3d/GrD3DGpu.h" sk_sp GrD3DRootSignature::Make(GrD3DGpu* gpu, int numTextureSamplers, int numUAVs) { // Just allocate enough space for 3 in case we need it. D3D12_ROOT_PARAMETER parameters[3]; // The first will always be our uniforms parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; parameters[0].Descriptor.ShaderRegister = 0; parameters[0].Descriptor.RegisterSpace = GrSPIRVUniformHandler::kUniformDescriptorSet; parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; int parameterCount = 1; int numShaderViews = numTextureSamplers + numUAVs; SkAutoTArray samplerRanges(numTextureSamplers); SkAutoTArray shaderViewRanges(numShaderViews); if (numTextureSamplers) { // Now handle the textures and samplers. We need a range for each sampler because of the // interaction between how we set bindings and spirv-cross. Each binding value is used for // the register value in the HLSL shader. So setting a binding of i for a texture will give // it register t[i] in HLSL. We set the bindings of textures and samplers in pairs with the // sampler at i and the corresponding texture at i+1. Thus no textures or samplers will have // a contiguous range of HLSL registers so we must define a different range for each. for (int i = 0; i < numTextureSamplers; ++i) { samplerRanges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; samplerRanges[i].NumDescriptors = 1; samplerRanges[i].BaseShaderRegister = 2 * i; // Spirv-Cross uses the descriptor set as the space in HLSL samplerRanges[i].RegisterSpace = GrSPIRVUniformHandler::kSamplerTextureDescriptorSet; // In the descriptor table the descriptors will all be contiguous. samplerRanges[i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; shaderViewRanges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; shaderViewRanges[i].NumDescriptors = 1; shaderViewRanges[i].BaseShaderRegister = 2 * i + 1; // Spirv-Cross uses the descriptor set as the space in HLSL shaderViewRanges[i].RegisterSpace = GrSPIRVUniformHandler::kSamplerTextureDescriptorSet; // In the descriptor table the descriptors will all be contiguous. shaderViewRanges[i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; } } if (numUAVs) { shaderViewRanges[numTextureSamplers].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; shaderViewRanges[numTextureSamplers].NumDescriptors = numUAVs; // The assigned register range for the texture SRVs and samplers is from 0 to // 2*(numTextureSamplers-1) + 1, so we start with the next register, 2*numTextureSamplers shaderViewRanges[numTextureSamplers].BaseShaderRegister = 2 * numTextureSamplers; // We share texture descriptor set shaderViewRanges[numTextureSamplers].RegisterSpace = GrSPIRVUniformHandler::kSamplerTextureDescriptorSet; // In the descriptor table the descriptors will all be contiguous. shaderViewRanges[numTextureSamplers].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; } if (numShaderViews) { unsigned numDescriptorRanges = numUAVs ? numTextureSamplers + 1 : numTextureSamplers; parameters[parameterCount].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameters[parameterCount].DescriptorTable.NumDescriptorRanges = numDescriptorRanges; parameters[parameterCount].DescriptorTable.pDescriptorRanges = shaderViewRanges.get(); parameters[parameterCount].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; parameterCount++; } if (numTextureSamplers) { parameters[parameterCount].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameters[parameterCount].DescriptorTable.NumDescriptorRanges = numTextureSamplers; parameters[parameterCount].DescriptorTable.pDescriptorRanges = samplerRanges.get(); parameters[parameterCount].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; parameterCount++; } D3D12_ROOT_SIGNATURE_DESC rootDesc{}; rootDesc.NumParameters = parameterCount; rootDesc.pParameters = parameters; rootDesc.NumStaticSamplers = 0; rootDesc.pStaticSamplers = nullptr; rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; gr_cp rootSigBinary; gr_cp error; // TODO: D3D Static Function HRESULT hr = D3D12SerializeRootSignature(&rootDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, &rootSigBinary, &error); if (!SUCCEEDED(hr)) { SkDebugf("Failed to serialize root signature. Error: %s\n", reinterpret_cast(error->GetBufferPointer())); return nullptr; } gr_cp rootSig; hr = gpu->device()->CreateRootSignature(0, rootSigBinary->GetBufferPointer(), rootSigBinary->GetBufferSize(), IID_PPV_ARGS(&rootSig)); if (!SUCCEEDED(hr)) { SkDebugf("Failed to create root signature.\n"); return nullptr; } return sk_sp(new GrD3DRootSignature(std::move(rootSig), numTextureSamplers, numUAVs)); } GrD3DRootSignature::GrD3DRootSignature(gr_cp rootSig, int numTextureSamplers, int numUAVs) : fRootSignature(std::move(rootSig)) , fNumTextureSamplers(numTextureSamplers) , fNumUAVs(numUAVs) { } bool GrD3DRootSignature::isCompatible(int numTextureSamplers, int numUAVs) const { return fNumTextureSamplers == numTextureSamplers && fNumUAVs == numUAVs; }