void SetDescriptorHeaps(ID3D12GraphicsCommandList* cmdList) { ID3D12DescriptorHeap* heaps[] = { SRVDescriptorHeap.CurrentHeap(), }; cmdList->SetDescriptorHeaps(ArraySize_(heaps), heaps); }
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"); } }
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(); }
// 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); }
"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) {
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(); }
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); }
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_SAMPLER_DESC GetSamplerState(SamplerState samplerState) { Assert_(uint64(samplerState) < ArraySize_(SamplerStateDescs)); return SamplerStateDescs[uint64(samplerState)]; }
D3D12_DEPTH_STENCIL_DESC GetDepthState(DepthState depthState) { Assert_(uint64(depthState) < ArraySize_(DepthStateDescs)); return DepthStateDescs[uint64(depthState)]; }
D3D12_RASTERIZER_DESC GetRasterizerState(RasterizerState rasterizerState) { Assert_(uint64(rasterizerState) < ArraySize_(RasterizerStateDescs)); return RasterizerStateDescs[uint64(rasterizerState)]; }
D3D12_BLEND_DESC GetBlendState(BlendState blendState) { Assert_(uint64(blendState) < ArraySize_(BlendStateDescs)); return BlendStateDescs[uint64(blendState)]; }
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
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; } }