コード例 #1
0
void SetDescriptorHeaps(ID3D12GraphicsCommandList* cmdList)
{
    ID3D12DescriptorHeap* heaps[] =
    {
        SRVDescriptorHeap.CurrentHeap(),
    };

    cmdList->SetDescriptorHeaps(ArraySize_(heaps), heaps);
}
コード例 #2
0
void PostProcessHelper::Initialize()
{
    // Load the shaders
    std::wstring fullScreenTriPath = SampleFrameworkDir() + L"Shaders\\FullScreenTriangle.hlsl";
    fullScreenTriVS = CompileFromFile(fullScreenTriPath.c_str(), "FullScreenTriangleVS", ShaderType::Vertex);

    {
        D3D12_ROOT_PARAMETER1 rootParameters[NumRootParams] = {};

        rootParameters[RootParam_StandardDescriptors].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
        rootParameters[RootParam_StandardDescriptors].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
        rootParameters[RootParam_StandardDescriptors].DescriptorTable.pDescriptorRanges = DX12::StandardDescriptorRanges();
        rootParameters[RootParam_StandardDescriptors].DescriptorTable.NumDescriptorRanges = DX12::NumStandardDescriptorRanges;

        rootParameters[RootParam_SRVIndices].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
        rootParameters[RootParam_SRVIndices].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
        rootParameters[RootParam_SRVIndices].Descriptor.RegisterSpace = 0;
        rootParameters[RootParam_SRVIndices].Descriptor.ShaderRegister = 0;

        rootParameters[RootParam_AppSettings].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
        rootParameters[RootParam_AppSettings].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
        rootParameters[RootParam_AppSettings].Descriptor.RegisterSpace = 0;
        rootParameters[RootParam_AppSettings].Descriptor.ShaderRegister = AppSettings::CBufferRegister;

        D3D12_STATIC_SAMPLER_DESC staticSamplers[4] = {};
        staticSamplers[0] = DX12::GetStaticSamplerState(SamplerState::Point, 0);
        staticSamplers[1] = DX12::GetStaticSamplerState(SamplerState::LinearClamp, 1);
        staticSamplers[2] = DX12::GetStaticSamplerState(SamplerState::Linear, 2);
        staticSamplers[3] = DX12::GetStaticSamplerState(SamplerState::LinearBorder, 3);

        D3D12_ROOT_SIGNATURE_DESC1 rootSignatureDesc = {};
        rootSignatureDesc.NumParameters = ArraySize_(rootParameters);
        rootSignatureDesc.pParameters = rootParameters;
        rootSignatureDesc.NumStaticSamplers = ArraySize_(staticSamplers);
        rootSignatureDesc.pStaticSamplers = staticSamplers;
        rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;

        DX12::CreateRootSignature(&rootSignature, rootSignatureDesc);
        rootSignature->SetName(L"PostProcessHelper");
    }
}
コード例 #3
0
void Shutdown_Upload()
{
    for(uint64 i = 0; i < ArraySize_(TempFrameBuffers); ++i)
        Release(TempFrameBuffers[i]);

    Release(UploadCmdList);
    Release(UploadBuffer);
    Release(UploadCmdQueue);
    UploadFence.Shutdown();
    for(uint64 i = 0; i < MaxUploadSubmissions; ++i)
        Release(UploadSubmissions[i].CmdAllocator);

    Release(convertCmdAllocator);
    Release(convertCmdList);
    Release(convertCmdQueue);
    Release(convertPSO);
    Release(convertArrayPSO);
    Release(convertRootSignature);
    convertFence.Shutdown();

    Release(readbackCmdAllocator);
    Release(readbackCmdList);
    readbackFence.Shutdown();
}
コード例 #4
0
// Renders all meshes in the model, with shadows
void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera)
{
    PIXEvent event(L"Mesh Rendering");

    // Set states
    float blendFactor[4] = {1, 1, 1, 1};
    context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF);
    context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0);
    context->RSSetState(rasterizerStates.BackFaceCull());

    ID3D11SamplerState* sampStates[] = {
        samplerStates.Anisotropic(),
        evsmSampler,
        samplerStates.LinearClamp(),
        samplerStates.ReversedShadowMapPCF(),
    };

    context->PSSetSamplers(0, ArraySize_(sampStates), sampStates);

    // Set constant buffers
    meshVSConstants.Data.World = Float4x4();
    meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix());
    meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix());
    meshVSConstants.ApplyChanges(context);
    meshVSConstants.SetVS(context, 0);

    meshPSConstants.Data.SunDirectionWS = AppSettings::SunDirection;
    meshPSConstants.Data.SunIlluminance = AppSettings::SunIlluminance();
    meshPSConstants.Data.CosSunAngularRadius = std::cos(DegToRad(AppSettings::SunSize) / 2.0f);
    meshPSConstants.Data.SinSunAngularRadius = std::sin(DegToRad(AppSettings::SunSize) / 2.0f);
    meshPSConstants.Data.CameraPosWS = camera.Position();
    meshPSConstants.ApplyChanges(context);
    meshPSConstants.SetPS(context, 0);

    shadowConstants.Data.PositiveExponent = PositiveExponent;
    shadowConstants.Data.NegativeExponent = NegativeExponent;
    shadowConstants.Data.LightBleedingReduction = LightBleedingReduction;
    shadowConstants.ApplyChanges(context);
    shadowConstants.SetPS(context, 1);

    // Set shaders
    context->DSSetShader(nullptr, nullptr, 0);
    context->HSSetShader(nullptr, nullptr, 0);
    context->GSSetShader(nullptr, nullptr, 0);
    context->VSSetShader(meshVS, nullptr, 0);
    context->PSSetShader(meshPS, nullptr, 0);

    // Draw all meshes
    for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx)
    {
        const Mesh& mesh = sceneModel->Meshes()[meshIdx];

        // Set the vertices and indices
        ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() };
        UINT vertexStrides[1] = { mesh.VertexStride() };
        UINT offsets[1] = { 0 };
        context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets);
        context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0);
        context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

        // Set the input layout
        context->IASetInputLayout(meshInputLayouts[meshIdx]);

        // Draw all parts
        for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx)
        {
            const MeshPart& part = mesh.MeshParts()[partIdx];
            const MeshMaterial& material = sceneModel->Materials()[part.MaterialIdx];

            // Set the textures
            ID3D11ShaderResourceView* psTextures[] =
            {
                material.DiffuseMap,
                material.NormalMap,
                sunVSM.SRView,
            };

            context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures);
            context->DrawIndexed(part.IndexCount, part.IndexStart, 0);
        }
    }

    ID3D11ShaderResourceView* nullSRVs[8] = { NULL };
    context->PSSetShaderResources(0, 8, nullSRVs);
}
コード例 #5
0
ファイル: euler_013.cpp プロジェクト: pnowell/LibPhil
    "16730939319872750275468906903707539413042652315011",
    "94809377245048795150954100921645863754710598436791",
    "78639167021187492431995700641917969777599028300699",
    "15368713711936614952811305876380278410754449733078",
    "40789923115535562561142322423255033685442488917353",
    "44889911501440648020369068063960672322193204149535",
    "41503128880339536053299340368006977710650566631954",
    "81234880673210146739058568557934581403627822703280",
    "82616570773948327592232845941706525094512325230608",
    "22918802058777319719839450180888072429661980811197",
    "77158542502016545090413245809786882778948721859617",
    "72107838435069186155435662884062257473692284509516",
    "20849603980134001723930671666823555245252804609722",
    "53503534226472524250874054075591789781264330331690",
};
static const uint32 kNumbersSize = ArraySize_(kNumbers);
static cpointer kAnswer = "5537376230390876637302048746832985971773659831892672";

// ================================================================================================
// Problem 13
// ================================================================================================
sint32 Problem13() {
    CBigInt sum;
    for(uintn i = 0; i < kNumbersSize; ++i)
        sum += CBigInt(kNumbers[i]);

    // -- iterate over the ten most significant digits
    uintn numdigits = sum.NumDigits();
    Assert_(numdigits >= 10, "Not enough digits : " UintNFmt_, numdigits);
    flagn correct = true;
    for(uintn i = numdigits; i > 0; --i) {
コード例 #6
0
void ConvertAndReadbackTexture(const Texture& texture, DXGI_FORMAT outputFormat, ReadbackBuffer& readbackBuffer)
{
    Assert_(convertCmdList != nullptr);
    Assert_(texture.Valid());
    Assert_(texture.Depth == 1);

    // Create a buffer for the CS to write flattened, converted texture data into
    FormattedBufferInit init;
    init.Format = outputFormat;
    init.NumElements = texture.Width * texture.Height * texture.ArraySize;
    init.CreateUAV = true;

    FormattedBuffer convertBuffer;
    convertBuffer.Initialize(init);

    convertBuffer.Transition(convertCmdList, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);

    // Run the conversion compute shader
    DX12::SetDescriptorHeaps(convertCmdList);
    convertCmdList->SetComputeRootSignature(convertRootSignature);
    convertCmdList->SetPipelineState(texture.ArraySize > 1 ? convertArrayPSO : convertPSO);

    D3D12_CPU_DESCRIPTOR_HANDLE descriptors[2] = { texture.SRV.CPUHandle, convertBuffer.UAV() };
    BindShaderResources(convertCmdList, 0, ArraySize_(descriptors), descriptors, CmdListMode::Compute, ShaderResourceType::SRV_UAV_CBV);

    uint32 dispatchX = DispatchSize(convertTGSize, texture.Width);
    uint32 dispatchY = DispatchSize(convertTGSize, texture.Height);
    uint32 dispatchZ = texture.ArraySize;
    convertCmdList->Dispatch(dispatchX, dispatchY, dispatchZ);

    convertBuffer.Transition(convertCmdList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);

    // Execute the conversion command list and signal a fence
    DXCall(convertCmdList->Close());
    ID3D12CommandList* cmdLists[1] = { convertCmdList };
    convertCmdQueue->ExecuteCommandLists(1, cmdLists);

    convertFence.Signal(convertCmdQueue, 1);

    // Have the readback wait for conversion finish, and then have it copy the data to a readback buffer
    ID3D12CommandQueue* readbackQueue = UploadCmdQueue;
    readbackQueue->Wait(convertFence.D3DFence, 1);

    readbackBuffer.Shutdown();
    readbackBuffer.Initialize(convertBuffer.InternalBuffer.Size);

    readbackCmdList->CopyResource(readbackBuffer.Resource, convertBuffer.InternalBuffer.Resource);

    // Execute the readback command list and signal a fence
    DXCall(readbackCmdList->Close());
    cmdLists[0] = readbackCmdList;
    readbackQueue->ExecuteCommandLists(1, cmdLists);

    readbackFence.Signal(readbackQueue, 1);

    readbackFence.Wait(1);

    // Clean up
    convertFence.Clear(0);
    readbackFence.Clear(0);

    DXCall(convertCmdAllocator->Reset());
    DXCall(convertCmdList->Reset(convertCmdAllocator, nullptr));

    DXCall(readbackCmdAllocator->Reset());
    DXCall(readbackCmdList->Reset(readbackCmdAllocator, nullptr));

    convertBuffer.Shutdown();
}
コード例 #7
0
void Initialize_Upload()
{
    for(uint64 i = 0; i < MaxUploadSubmissions; ++i)
        DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&UploadSubmissions[i].CmdAllocator)));

    DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, UploadSubmissions[0].CmdAllocator, nullptr, IID_PPV_ARGS(&UploadCmdList)));
    DXCall(UploadCmdList->Close());

    D3D12_COMMAND_QUEUE_DESC queueDesc = { };
    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
    DXCall(Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&UploadCmdQueue)));

    UploadFence.Init(0);

    D3D12_RESOURCE_DESC resourceDesc = { };
    resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    resourceDesc.Width = uint32(UploadBufferSize);
    resourceDesc.Height = 1;
    resourceDesc.DepthOrArraySize = 1;
    resourceDesc.MipLevels = 1;
    resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
    resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
    resourceDesc.SampleDesc.Count = 1;
    resourceDesc.SampleDesc.Quality = 0;
    resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    resourceDesc.Alignment = 0;

    DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc,
                                           D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&UploadBuffer)));

    D3D12_RANGE readRange = { };
    DXCall(UploadBuffer->Map(0, &readRange, reinterpret_cast<void**>(&UploadBufferCPUAddr)));

    // Temporary buffer memory that swaps every frame
    resourceDesc.Width = uint32(TempBufferSize);

    for(uint64 i = 0; i < RenderLatency; ++i)
    {
        DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc,
                                               D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&TempFrameBuffers[i])));

        DXCall(TempFrameBuffers[i]->Map(0, &readRange, reinterpret_cast<void**>(&TempFrameCPUMem[i])));
        TempFrameGPUMem[i] = TempFrameBuffers[i]->GetGPUVirtualAddress();
    }

    // Texture conversion resources
    DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&convertCmdAllocator)));
    DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, convertCmdAllocator, nullptr, IID_PPV_ARGS(&convertCmdList)));
    DXCall(convertCmdList->Close());
    DXCall(convertCmdList->Reset(convertCmdAllocator, nullptr));

    D3D12_COMMAND_QUEUE_DESC convertQueueDesc = {};
    convertQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    convertQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;
    DXCall(Device->CreateCommandQueue(&convertQueueDesc, IID_PPV_ARGS(&convertCmdQueue)));

    CompileOptions opts;
    opts.Add("TGSize_", convertTGSize);
    const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl";
    convertCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureCS", ShaderType::Compute, ShaderProfile::SM51, opts);
    convertArrayCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureArrayCS", ShaderType::Compute, ShaderProfile::SM51, opts);

    {
        D3D12_DESCRIPTOR_RANGE ranges[2] = {};
        ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
        ranges[0].NumDescriptors = 1;
        ranges[0].BaseShaderRegister = 0;
        ranges[0].RegisterSpace = 0;
        ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

        ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
        ranges[1].NumDescriptors = 1;
        ranges[1].BaseShaderRegister = 0;
        ranges[1].RegisterSpace = 0;
        ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

        D3D12_ROOT_PARAMETER rootParameters[1] = {};
        rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
        rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
        rootParameters[0].DescriptorTable.pDescriptorRanges = ranges;
        rootParameters[0].DescriptorTable.NumDescriptorRanges = ArraySize_(ranges);

        D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
        rootSignatureDesc.NumParameters = ArraySize_(rootParameters);
        rootSignatureDesc.pParameters = rootParameters;
        rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;

        DX12::CreateRootSignature(&convertRootSignature, rootSignatureDesc);
    }

    {
        D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = { };
        psoDesc.CS = convertCS.ByteCode();
        psoDesc.pRootSignature = convertRootSignature;
        psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
        Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertPSO));

        psoDesc.CS = convertArrayCS.ByteCode();
        Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertArrayPSO));
    }

    convertFence.Init(0);

    // Readback resources
    DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&readbackCmdAllocator)));
    DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, readbackCmdAllocator, nullptr, IID_PPV_ARGS(&readbackCmdList)));
    DXCall(readbackCmdList->Close());
    DXCall(readbackCmdList->Reset(readbackCmdAllocator, nullptr));

    readbackFence.Init(0);
}
コード例 #8
0
D3D12_STATIC_SAMPLER_DESC GetStaticSamplerState(SamplerState samplerState, uint32 shaderRegister,
                                                uint32 registerSpace, D3D12_SHADER_VISIBILITY visibility)
{
    Assert_(uint64(samplerState) < ArraySize_(SamplerStateDescs));
    return ConvertToStaticSampler(SamplerStateDescs[uint64(samplerState)], shaderRegister, registerSpace, visibility);
}
コード例 #9
0
D3D12_SAMPLER_DESC GetSamplerState(SamplerState samplerState)
{
    Assert_(uint64(samplerState) < ArraySize_(SamplerStateDescs));
    return SamplerStateDescs[uint64(samplerState)];
}
コード例 #10
0
D3D12_DEPTH_STENCIL_DESC GetDepthState(DepthState depthState)
{
    Assert_(uint64(depthState) < ArraySize_(DepthStateDescs));
    return DepthStateDescs[uint64(depthState)];
}
コード例 #11
0
D3D12_RASTERIZER_DESC GetRasterizerState(RasterizerState rasterizerState)
{
    Assert_(uint64(rasterizerState) < ArraySize_(RasterizerStateDescs));
    return RasterizerStateDescs[uint64(rasterizerState)];
}
コード例 #12
0
D3D12_BLEND_DESC GetBlendState(BlendState blendState)
{
    Assert_(uint64(blendState) < ArraySize_(BlendStateDescs));
    return BlendStateDescs[uint64(blendState)];
}
コード例 #13
0
namespace DX12
{

uint32 RTVDescriptorSize = 0;
uint32 SRVDescriptorSize = 0;
uint32 UAVDescriptorSize = 0;
uint32 CBVDescriptorSize = 0;
uint32 DSVDescriptorSize = 0;

DescriptorHeap RTVDescriptorHeap;
DescriptorHeap SRVDescriptorHeap;
DescriptorHeap DSVDescriptorHeap;
DescriptorHeap UAVDescriptorHeap;

uint32 NullTexture2DSRV = uint32(-1);

static const uint64 NumBlendStates = uint64(BlendState::NumValues);
static const uint64 NumRasterizerStates = uint64(RasterizerState::NumValues);
static const uint64 NumDepthStates = uint64(DepthState::NumValues);
static const uint64 NumSamplerStates = uint64(SamplerState::NumValues);

static D3D12_BLEND_DESC BlendStateDescs[NumBlendStates] = { };
static D3D12_RASTERIZER_DESC RasterizerStateDescs[NumRasterizerStates] = { };
static D3D12_DEPTH_STENCIL_DESC DepthStateDescs[NumBlendStates] = { };
static D3D12_SAMPLER_DESC SamplerStateDescs[NumSamplerStates] = { };

static D3D12_DESCRIPTOR_RANGE1 StandardDescriptorRangeDescs[NumStandardDescriptorRanges] = { };

void Initialize_Helpers()
{
    RTVDescriptorHeap.Init(256, 0, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, false);
    SRVDescriptorHeap.Init(1024, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, true);
    DSVDescriptorHeap.Init(256, 0, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, false);
    UAVDescriptorHeap.Init(256, 0, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, false);

    RTVDescriptorSize = RTVDescriptorHeap.DescriptorSize;
    SRVDescriptorSize = UAVDescriptorSize = CBVDescriptorSize = SRVDescriptorHeap.DescriptorSize;
    DSVDescriptorSize = DSVDescriptorHeap.DescriptorSize;

    // Standard descriptor ranges for binding to the arrays in DescriptorTables.hlsl
    InsertStandardDescriptorRanges(StandardDescriptorRangeDescs);

    // Blend state initialization
    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::Disabled)];
        blendDesc.RenderTarget[0].BlendEnable = false;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::Additive)];
        blendDesc.RenderTarget[0].BlendEnable = true;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::AlphaBlend)];
        blendDesc.RenderTarget[0].BlendEnable = true;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::PreMultiplied)];
        blendDesc.RenderTarget[0].BlendEnable = false;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::NoColorWrites)];
        blendDesc.RenderTarget[0].BlendEnable = false;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = 0;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    {
        D3D12_BLEND_DESC& blendDesc = BlendStateDescs[uint64(BlendState::PreMultipliedRGB)];
        blendDesc.RenderTarget[0].BlendEnable = true;
        blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
        blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC1_COLOR;
        blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
        blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
        blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
    }

    // Rasterizer state initialization
    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::NoCull)];
        rastDesc.CullMode = D3D12_CULL_MODE_NONE;
        rastDesc.DepthClipEnable = true;
        rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
        rastDesc.MultisampleEnable = true;
    }

    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::FrontFaceCull)];
        rastDesc.CullMode = D3D12_CULL_MODE_FRONT;
        rastDesc.DepthClipEnable = true;
        rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
        rastDesc.MultisampleEnable = true;
    }

    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::BackFaceCull)];
        rastDesc.CullMode = D3D12_CULL_MODE_BACK;
        rastDesc.DepthClipEnable = true;
        rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
        rastDesc.MultisampleEnable = true;
    }

    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::BackFaceCullNoZClip)];
        rastDesc.CullMode = D3D12_CULL_MODE_BACK;
        rastDesc.DepthClipEnable = false;
        rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
        rastDesc.MultisampleEnable = true;
    }

    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::NoCullNoMS)];
        rastDesc.CullMode = D3D12_CULL_MODE_NONE;
        rastDesc.DepthClipEnable = true;
        rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
        rastDesc.MultisampleEnable = false;
    }

    {
        D3D12_RASTERIZER_DESC& rastDesc = RasterizerStateDescs[uint64(RasterizerState::Wireframe)];
        rastDesc.CullMode = D3D12_CULL_MODE_NONE;
        rastDesc.DepthClipEnable = true;
        rastDesc.FillMode = D3D12_FILL_MODE_WIREFRAME;
        rastDesc.MultisampleEnable = true;
    }

    // Depth state initialization
    {
        D3D12_DEPTH_STENCIL_DESC& dsDesc = DepthStateDescs[uint64(DepthState::Disabled)];
        dsDesc.DepthEnable = false;
        dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
        dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
    }

    {
        D3D12_DEPTH_STENCIL_DESC& dsDesc = DepthStateDescs[uint64(DepthState::Enabled)];
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
        dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
    }

    {
        D3D12_DEPTH_STENCIL_DESC& dsDesc = DepthStateDescs[uint64(DepthState::Reversed)];
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
        dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
    }

    {
        D3D12_DEPTH_STENCIL_DESC& dsDesc = DepthStateDescs[uint64(DepthState::WritesEnabled)];
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
        dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
    }

    {
        D3D12_DEPTH_STENCIL_DESC& dsDesc = DepthStateDescs[uint64(DepthState::ReversedWritesEnabled)];
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
        dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
    }

    // Sampler state initialization
    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::Linear)];

        sampDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::LinearClamp)];

        sampDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::LinearBorder)];

        sampDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::Point)];

        sampDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::Anisotropic)];

        sampDesc.Filter = D3D12_FILTER_ANISOTROPIC;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 16;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::ShadowMap)];

        sampDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::ShadowMapPCF)];

        sampDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::ReversedShadowMap)];

        sampDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SAMPLER_DESC& sampDesc = SamplerStateDescs[uint64(SamplerState::ReversedShadowMapPCF)];

        sampDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
        sampDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampDesc.MipLODBias = 0.0f;
        sampDesc.MaxAnisotropy = 1;
        sampDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
        sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0;
        sampDesc.MinLOD = 0;
        sampDesc.MaxLOD = D3D12_FLOAT32_MAX;
    }

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = { };
        srvDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srvDesc.Texture2D.MipLevels = 1;
        srvDesc.Texture2D.MostDetailedMip = 0;
        srvDesc.Texture2D.PlaneSlice = 0;
        srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;

        PersistentDescriptorAlloc srvAlloc = SRVDescriptorHeap.AllocatePersistent();
        for(uint32 i = 0; i < SRVDescriptorHeap.NumHeaps; ++i)
            Device->CreateShaderResourceView(nullptr, &srvDesc, srvAlloc.Handles[i]);
        NullTexture2DSRV = srvAlloc.Index;
    }
}

void Shutdown_Helpers()
{
    SRVDescriptorHeap.FreePersistent(NullTexture2DSRV);

    RTVDescriptorHeap.Shutdown();
    SRVDescriptorHeap.Shutdown();
    DSVDescriptorHeap.Shutdown();
    UAVDescriptorHeap.Shutdown();
}

void EndFrame_Helpers()
{
    RTVDescriptorHeap.EndFrame();
    SRVDescriptorHeap.EndFrame();
    DSVDescriptorHeap.EndFrame();
    UAVDescriptorHeap.EndFrame();
}

void TransitionResource(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after, uint32 subResource)
{
    D3D12_RESOURCE_BARRIER barrier = { };
    barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    barrier.Transition.pResource = resource;
    barrier.Transition.StateBefore = before;
    barrier.Transition.StateAfter = after;
    barrier.Transition.Subresource = subResource;
    cmdList->ResourceBarrier(1, &barrier);
}

uint64 GetResourceSize(const D3D12_RESOURCE_DESC& desc, uint32 firstSubResource, uint32 numSubResources)
{
    uint64 size = 0;
    Device->GetCopyableFootprints(&desc, firstSubResource, numSubResources, 0, nullptr, nullptr, nullptr, &size);
    return size;
}

uint64 GetResourceSize(ID3D12Resource* resource, uint32 firstSubResource, uint32 numSubResources)
{
    D3D12_RESOURCE_DESC desc = resource->GetDesc();

    return GetResourceSize(desc, firstSubResource, numSubResources);
}

const D3D12_HEAP_PROPERTIES* GetDefaultHeapProps()
{
    static D3D12_HEAP_PROPERTIES heapProps =
    {
        D3D12_HEAP_TYPE_DEFAULT,
        D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
        D3D12_MEMORY_POOL_UNKNOWN,
        0,
        0,
    };

    return &heapProps;
}

const D3D12_HEAP_PROPERTIES* GetUploadHeapProps()
{
    static D3D12_HEAP_PROPERTIES heapProps =
    {
        D3D12_HEAP_TYPE_UPLOAD,
        D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
        D3D12_MEMORY_POOL_UNKNOWN,
        0,
        0,
    };

    return &heapProps;
}

const D3D12_HEAP_PROPERTIES* GetReadbackHeapProps()
{
    static D3D12_HEAP_PROPERTIES heapProps =
    {
        D3D12_HEAP_TYPE_READBACK,
        D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
        D3D12_MEMORY_POOL_UNKNOWN,
        0,
        0,
    };

    return &heapProps;
}

D3D12_BLEND_DESC GetBlendState(BlendState blendState)
{
    Assert_(uint64(blendState) < ArraySize_(BlendStateDescs));
    return BlendStateDescs[uint64(blendState)];
}

D3D12_RASTERIZER_DESC GetRasterizerState(RasterizerState rasterizerState)
{
    Assert_(uint64(rasterizerState) < ArraySize_(RasterizerStateDescs));
    return RasterizerStateDescs[uint64(rasterizerState)];
}

D3D12_DEPTH_STENCIL_DESC GetDepthState(DepthState depthState)
{
    Assert_(uint64(depthState) < ArraySize_(DepthStateDescs));
    return DepthStateDescs[uint64(depthState)];
}

D3D12_SAMPLER_DESC GetSamplerState(SamplerState samplerState)
{
    Assert_(uint64(samplerState) < ArraySize_(SamplerStateDescs));
    return SamplerStateDescs[uint64(samplerState)];
}

D3D12_STATIC_SAMPLER_DESC GetStaticSamplerState(SamplerState samplerState, uint32 shaderRegister,
                                                uint32 registerSpace, D3D12_SHADER_VISIBILITY visibility)
{
    Assert_(uint64(samplerState) < ArraySize_(SamplerStateDescs));
    return ConvertToStaticSampler(SamplerStateDescs[uint64(samplerState)], shaderRegister, registerSpace, visibility);
}

D3D12_STATIC_SAMPLER_DESC ConvertToStaticSampler(const D3D12_SAMPLER_DESC& samplerDesc, uint32 shaderRegister,
                                                 uint32 registerSpace, D3D12_SHADER_VISIBILITY visibility)
{
    D3D12_STATIC_SAMPLER_DESC staticDesc = { };
    staticDesc.Filter = samplerDesc.Filter;
    staticDesc.AddressU = samplerDesc.AddressU;
    staticDesc.AddressV = samplerDesc.AddressV;
    staticDesc.AddressW = samplerDesc.AddressW;
    staticDesc.MipLODBias = samplerDesc.MipLODBias;
    staticDesc.MaxAnisotropy = samplerDesc.MaxAnisotropy;
    staticDesc.ComparisonFunc = samplerDesc.ComparisonFunc;
    staticDesc.MinLOD = samplerDesc.MinLOD;
    staticDesc.MaxLOD = samplerDesc.MaxLOD;
    staticDesc.ShaderRegister = shaderRegister;
    staticDesc.RegisterSpace = registerSpace;
    staticDesc.ShaderVisibility = visibility;

    Float4 borderColor = Float4(samplerDesc.BorderColor[0], samplerDesc.BorderColor[1], samplerDesc.BorderColor[2], samplerDesc.BorderColor[3]);
    if(borderColor == Float4(1.0f, 1.0f, 1.0f, 1.0f))
        staticDesc.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
    else if(borderColor == Float4(0.0f, 0.0f, 0.0f, 1.0f))
        staticDesc.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
    else
        staticDesc.BorderColor =  D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;

    return staticDesc;
}

void SetViewport(ID3D12GraphicsCommandList* cmdList, uint64 width, uint64 height, float zMin, float zMax)
{
    D3D12_VIEWPORT viewport = { };
    viewport.Width = float(width);
    viewport.Height = float(height);
    viewport.MinDepth = zMin;
    viewport.MaxDepth = zMax;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;

    D3D12_RECT scissorRect = { };
    scissorRect.left = 0;
    scissorRect.top = 0;
    scissorRect.right = uint32(width);
    scissorRect.bottom = uint32(height);

    cmdList->RSSetViewports(1, &viewport);
    cmdList->RSSetScissorRects(1, &scissorRect);
}

void CreateRootSignature(ID3D12RootSignature** rootSignature, const D3D12_ROOT_SIGNATURE_DESC1& desc)
{
    D3D12_VERSIONED_ROOT_SIGNATURE_DESC versionedDesc = { };
    versionedDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
    versionedDesc.Desc_1_1 = desc;

    ID3DBlobPtr signature;
    ID3DBlobPtr error;
    HRESULT hr = D3D12SerializeVersionedRootSignature(&versionedDesc, &signature, &error);
    if(FAILED(hr))
    {
        const char* errString = error ? reinterpret_cast<const char*>(error->GetBufferPointer()) : "";

        #if UseAsserts_
            AssertMsg_(false, "Failed to create root signature: %s", errString);
        #else
            throw DXException(hr, MakeString(L"Failed to create root signature: %s", errString).c_str());
        #endif
    }

    DXCall(DX12::Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature)));
}

uint32 DispatchSize(uint64 numElements, uint64 groupSize)
{
    Assert_(groupSize > 0);
    return uint32((numElements + (groupSize - 1)) / groupSize);
}

static const uint64 MaxBindCount = 16;
static const uint32 DescriptorCopyRanges[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
StaticAssert_(ArraySize_(DescriptorCopyRanges) == MaxBindCount);

void SetDescriptorHeaps(ID3D12GraphicsCommandList* cmdList)
{
    ID3D12DescriptorHeap* heaps[] =
    {
        SRVDescriptorHeap.CurrentHeap(),
    };

    cmdList->SetDescriptorHeaps(ArraySize_(heaps), heaps);
}

D3D12_GPU_DESCRIPTOR_HANDLE TempDescriptorTable(const D3D12_CPU_DESCRIPTOR_HANDLE* handles, uint64 count)
{
    Assert_(count <= MaxBindCount);
    Assert_(count > 0);

    TempDescriptorAlloc tempAlloc = SRVDescriptorHeap.AllocateTemporary(uint32(count));

    uint32 destRanges[1] = { uint32(count) };
    Device->CopyDescriptors(1, &tempAlloc.StartCPUHandle, destRanges, uint32(count), handles, DescriptorCopyRanges, SRVDescriptorHeap.HeapType);

    return tempAlloc.StartGPUHandle;
}

void BindTempDescriptorTable(ID3D12GraphicsCommandList* cmdList, const D3D12_CPU_DESCRIPTOR_HANDLE* handles,
                             uint64 count, uint32 rootParameter, CmdListMode cmdListMode)
{
    D3D12_GPU_DESCRIPTOR_HANDLE tempTable = TempDescriptorTable(handles, count);

    if(cmdListMode == CmdListMode::Graphics)
        cmdList->SetGraphicsRootDescriptorTable(rootParameter, tempTable);
    else
        cmdList->SetComputeRootDescriptorTable(rootParameter, tempTable);
}

TempBuffer TempConstantBuffer(uint64 cbSize, bool makeDescriptor)
{
    Assert_(cbSize > 0);
    MapResult tempMem = DX12::AcquireTempBufferMem(cbSize, ConstantBufferAlignment);
    TempBuffer tempBuffer;
    tempBuffer.CPUAddress = tempMem.CPUAddress;
    tempBuffer.GPUAddress = tempMem.GPUAddress;
    if(makeDescriptor)
    {
        TempDescriptorAlloc cbvAlloc = SRVDescriptorHeap.AllocateTemporary(1);
        D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = { };
        cbvDesc.BufferLocation = tempMem.GPUAddress;
        cbvDesc.SizeInBytes = uint32(AlignTo(cbSize, ConstantBufferAlignment));
        DX12::Device->CreateConstantBufferView(&cbvDesc, cbvAlloc.StartCPUHandle);
        tempBuffer.DescriptorIndex = cbvAlloc.StartIndex;
    }

    return tempBuffer;
}

void BindTempConstantBuffer(ID3D12GraphicsCommandList* cmdList, const void* cbData, uint64 cbSize, uint32 rootParameter, CmdListMode cmdListMode)
{
    TempBuffer tempBuffer = TempConstantBuffer(cbSize, false);
    memcpy(tempBuffer.CPUAddress, cbData, cbSize);

    if(cmdListMode == CmdListMode::Graphics)
        cmdList->SetGraphicsRootConstantBufferView(rootParameter, tempBuffer.GPUAddress);
    else
        cmdList->SetComputeRootConstantBufferView(rootParameter, tempBuffer.GPUAddress);
}

TempBuffer TempStructuredBuffer(uint64 numElements, uint64 stride, bool makeDescriptor)
{
    Assert_(numElements > 0);
    Assert_(stride > 0);
    Assert_(stride % 4 == 0);

    MapResult tempMem = DX12::AcquireTempBufferMem(numElements * stride, stride);
    Assert_(tempMem.ResourceOffset % stride == 0);

    TempBuffer result;
    result.CPUAddress = tempMem.CPUAddress;
    result.GPUAddress = tempMem.GPUAddress;

    if(makeDescriptor)
    {
        TempDescriptorAlloc srvAlloc = SRVDescriptorHeap.AllocateTemporary(1);

        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
        srvDesc.Format = DXGI_FORMAT_UNKNOWN;
        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srvDesc.Buffer.FirstElement = uint32(tempMem.ResourceOffset / stride);
        srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
        srvDesc.Buffer.NumElements = uint32(numElements);
        srvDesc.Buffer.StructureByteStride = uint32(stride);
        DX12::Device->CreateShaderResourceView(tempMem.Resource, &srvDesc, srvAlloc.StartCPUHandle);

        result.DescriptorIndex = srvAlloc.StartIndex;
    }

    return result;
}

TempBuffer TempFormattedBuffer(uint64 numElements, DXGI_FORMAT format, bool makeDescriptor)
{
    Assert_(format != DXGI_FORMAT_UNKNOWN);
    Assert_(numElements > 0);
    uint64 stride = DirectX::BitsPerPixel(format) / 8;

    MapResult tempMem = DX12::AcquireTempBufferMem(numElements * stride, stride);
    Assert_(tempMem.ResourceOffset % stride == 0);

    TempBuffer result;
    result.CPUAddress = tempMem.CPUAddress;
    result.GPUAddress = tempMem.GPUAddress;

    if(makeDescriptor)
    {
        TempDescriptorAlloc srvAlloc = SRVDescriptorHeap.AllocateTemporary(1);

        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = { };
        srvDesc.Format = format;
        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srvDesc.Buffer.FirstElement = uint32(tempMem.ResourceOffset / stride);
        srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
        srvDesc.Buffer.NumElements = uint32(numElements);
        DX12::Device->CreateShaderResourceView(tempMem.Resource, &srvDesc, srvAlloc.StartCPUHandle);

        result.DescriptorIndex = srvAlloc.StartIndex;
    }

    return result;
}

TempBuffer TempRawBuffer(uint64 numElements, bool makeDescriptor)
{
    Assert_(numElements > 0);
    const uint64 stride = 4;

    MapResult tempMem = DX12::AcquireTempBufferMem(numElements * stride, stride);
    Assert_(tempMem.ResourceOffset % stride == 0);

    TempBuffer result;
    result.CPUAddress = tempMem.CPUAddress;

    if(makeDescriptor)
    {
        TempDescriptorAlloc srvAlloc = SRVDescriptorHeap.AllocateTemporary(1);

        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = { };
        srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srvDesc.Buffer.FirstElement = uint32(tempMem.ResourceOffset / stride);
        srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
        srvDesc.Buffer.NumElements = uint32(numElements);
        DX12::Device->CreateShaderResourceView(tempMem.Resource, &srvDesc, srvAlloc.StartCPUHandle);

        result.DescriptorIndex = srvAlloc.StartIndex;
    }

    return result;
}

const D3D12_DESCRIPTOR_RANGE1* StandardDescriptorRanges()
{
    Assert_(SRVDescriptorSize != 0);
    return StandardDescriptorRangeDescs;
}

void InsertStandardDescriptorRanges(D3D12_DESCRIPTOR_RANGE1* ranges)
{
    uint32 userStart = NumStandardDescriptorRanges - NumUserDescriptorRanges;
    for(uint32 i = 0; i < NumStandardDescriptorRanges; ++i)
    {
        StandardDescriptorRangeDescs[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
        StandardDescriptorRangeDescs[i].NumDescriptors = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
        StandardDescriptorRangeDescs[i].BaseShaderRegister = 0;
        StandardDescriptorRangeDescs[i].RegisterSpace = i;
        StandardDescriptorRangeDescs[i].OffsetInDescriptorsFromTableStart = 0;
        StandardDescriptorRangeDescs[i].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE;
        if(i >= userStart)
            StandardDescriptorRangeDescs[i].RegisterSpace = (i - userStart) + 100;
    }
}

void BindAsDescriptorTable(ID3D12GraphicsCommandList* cmdList, uint32 descriptorIdx, uint32 rootParameter, CmdListMode cmdListMode)
{
    Assert_(descriptorIdx != uint32(-1));
    D3D12_GPU_DESCRIPTOR_HANDLE handle = SRVDescriptorHeap.GPUHandleFromIndex(descriptorIdx);
    if(cmdListMode == CmdListMode::Compute)
        cmdList->SetComputeRootDescriptorTable(rootParameter, handle);
    else
        cmdList->SetGraphicsRootDescriptorTable(rootParameter, handle);
}

void BindStandardDescriptorTable(ID3D12GraphicsCommandList* cmdList, uint32 rootParameter, CmdListMode cmdListMode)
{
    D3D12_GPU_DESCRIPTOR_HANDLE handle = SRVDescriptorHeap.GPUStart[SRVDescriptorHeap.HeapIndex];
    if(cmdListMode == CmdListMode::Compute)
        cmdList->SetComputeRootDescriptorTable(rootParameter, handle);
    else
        cmdList->SetGraphicsRootDescriptorTable(rootParameter, handle);
}

} // namespace DX12
コード例 #14
0
namespace SampleFramework12
{

static const char* TypeStrings[] = { "vertex", "hull", "domain", "geometry", "pixel", "compute" };
StaticAssert_(ArraySize_(TypeStrings) == uint64(ShaderType::NumTypes));

static const uint64 TotalNumProfiles = uint64(ShaderType::NumTypes) * uint64(ShaderProfile::NumProfiles);
static const char* ProfileStrings[] =
{
    "vs_5_0", "hs_5_0", "ds_5_0", "gs_5_0", "ps_5_0", "cs_5_0",
    "vs_5_1", "hs_5_1", "ds_5_1", "gs_5_1", "ps_5_1", "cs_5_1",
};

StaticAssert_(ArraySize_(ProfileStrings) == TotalNumProfiles);

static string GetExpandedShaderCode(const wchar* path, GrowableList<wstring>& filePaths)
{
    for(uint64 i = 0; i < filePaths.Count(); ++i)
        if(filePaths[i] == path)
            return string();

    filePaths.Add(path);

    string fileContents = ReadFileAsString(path);

    // Look for includes
    size_t lineStart = 0;
    while(true)
    {
        size_t lineEnd = fileContents.find('\n', lineStart);
        size_t lineLength = 0;
        if(lineEnd == string::npos)
            lineLength = string::npos;
        else
            lineLength = lineEnd - lineStart;

        string line = fileContents.substr(lineStart, lineLength);
        if(line.find("#include") == 0)
        {
            wstring fullIncludePath;
            size_t startQuote = line.find('\"');
            if(startQuote != -1)
            {
                size_t endQuote = line.find('\"', startQuote + 1);
                string includePath = line.substr(startQuote + 1, endQuote - startQuote - 1);
                fullIncludePath = AnsiToWString(includePath.c_str());
            }
            else
            {
                startQuote = line.find('<');
                if(startQuote == -1)
                    throw Exception(L"Malformed include statement: \"" + AnsiToWString(line.c_str()) + L"\" in file " + path);
                size_t endQuote = line.find('>', startQuote + 1);
                string includePath = line.substr(startQuote + 1, endQuote - startQuote - 1);
                fullIncludePath = SampleFrameworkDir() + L"Shaders\\" + AnsiToWString(includePath.c_str());
            }

            if(FileExists(fullIncludePath.c_str()) == false)
                throw Exception(L"Couldn't find #included file \"" + fullIncludePath + L"\" in file " + path);

            string includeCode = GetExpandedShaderCode(fullIncludePath.c_str(), filePaths);
            fileContents.insert(lineEnd + 1, includeCode);
            lineEnd += includeCode.length();
        }

        if(lineEnd == string::npos)
            break;

        lineStart = lineEnd + 1;
    }

    return fileContents;
}

static const wstring baseCacheDir = L"ShaderCache\\";

#if _DEBUG
    static const wstring cacheSubDir = L"Debug\\";
#else
    static const std::wstring cacheSubDir = L"Release\\";
#endif

static const wstring cacheDir = baseCacheDir + cacheSubDir;

static string MakeDefinesString(const D3D_SHADER_MACRO* defines)
{
    string definesString;
    while(defines && defines->Name != nullptr && defines != nullptr)
    {
        if(definesString.length() > 0)
            definesString += "|";
        definesString += defines->Name;
        definesString += "=";
        definesString += defines->Definition;
        ++defines;
    }

    return definesString;
}

static wstring MakeShaderCacheName(const std::string& shaderCode, const char* functionName,
                                   const char* profile, const D3D_SHADER_MACRO* defines)
{
    string hashString = shaderCode;
    hashString += "\n";
    hashString += functionName;
    hashString += "\n";
    hashString += profile;
    hashString += "\n";

    hashString += MakeDefinesString(defines);

    Hash codeHash = GenerateHash(hashString.data(), int(hashString.length()), 0);

    return cacheDir + codeHash.ToString() + L".cache";
}

class FrameworkInclude : public ID3DInclude
{
    HRESULT Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) override
    {
        std::wstring filePath;
        if(IncludeType == D3D_INCLUDE_LOCAL)
            filePath = AnsiToWString(pFileName);
        else if(IncludeType == D3D_INCLUDE_SYSTEM)
            filePath = SampleFrameworkDir() + L"Shaders\\" + AnsiToWString(pFileName);
        else
            return E_FAIL;

        if(FileExists(filePath.c_str()) == false)
            return E_FAIL;
        File file(filePath.c_str(), FileOpenMode::Read);
        *pBytes = UINT(file.Size());
        uint8* data = reinterpret_cast<uint8*>(std::malloc(*pBytes));
        file.Read(*pBytes, data);
        *ppData = data;
        return S_OK;
    }

    HRESULT Close(LPCVOID pData) override
    {
        std::free(const_cast<void*>(pData));
        return S_OK;
    }
};

static ID3DBlob* CompileShader(const wchar* path, const char* functionName, ShaderType type, ShaderProfile profile,
                              const D3D_SHADER_MACRO* defines, bool forceOptimization, GrowableList<wstring>& filePaths)
{
    if(FileExists(path) == false)
    {
        Assert_(false);
        throw Exception(L"Shader file " + std::wstring(path) + L" does not exist");
    }

    uint64 profileIdx = uint64(profile) * uint64(ShaderType::NumTypes) + uint64(type);
    Assert_(profileIdx < TotalNumProfiles);
    const char* profileString = ProfileStrings[profileIdx];

    // Make a hash off the expanded shader code
    string shaderCode = GetExpandedShaderCode(path, filePaths);
    wstring cacheName = MakeShaderCacheName(shaderCode, functionName, profileString, defines);

    if(FileExists(cacheName.c_str()))
    {
        File cacheFile(cacheName.c_str(), FileOpenMode::Read);

        const uint64 shaderSize = cacheFile.Size();
        Array<uint8> compressedShader;
        compressedShader.Init(shaderSize);
        cacheFile.Read(shaderSize, compressedShader.Data());

        ID3DBlob* decompressedShader[1] = { nullptr };
        uint32 indices[1] = { 0 };
        DXCall(D3DDecompressShaders(compressedShader.Data(), shaderSize, 1, 0,
                                    indices, 0, decompressedShader, nullptr));

        return decompressedShader[0];
    }

    WriteLog("Compiling %s shader %s_%s %s\n", TypeStrings[uint64(type)],
                WStringToAnsi(GetFileName(path).c_str()).c_str(),
                functionName, MakeDefinesString(defines).c_str());

    // Loop until we succeed, or an exception is thrown
    while(true)
    {
        UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS;
        #ifdef _DEBUG
            flags |= D3DCOMPILE_DEBUG;
            // This is causing some shader bugs
            /*if(forceOptimization == false)
                flags |= D3DCOMPILE_SKIP_OPTIMIZATION;*/
        #endif

        ID3DBlob* compiledShader;
        ID3DBlobPtr errorMessages;
        FrameworkInclude include;
        HRESULT hr = D3DCompileFromFile(path, defines, &include, functionName,
                                        profileString, flags, 0, &compiledShader, &errorMessages);

        if(FAILED(hr))
        {
            if(errorMessages)
            {
                wchar message[1024] = { 0 };
                char* blobdata = reinterpret_cast<char*>(errorMessages->GetBufferPointer());

                MultiByteToWideChar(CP_ACP, 0, blobdata, static_cast<int>(errorMessages->GetBufferSize()), message, 1024);
                std::wstring fullMessage = L"Error compiling shader file \"";
                fullMessage += path;
                fullMessage += L"\" - ";
                fullMessage += message;

                // Pop up a message box allowing user to retry compilation
                int retVal = MessageBoxW(nullptr, fullMessage.c_str(), L"Shader Compilation Error", MB_RETRYCANCEL);
                if(retVal != IDRETRY)
                    throw DXException(hr, fullMessage.c_str());
            }
            else
            {
                Assert_(false);
                throw DXException(hr);
            }
        }
        else
        {
            // Compress the shader
            D3D_SHADER_DATA shaderData;
            shaderData.pBytecode = compiledShader->GetBufferPointer();
            shaderData.BytecodeLength = compiledShader->GetBufferSize();
            ID3DBlobPtr compressedShader;
            DXCall(D3DCompressShaders(1, &shaderData, D3D_COMPRESS_SHADER_KEEP_ALL_PARTS, &compressedShader));

            // Create the cache directory if it doesn't exist
            if(DirectoryExists(baseCacheDir.c_str()) == false)
                Win32Call(CreateDirectory(baseCacheDir.c_str(), nullptr));

            if(DirectoryExists(cacheDir.c_str()) == false)
                Win32Call(CreateDirectory(cacheDir.c_str(), nullptr));

            File cacheFile(cacheName.c_str(), FileOpenMode::Write);

            // Write the compiled shader to disk
            uint64 shaderSize = compressedShader->GetBufferSize();
            cacheFile.Write(shaderSize, compressedShader->GetBufferPointer());

            return compiledShader;
        }
    }
}

struct ShaderFile
{
    wstring FilePath;
    uint64 TimeStamp;
    GrowableList<CompiledShader*> Shaders;

    ShaderFile(const wstring& filePath) : TimeStamp(0), FilePath(filePath)
    {
    }
};

static GrowableList<ShaderFile*> ShaderFiles;
static GrowableList<CompiledShader*> CompiledShaders;

static void CompileShader(CompiledShader* shader)
{
    Assert_(shader != nullptr);

    GrowableList<wstring> filePaths;
    D3D_SHADER_MACRO defines[CompileOptions::MaxDefines + 1];
    shader->CompileOpts.MakeDefines(defines);
    shader->ByteCode = CompileShader(shader->FilePath.c_str(), shader->FunctionName.c_str(),
                                     shader->Type, shader->Profile, defines,
                                     shader->ForceOptimization, filePaths);
    shader->ByteCodeHash = GenerateHash(shader->ByteCode->GetBufferPointer(), int(shader->ByteCode->GetBufferSize()));

    for(uint64 fileIdx = 0; fileIdx < filePaths.Count(); ++ fileIdx)
    {
        const wstring& filePath = filePaths[fileIdx];
        ShaderFile* shaderFile = nullptr;
        for(uint64 shaderFileIdx = 0; shaderFileIdx < ShaderFiles.Count(); ++shaderFileIdx)
        {
            if(ShaderFiles[shaderFileIdx]->FilePath == filePath)
            {
                shaderFile = ShaderFiles[shaderFileIdx];
                break;
            }
        }
        if(shaderFile == nullptr)
        {
            shaderFile = new ShaderFile(filePath);
            ShaderFiles.Add(shaderFile);
        }

        bool containsShader = false;
        for(uint64 shaderIdx = 0; shaderIdx < shaderFile->Shaders.Count(); ++shaderIdx)
        {
            if(shaderFile->Shaders[shaderIdx] == shader)
            {
                containsShader = true;
                break;
            }
        }

        if(containsShader == false)
            shaderFile->Shaders.Add(shader);
    }
}

CompiledShaderPtr CompileFromFile(const wchar* path,
                                  const char* functionName,
                                  ShaderType type,
                                  ShaderProfile profile,
                                  const CompileOptions& compileOpts,
                                  bool forceOptimization)
{
    CompiledShader* compiledShader = new CompiledShader(path, functionName, profile, compileOpts, forceOptimization, type);
    CompileShader(compiledShader);
    CompiledShaders.Add(compiledShader);

    return compiledShader;
}

VertexShaderPtr CompileVSFromFile(const wchar* path,
                                  const char* functionName,
                                  ShaderProfile profile,
                                  const CompileOptions& compileOptions,
                                  bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Vertex, profile, compileOptions, forceOptimization);
}

PixelShaderPtr CompilePSFromFile(const wchar* path,
                                 const char* functionName,
                                 ShaderProfile profile,
                                 const CompileOptions& compileOptions,
                                 bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Pixel, profile, compileOptions, forceOptimization);
}

GeometryShaderPtr CompileGSFromFile(const wchar* path,
                                    const char* functionName,
                                    ShaderProfile profile,
                                    const CompileOptions& compileOptions,
                                    bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Geometry, profile, compileOptions, forceOptimization);
}

HullShaderPtr CompileHSFromFile(const wchar* path,
                                const char* functionName,
                                ShaderProfile profile,
                                const CompileOptions& compileOptions,
                                bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Hull, profile, compileOptions, forceOptimization);
}

DomainShaderPtr CompileDSFromFile(const wchar* path,
                                  const char* functionName,
                                  ShaderProfile profile,
                                  const CompileOptions& compileOptions,
                                  bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Domain, profile, compileOptions, forceOptimization);
}

ComputeShaderPtr CompileCSFromFile(const wchar* path,
                                   const char* functionName,
                                   ShaderProfile profile,
                                   const CompileOptions& compileOptions,
                                   bool forceOptimization)
{
    return CompileFromFile(path, functionName, ShaderType::Compute, profile, compileOptions, forceOptimization);
}

bool UpdateShaders()
{
    if(ShaderFiles.Count() == 0)
        return false;

    static uint64 currFile = 0;
    currFile = (currFile + 1) % uint64(ShaderFiles.Count());

    ShaderFile* file = ShaderFiles[currFile];
    const uint64 newTimeStamp = GetFileTimestamp(file->FilePath.c_str());
    if(file->TimeStamp == 0)
    {
        file->TimeStamp = newTimeStamp;
        return false;
    }

    if(file->TimeStamp < newTimeStamp)
    {
        WriteLog("Hot-swapping shaders for %ls\n", file->FilePath.c_str());
        file->TimeStamp = newTimeStamp;
        for(uint64 i = 0; i < file->Shaders.Count(); ++i)
        {
            // Retry a few times to avoid file conflicts with text editors
            const uint64 NumRetries = 10;
            for(uint64 retryCount = 0; retryCount < NumRetries; ++retryCount)
            {
                try
                {
                    CompiledShader* shader = file->Shaders[i];
                    CompileShader(shader);
                    break;
                }
                catch(Win32Exception& exception)
                {
                    if(retryCount == NumRetries - 1)
                        throw exception;
                    Sleep(15);
                }
            }
        }

        return true;
    }

    return false;
}

void ShutdownShaders()
{
    for(uint64 i = 0; i < ShaderFiles.Count(); ++i)
        delete ShaderFiles[i];

    for(uint64 i = 0; i < CompiledShaders.Count(); ++i)
        delete CompiledShaders[i];
}

// == CompileOptions ==============================================================================

CompileOptions::CompileOptions()
{
    Reset();
}

void CompileOptions::Add(const std::string& name, uint32 value)
{
    Assert_(numDefines < MaxDefines);

    nameOffsets[numDefines] = bufferIdx;
    for(uint32 i = 0; i < name.length(); ++i)
        buffer[bufferIdx++] = name[i];
    ++bufferIdx;

    std::string stringVal = ToAnsiString(value);
    defineOffsets[numDefines] = bufferIdx;
    for(uint32 i = 0; i < stringVal.length(); ++i)
        buffer[bufferIdx++] = stringVal[i];
    ++bufferIdx;

    ++numDefines;
}

void CompileOptions::Reset()
{
    numDefines = 0;
    bufferIdx = 0;

    for(uint32 i = 0; i < MaxDefines; ++i)
    {
        nameOffsets[i] = 0xFFFFFFFF;
        defineOffsets[i] = 0xFFFFFFFF;
    }

    ZeroMemory(buffer, BufferSize);
}

void CompileOptions::MakeDefines(D3D_SHADER_MACRO defines[MaxDefines + 1]) const
{
    for(uint32 i = 0; i < numDefines; ++i)
    {
        defines[i].Name = buffer + nameOffsets[i];
        defines[i].Definition = buffer + defineOffsets[i];
    }

    defines[numDefines].Name = nullptr;
    defines[numDefines].Definition = nullptr;
}

}