diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 1135d80fe0..7aa469dc93 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -20,7 +20,9 @@ static void check(HRESULT hr) D3D12GSRender::D3D12GSRender() : GSRender(), m_fbo(nullptr), m_PSO(nullptr) { - memset(vertexBufferSize, 0, sizeof(vertexBufferSize)); + memset(m_vertexBufferSize, 0, sizeof(m_vertexBufferSize)); + m_constantsBufferOffset = 0; + m_constantsBufferIndex = 0; // Enable d3d debug layer Microsoft::WRL::ComPtr debugInterface; D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)); @@ -95,6 +97,45 @@ D3D12GSRender::D3D12GSRender() IID_PPV_ARGS(&m_vertexBuffer[i]) )); } + + check(m_device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &resDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&m_constantsBuffer) + )); + + D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; + descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + descriptorHeapDesc.NumDescriptors = 1000; // For safety + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + check(m_device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&m_constantsBufferDescriptorsHeap))); + + // Common root signature + D3D12_DESCRIPTOR_RANGE descriptorRange = {}; + descriptorRange.BaseShaderRegister = 0; + descriptorRange.NumDescriptors = 1; + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + D3D12_ROOT_PARAMETER RP = {}; + RP.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP.DescriptorTable.pDescriptorRanges = &descriptorRange; + RP.DescriptorTable.NumDescriptorRanges = 1; + + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; + rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + rootSignatureDesc.NumParameters = 1; + rootSignatureDesc.pParameters = &RP; + + Microsoft::WRL::ComPtr rootSignatureBlob; + check(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, nullptr)); + + m_device->CreateRootSignature(0, + rootSignatureBlob->GetBufferPointer(), + rootSignatureBlob->GetBufferSize(), + IID_PPV_ARGS(&m_rootSignature)); } D3D12GSRender::~D3D12GSRender() @@ -238,7 +279,7 @@ void D3D12GSRender::EnableVertexData(bool indexed_draw) memcpy((char*)bufferMap + data_offset * item_size, &m_vertex_data[i].data[data_offset * item_size], data_size); m_vertexBuffer[i]->Unmap(0, nullptr); size_t newOffset = (data_offset + data_size) * item_size; - vertexBufferSize[i] = newOffset > vertexBufferSize[i] ? newOffset : vertexBufferSize[i]; + m_vertexBufferSize[i] = newOffset > m_vertexBufferSize[i] ? newOffset : m_vertexBufferSize[i]; } if (indexed_draw) @@ -270,6 +311,86 @@ void D3D12GSRender::EnableVertexData(bool indexed_draw) } } +void D3D12GSRender::FillVertexShaderConstantsBuffer() +{ + float scaleOffsetMat[16] = + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + size_t currentoffset = 0; + void *constantsBufferMap; + // TODO: Use finer range + D3D12_RANGE range = { + m_constantsBufferOffset, + 1024 * 1024 - m_constantsBufferOffset + }; + check(m_constantsBuffer->Map(0, &range, &constantsBufferMap)); + + // Scale + scaleOffsetMat[0] = (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 0)] / (RSXThread::m_width / RSXThread::m_width_scale); + scaleOffsetMat[5] = (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 1)] / (RSXThread::m_height / RSXThread::m_height_scale); + scaleOffsetMat[10] = (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 2)]; + + // Offset + scaleOffsetMat[3] = (float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 0)] - (RSXThread::m_width / RSXThread::m_width_scale); + scaleOffsetMat[7] = (float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 1)] - (RSXThread::m_height / RSXThread::m_height_scale); + scaleOffsetMat[11] = (float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 2)] - 1 / 2.0f; + + scaleOffsetMat[3] /= RSXThread::m_width / RSXThread::m_width_scale; + scaleOffsetMat[7] /= RSXThread::m_height / RSXThread::m_height_scale; + + memcpy((char*)constantsBufferMap + m_constantsBufferOffset + currentoffset, scaleOffsetMat, 16 * sizeof(float)); + currentoffset += 16 * sizeof(float); + + for (const RSXTransformConstant& c : m_transform_constants) + { + float vector[] = { c.x, c.y, c.z, c.w }; + memcpy((char*)constantsBufferMap + m_constantsBufferOffset + currentoffset, vector, 4 * sizeof(float)); + currentoffset += 4 * sizeof(float); + } + m_constantsBuffer->Unmap(0, &range); + // Align to 256 byte + currentoffset = (currentoffset + 255) & ~255; + + + D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferViewDesc = {}; + constantBufferViewDesc.BufferLocation = m_constantsBuffer->GetGPUVirtualAddress() + m_constantsBufferOffset; + constantBufferViewDesc.SizeInBytes = (UINT)currentoffset; + D3D12_CPU_DESCRIPTOR_HANDLE Handle = m_constantsBufferDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += m_constantsBufferIndex * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + m_device->CreateConstantBufferView(&constantBufferViewDesc, Handle); + m_constantsBufferOffset += currentoffset; +} + +void D3D12GSRender::FillPixelShaderConstantsBuffer() +{ +/* if (!m_cur_fragment_prog) + { + LOG_ERROR(RSX, "InitFragmentData: m_cur_shader_prog == NULL"); + return; + } + + for (const RSXTransformConstant& c : m_fragment_constants) + { + u32 id = c.id - m_cur_fragment_prog->offset; + + //LOG_WARNING(RSX,"fc%u[0x%x - 0x%x] = (%f, %f, %f, %f)", id, c.id, m_cur_shader_prog->offset, c.x, c.y, c.z, c.w); + + const std::string name = fmt::Format("fc%u", id); + const int l = m_program.GetLocation(name); + checkForGlError("glGetUniformLocation " + name); + + glUniform4f(l, c.x, c.y, c.z, c.w); + checkForGlError("glUniform4f " + name + fmt::Format(" %u [%f %f %f %f]", l, c.x, c.y, c.z, c.w)); + } + + //if (m_fragment_constants.GetCount())*/ + // LOG_NOTICE(HLE, ""); +} + bool D3D12GSRender::LoadProgram() { @@ -287,7 +408,7 @@ bool D3D12GSRender::LoadProgram() return false; } - m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_cur_vertex_prog, m_cur_fragment_prog, m_IASet); + m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, m_IASet); return true; } @@ -297,6 +418,8 @@ void D3D12GSRender::ExecCMD() m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList)); m_inflightCommandList.push_back(commandList); + commandList->SetGraphicsRootSignature(m_rootSignature); + if (m_indexed_array.m_count) { // LoadVertexData(m_indexed_array.index_min, m_indexed_array.index_max - m_indexed_array.index_min + 1); @@ -313,15 +436,21 @@ void D3D12GSRender::ExecCMD() D3D12_VERTEX_BUFFER_VIEW vertexBufferView = {}; vertexBufferView.BufferLocation = m_vertexBuffer[i]->GetGPUVirtualAddress(); - vertexBufferView.SizeInBytes = (UINT)vertexBufferSize[i]; + vertexBufferView.SizeInBytes = (UINT)m_vertexBufferSize[i]; vertexBufferView.StrideInBytes = (UINT)item_size; vertexBufferViews.push_back(vertexBufferView); - assert((m_draw_array_first + m_draw_array_count) * item_size <= vertexBufferSize[i]); + assert((m_draw_array_first + m_draw_array_count) * item_size <= m_vertexBufferSize[i]); } commandList->IASetVertexBuffers(0, (UINT)vertexBufferViews.size(), vertexBufferViews.data()); - // InitVertexData(); - // InitFragmentData(); + FillVertexShaderConstantsBuffer(); + commandList->SetDescriptorHeaps(1, &m_constantsBufferDescriptorsHeap); + D3D12_GPU_DESCRIPTOR_HANDLE Handle = m_constantsBufferDescriptorsHeap->GetGPUDescriptorHandleForHeapStart(); + Handle.ptr += m_constantsBufferIndex * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + commandList->SetGraphicsRootDescriptorTable(0, Handle); + m_constantsBufferIndex++; + + FillPixelShaderConstantsBuffer(); } if (!LoadProgram()) @@ -758,6 +887,8 @@ void D3D12GSRender::Flip() for (ID3D12GraphicsCommandList *gfxCommandList : m_inflightCommandList) gfxCommandList->Release(); m_inflightCommandList.clear(); - memset(vertexBufferSize, 0, sizeof(vertexBufferSize)); + memset(m_vertexBufferSize, 0, sizeof(m_vertexBufferSize)); + m_constantsBufferOffset = 0; + m_constantsBufferIndex = 0; } #endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 5bcc64c487..e987143e40 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -43,17 +43,21 @@ void SetGetD3DGSFrameCallback(GetGSFrameCb2 value); class D3D12GSRender : public GSRender { private: - size_t vertexBufferSize[32]; + size_t m_vertexBufferSize[32]; std::vector m_vdata; // std::vector m_post_draw_objs; PipelineStateObjectCache m_cachePSO; ID3D12PipelineState *m_PSO; + ID3D12RootSignature *m_rootSignature; // GLTexture m_gl_textures[m_textures_count]; // GLTexture m_gl_vertex_textures[m_textures_count]; ID3D12Resource *m_indexBuffer, *m_vertexBuffer[m_vertex_count]; + ID3D12Resource *m_constantsBuffer; + ID3D12DescriptorHeap *m_constantsBufferDescriptorsHeap; + size_t m_constantsBufferOffset, m_constantsBufferIndex; std::vector m_IASet; D3D12RenderTargetSets *m_fbo; ID3D12Device* m_device; @@ -80,9 +84,9 @@ private: bool LoadProgram(); void EnableVertexData(bool indexed_draw = false); + void FillVertexShaderConstantsBuffer(); + void FillPixelShaderConstantsBuffer(); /*void DisableVertexData(); - void InitVertexData(); - void InitFragmentData(); void WriteBuffers(); void WriteDepthBuffer(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 3fa7ed3901..613a65fad6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -90,7 +90,7 @@ void PipelineStateObjectCache::Add(ID3D12PipelineState *prog, Shader& fp, Shader cachePSO.insert(std::make_pair(key, prog)); } -ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Device *device, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet) +ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Device *device, ID3D12RootSignature *rootSignature, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet) { ID3D12PipelineState *result = nullptr; Shader m_vertex_prog, m_fragment_prog; @@ -163,10 +163,18 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Dev D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {}; - graphicPipelineStateDesc.VS.BytecodeLength = m_vertex_prog.bytecode->GetBufferSize(); - graphicPipelineStateDesc.VS.pShaderBytecode = m_vertex_prog.bytecode->GetBufferPointer(); - graphicPipelineStateDesc.PS.BytecodeLength = m_fragment_prog.bytecode->GetBufferSize(); - graphicPipelineStateDesc.PS.pShaderBytecode = m_fragment_prog.bytecode->GetBufferPointer(); + if (m_vertex_prog.bytecode != nullptr) + { + graphicPipelineStateDesc.VS.BytecodeLength = m_vertex_prog.bytecode->GetBufferSize(); + graphicPipelineStateDesc.VS.pShaderBytecode = m_vertex_prog.bytecode->GetBufferPointer(); + } + if (m_fragment_prog.bytecode != nullptr) + { + graphicPipelineStateDesc.PS.BytecodeLength = m_fragment_prog.bytecode->GetBufferSize(); + graphicPipelineStateDesc.PS.pShaderBytecode = m_fragment_prog.bytecode->GetBufferPointer(); + } + + graphicPipelineStateDesc.pRootSignature = rootSignature; // Sensible default value static D3D12_RASTERIZER_DESC CD3D12_RASTERIZER_DESC = @@ -240,22 +248,44 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Dev return result; } +#define TO_STRING(x) #x + void Shader::Compile(SHADER_TYPE st) { - static const char VSstring[] = - "#define RS \"RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)\"\n" - "[RootSignature(RS)]\n" - "float4 main(float4 pos : TEXCOORD0) : SV_POSITION\n" - "{\n" - " return float4(pos.x, pos.y, 0., 1.);\n" - "}"; - static const char FSstring[] = - "#define RS \"RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)\"\n" - "[RootSignature(RS)]\n" - "float4 main() : SV_TARGET" - "{" - "return float4(1.0f, 1.0f, 1.0f, 1.0f);" - "}"; + static const char VSstring[] = TO_STRING( + cbuffer CONSTANT : register(b0) + { + float4x4 scaleOffsetMat; + }; + + struct vertex { + float4 pos : TEXCOORD0; + float4 color : TEXCOORD3; + }; + + struct pixel { + float4 pos : SV_POSITION; + float4 color : TEXCOORD0; + }; + + pixel main(vertex In) + { + pixel Out; + Out.pos = mul(float4(In.pos.x, In.pos.y, 0., 1.), scaleOffsetMat); + Out.color = In.color; + return Out; + }); + + static const char FSstring[] = TO_STRING( + struct pixel { + float4 pos : SV_POSITION; + float4 color : TEXCOORD0; + }; + float4 main(pixel In) : SV_TARGET + { + return In.color; + }); + HRESULT hr; Microsoft::WRL::ComPtr errorBlob; switch (st) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index bddf433027..f8fa6a5ea2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -161,7 +161,7 @@ public: PipelineStateObjectCache(); ~PipelineStateObjectCache(); // Note: the last param is not taken into account if the PSO is not regenerated - ID3D12PipelineState *getGraphicPipelineState(ID3D12Device *device, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet); + ID3D12PipelineState *getGraphicPipelineState(ID3D12Device *device, ID3D12RootSignature *rootSignature, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet); };