You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/DX12/API/DX12Shader.cpp

259 lines
9.6 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "DX12Shader.hpp"
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define DX12SHADER_CPP_SECTION_1 1
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION DX12SHADER_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(DX12Shader_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
#include <d3d11shader.h>
#include <d3dcompiler.h>
#endif
namespace DX12
{
namespace
{
AZ::u32 MakeHashFromDesc(const D3D11_SHADER_DESC& desc11)
{
// Don't hash pointers. Hashing pointers will make the hash inconsistent between multiple app runs. Making it consistent allows the objects to be serialized to disk and reloaded
// on subsequent runs.
D3D11_SHADER_DESC noPointers = desc11;
noPointers.Creator = nullptr;
return DX12::ComputeSmallHash<sizeof(D3D11_SHADER_DESC)>(&noPointers);
}
AZ::u32 MakeHashFromBindings(ReflectedBindings& bindings)
{
const ReflectedBindingRangeList* lists[] =
{
&bindings.m_ConstantBuffers,
&bindings.m_InputResources,
&bindings.m_OutputResources,
&bindings.m_Samplers
};
AZ::Crc32 hash = 0;
for (AZ::u32 i = 0; i < AZ_ARRAY_SIZE(lists); ++i)
{
const ReflectedBindingRangeList& list = *lists[i];
if (list.m_DescriptorCount)
{
hash.Add(&i, sizeof(AZ::u32));
hash.Add(list.m_Ranges.data(), list.m_Ranges.size() * sizeof(ReflectedBindingRange));
}
}
return hash;
}
void AppendResourceToRanges(
ReflectedBindingRangeList& bindings,
AZ::u8 shaderRegister,
AZ::u8 count,
AZ::u8 type,
AZ::u8 dimension,
bool bUsed = true,
bool bShared = false,
bool bMergeable = true)
{
AZ::u32 rangeIdx = 0;
AZ::u32 rangeCount = bindings.m_Ranges.size();
// Attempts to merge a resource into an existing range. We can do this if
// the resource is marked as mergeable, and it's not shared across different
// shader stages.
bool bMerged = false;
if (bMergeable && !bShared)
{
for (; rangeIdx < rangeCount; ++rangeIdx)
{
ReflectedBindingRange& r = bindings.m_Ranges[rangeIdx];
if (r.m_bMergeable || r.m_bShared || (r.m_bUsed != bUsed))
{
continue; // Non-Mergeable
}
// Can we join new range with an existing one?
if (r.m_ShaderRegister + r.m_Count == shaderRegister)
{
#ifdef GFX_DEBUG
for (size_t j = 0; j < count; ++j)
{
r.m_Types[r.m_Count + j] = type;
r.m_Dimensions[r.m_Count + j] = dimension;
}
#endif
r.m_Count += count;
bMerged = true;
break;
}
}
}
if (!bMerged)
{
bindings.m_Ranges.push_back(ReflectedBindingRange(shaderRegister, count, type, dimension, bUsed, bShared, bMergeable));
}
bindings.m_DescriptorCount += count;
}
}
Shader::Shader(Device* device)
: DeviceObject(device)
{}
Shader::~Shader()
{}
Shader* Shader::CreateFromD3D11(Device* device, const D3D12_SHADER_BYTECODE& byteCode)
{
ID3D11ShaderReflection* shaderReflection = NULL;
// Reflect shader internals
if (S_OK != D3DReflect(byteCode.pShaderBytecode, byteCode.BytecodeLength, IID_ID3D11ShaderReflection, (void**)&shaderReflection))
{
DX12_ASSERT(0, "Could not do a shader reflection!");
return NULL;
}
D3D11_SHADER_DESC desc11;
shaderReflection->GetDesc(&desc11);
Shader* result = DX12::PassAddRef(new Shader(device));
result->m_Bytecode = byteCode;
result->m_hash = MakeHashFromDesc(desc11);
for (UINT i = 0; i < desc11.BoundResources; ++i)
{
D3D11_SHADER_INPUT_BIND_DESC bindDesc11;
shaderReflection->GetResourceBindingDesc(i, &bindDesc11);
bool bBindPointUsed = true;
bool bBindingSharable =
bindDesc11.BindPoint == eConstantBufferShaderSlot_PerMaterial ||
bindDesc11.BindPoint == eConstantBufferShaderSlot_PerPass ||
bindDesc11.BindPoint == eConstantBufferShaderSlot_PerView ||
bindDesc11.BindPoint == eConstantBufferShaderSlot_PerFrame;
bool bBindingMergeable = bindDesc11.BindPoint > eConstantBufferShaderSlot_PerInstanceLegacy;
switch (bindDesc11.Type)
{
case D3D10_SIT_CBUFFER:
DX12_ASSERT(bindDesc11.BindCount == 1, "Arrays of ConstantBuffers are not allowed!");
if (bindDesc11.BindCount == 1)
{
ID3D11ShaderReflectionConstantBuffer* constantBuffer = shaderReflection->GetConstantBufferByName(bindDesc11.Name);
D3D11_SHADER_BUFFER_DESC constantBufferDesc;
UINT variableUsedCount = 0;
constantBuffer->GetDesc(&constantBufferDesc);
for (UINT j = 0; j < constantBufferDesc.Variables; j++)
{
ID3D11ShaderReflectionVariable* variable = constantBuffer->GetVariableByIndex(j);
D3D11_SHADER_VARIABLE_DESC variableDesc;
variable->GetDesc(&variableDesc);
variableUsedCount += (variableDesc.uFlags & D3D10_SVF_USED);
}
bBindPointUsed = (variableUsedCount > 0);
}
// We need separate descriptor tables for dynamic CB's
AppendResourceToRanges(
result->m_Bindings.m_ConstantBuffers,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension),
bBindPointUsed,
bBindingSharable,
bBindingMergeable);
break;
// ID3D12Device::CreateGraphicsPipelineState: SRV or UAV root descriptors can only be Raw or Structured buffers.
case D3D10_SIT_TEXTURE:
case D3D10_SIT_TBUFFER:
AppendResourceToRanges(
result->m_Bindings.m_InputResources,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension));
break;
case D3D11_SIT_STRUCTURED:
case D3D11_SIT_BYTEADDRESS:
AppendResourceToRanges(
result->m_Bindings.m_InputResources,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension),
bBindPointUsed);
break;
case D3D11_SIT_UAV_RWTYPED:
AppendResourceToRanges(
result->m_Bindings.m_OutputResources,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension));
break;
case D3D11_SIT_UAV_RWSTRUCTURED:
case D3D11_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
case D3D11_SIT_UAV_RWBYTEADDRESS:
case D3D11_SIT_UAV_APPEND_STRUCTURED:
case D3D11_SIT_UAV_CONSUME_STRUCTURED:
AppendResourceToRanges(result->m_Bindings.m_OutputResources,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension),
bBindPointUsed);
break;
case D3D10_SIT_SAMPLER:
DX12_ASSERT(bindDesc11.BindCount == 1, "Arrays of SamplerStates are not allowed!");
AppendResourceToRanges(
result->m_Bindings.m_Samplers,
bindDesc11.BindPoint,
bindDesc11.BindCount,
static_cast<UINT8>(bindDesc11.Type),
static_cast<UINT8>(bindDesc11.Dimension));
break;
}
}
result->m_BindingHash = MakeHashFromBindings(result->m_Bindings);
return result;
}
}