From 579000e747413b9af3860c0b92e143d4ddc44e36 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 17 Mar 2018 13:55:42 -0500 Subject: [PATCH 1/5] GPU: Corrected the parameter documentation for the SetShader macro call. Register 0xE24 is actually a macro that sets some shader parameters in the register structure. Macros are uploaded to the GPU at startup and have their own ISA, we'll probably write an interpreter for this in the future. --- src/video_core/engines/maxwell_3d.cpp | 11 ++++++----- src/video_core/engines/maxwell_3d.h | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 603a2edaf2..9784ee069f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -15,6 +15,7 @@ const std::unordered_map Maxwell3D::method_handlers Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {} void Maxwell3D::CallMethod(u32 method, const std::vector& parameters) { + // TODO(Subv): Write an interpreter for the macros uploaded via registers 0x45 and 0x47 auto itr = method_handlers.find(method); if (itr == method_handlers.end()) { LOG_ERROR(HW_GPU, "Unhandled method call %08X", method); @@ -86,19 +87,19 @@ void Maxwell3D::SetShader(const std::vector& parameters) { * [1] = Unknown. * [2] = Offset to the start of the shader, after the 0x30 bytes header. * [3] = Shader Type. - * [4] = Shader End Address >> 8. + * [4] = Const Buffer Address >> 8. */ auto shader_program = static_cast(parameters[0]); // TODO(Subv): This address is probably an offset from the CODE_ADDRESS register. - GPUVAddr begin_address = parameters[2]; + GPUVAddr address = parameters[2]; auto shader_type = static_cast(parameters[3]); - GPUVAddr end_address = parameters[4] << 8; + GPUVAddr cb_address = parameters[4] << 8; auto& shader = state.shaders[static_cast(shader_program)]; shader.program = shader_program; shader.type = shader_type; - shader.begin_address = begin_address; - shader.end_address = end_address; + shader.address = address; + shader.cb_address = cb_address; } } // namespace Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c979d4e615..47df43c979 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -139,9 +139,9 @@ public: INSERT_PADDING_WORDS(0x5D0); struct { - u32 shader_code_call; - u32 shader_code_args; - } shader_code; + u32 set_shader_call; + u32 set_shader_args; + } set_shader; INSERT_PADDING_WORDS(0x10); }; std::array reg_array; @@ -154,8 +154,8 @@ public: struct ShaderInfo { Regs::ShaderType type; Regs::ShaderProgram program; - GPUVAddr begin_address; - GPUVAddr end_address; + GPUVAddr address; + GPUVAddr cb_address; }; std::array shaders; @@ -194,7 +194,7 @@ ASSERT_REG_POSITION(query, 0x6C0); ASSERT_REG_POSITION(vertex_array[0], 0x700); ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); ASSERT_REG_POSITION(shader_config[0], 0x800); -ASSERT_REG_POSITION(shader_code, 0xE24); +ASSERT_REG_POSITION(set_shader, 0xE24); #undef ASSERT_REG_POSITION From 1d9d9c16e8d05837e7f80c533190da27fb298d8b Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 17 Mar 2018 16:17:45 -0500 Subject: [PATCH 2/5] GPU: Make the SetShader macro call do the same as the real macro's code. It'll now set the CB_SIZE, CB_ADDRESS and CB_BIND registers when it's called. Presumably this SetShader function is binding the constant shader uniforms to buffer 1 (c1[]). --- src/video_core/engines/maxwell_3d.cpp | 20 +++++++++++++++++++- src/video_core/engines/maxwell_3d.h | 27 +++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 9784ee069f..4b15ed2f25 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -84,7 +84,7 @@ void Maxwell3D::SetShader(const std::vector& parameters) { /** * Parameters description: * [0] = Shader Program. - * [1] = Unknown. + * [1] = Unknown, presumably the shader id. * [2] = Offset to the start of the shader, after the 0x30 bytes header. * [3] = Shader Type. * [4] = Const Buffer Address >> 8. @@ -100,6 +100,24 @@ void Maxwell3D::SetShader(const std::vector& parameters) { shader.type = shader_type; shader.address = address; shader.cb_address = cb_address; + + // Perform the same operations as the real macro code. + // TODO(Subv): Early exit if register 0xD1C + shader_program contains the same as params[1]. + auto& shader_regs = regs.shader_config[static_cast(shader_program)]; + shader_regs.start_id = address; + // TODO(Subv): Write params[1] to register 0xD1C + shader_program. + // TODO(Subv): Write params[2] to register 0xD22 + shader_program. + + // Note: This value is hardcoded in the macro's code. + static constexpr u32 DefaultCBSize = 0x10000; + regs.const_buffer.cb_size = DefaultCBSize; + regs.const_buffer.cb_address_high = cb_address >> 32; + regs.const_buffer.cb_address_low = cb_address & 0xFFFFFFFF; + + // Write a hardcoded 0x11 to CB_BIND, this binds the current const buffer to buffer c1[] in the + // shader. It's likely that these are the constants for the shader. + regs.cb_bind[static_cast(shader_type)].valid.Assign(1); + regs.cb_bind[static_cast(shader_type)].index.Assign(1); } } // namespace Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 47df43c979..6eb98080d2 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -35,8 +35,10 @@ public: struct Regs { static constexpr size_t NUM_REGS = 0xE36; + static constexpr size_t NumCBData = 16; static constexpr size_t NumVertexArrays = 32; static constexpr size_t MaxShaderProgram = 6; + static constexpr size_t MaxShaderType = 5; enum class QueryMode : u32 { Write = 0, @@ -136,7 +138,27 @@ public: INSERT_PADDING_WORDS(9); } shader_config[MaxShaderProgram]; - INSERT_PADDING_WORDS(0x5D0); + INSERT_PADDING_WORDS(0x8C); + + struct { + u32 cb_size; + u32 cb_address_high; + u32 cb_address_low; + u32 cb_pos; + u32 cb_data[NumCBData]; + } const_buffer; + + INSERT_PADDING_WORDS(0x74); + + struct { + union { + BitField<0, 1, u32> valid; + BitField<4, 5, u32> index; + }; + INSERT_PADDING_WORDS(7); + } cb_bind[MaxShaderType]; + + INSERT_PADDING_WORDS(0x494); struct { u32 set_shader_call; @@ -161,7 +183,7 @@ public: std::array shaders; }; - State state; + State state{}; private: MemoryManager& memory_manager; @@ -194,6 +216,7 @@ ASSERT_REG_POSITION(query, 0x6C0); ASSERT_REG_POSITION(vertex_array[0], 0x700); ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); ASSERT_REG_POSITION(shader_config[0], 0x800); +ASSERT_REG_POSITION(const_buffer, 0x8E0); ASSERT_REG_POSITION(set_shader, 0xE24); #undef ASSERT_REG_POSITION From 66dae227908eb733ede0cc728b79d70352467bbc Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 17 Mar 2018 16:29:20 -0500 Subject: [PATCH 3/5] GPU: Corrected some register offsets and removed superfluous macro registers. --- src/video_core/engines/maxwell_3d.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 6eb98080d2..c8920da50d 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -148,7 +148,7 @@ public: u32 cb_data[NumCBData]; } const_buffer; - INSERT_PADDING_WORDS(0x74); + INSERT_PADDING_WORDS(0x10); struct { union { @@ -158,13 +158,7 @@ public: INSERT_PADDING_WORDS(7); } cb_bind[MaxShaderType]; - INSERT_PADDING_WORDS(0x494); - - struct { - u32 set_shader_call; - u32 set_shader_args; - } set_shader; - INSERT_PADDING_WORDS(0x10); + INSERT_PADDING_WORDS(0x50A); }; std::array reg_array; }; @@ -217,7 +211,7 @@ ASSERT_REG_POSITION(vertex_array[0], 0x700); ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); ASSERT_REG_POSITION(shader_config[0], 0x800); ASSERT_REG_POSITION(const_buffer, 0x8E0); -ASSERT_REG_POSITION(set_shader, 0xE24); +ASSERT_REG_POSITION(cb_bind[0], 0x904); #undef ASSERT_REG_POSITION From 88698c156ffe567885f154c80270db962d29e82b Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 17 Mar 2018 17:06:23 -0500 Subject: [PATCH 4/5] GPU: Store shader constbuffer bindings in the GPU state. --- src/video_core/engines/maxwell_3d.cpp | 38 +++++++++++++++++++++++++-- src/video_core/engines/maxwell_3d.h | 28 +++++++++++++++++--- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 4b15ed2f25..50153eff36 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -43,6 +43,26 @@ void Maxwell3D::WriteReg(u32 method, u32 value) { ASSERT_MSG(regs.code_address.CodeAddress() == 0, "Unexpected CODE_ADDRESS register value."); break; } + case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { + ProcessCBBind(Regs::ShaderType::Vertex); + break; + } + case MAXWELL3D_REG_INDEX(cb_bind[1].raw_config): { + ProcessCBBind(Regs::ShaderType::TesselationControl); + break; + } + case MAXWELL3D_REG_INDEX(cb_bind[2].raw_config): { + ProcessCBBind(Regs::ShaderType::TesselationEval); + break; + } + case MAXWELL3D_REG_INDEX(cb_bind[3].raw_config): { + ProcessCBBind(Regs::ShaderType::Geometry); + break; + } + case MAXWELL3D_REG_INDEX(cb_bind[4].raw_config): { + ProcessCBBind(Regs::ShaderType::Fragment); + break; + } case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): { DrawArrays(); break; @@ -95,11 +115,10 @@ void Maxwell3D::SetShader(const std::vector& parameters) { auto shader_type = static_cast(parameters[3]); GPUVAddr cb_address = parameters[4] << 8; - auto& shader = state.shaders[static_cast(shader_program)]; + auto& shader = state.shader_programs[static_cast(shader_program)]; shader.program = shader_program; shader.type = shader_type; shader.address = address; - shader.cb_address = cb_address; // Perform the same operations as the real macro code. // TODO(Subv): Early exit if register 0xD1C + shader_program contains the same as params[1]. @@ -118,6 +137,21 @@ void Maxwell3D::SetShader(const std::vector& parameters) { // shader. It's likely that these are the constants for the shader. regs.cb_bind[static_cast(shader_type)].valid.Assign(1); regs.cb_bind[static_cast(shader_type)].index.Assign(1); + + ProcessCBBind(shader_type); +} + +void Maxwell3D::ProcessCBBind(Regs::ShaderType stage) { + // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. + auto& shader = state.shader_stages[static_cast(stage)]; + auto& bind_data = regs.cb_bind[static_cast(stage)]; + + auto& buffer = shader.const_buffers[bind_data.index]; + + buffer.enabled = bind_data.valid.Value() != 0; + buffer.index = bind_data.index; + buffer.address = regs.const_buffer.BufferAddress(); + buffer.size = regs.const_buffer.cb_size; } } // namespace Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c8920da50d..9e28d83198 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -39,6 +39,8 @@ public: static constexpr size_t NumVertexArrays = 32; static constexpr size_t MaxShaderProgram = 6; static constexpr size_t MaxShaderType = 5; + // Maximum number of const buffers per shader stage. + static constexpr size_t MaxConstBuffers = 16; enum class QueryMode : u32 { Write = 0, @@ -146,12 +148,18 @@ public: u32 cb_address_low; u32 cb_pos; u32 cb_data[NumCBData]; + + GPUVAddr BufferAddress() const { + return static_cast( + (static_cast(cb_address_high) << 32) | cb_address_low); + } } const_buffer; INSERT_PADDING_WORDS(0x10); struct { union { + u32 raw_config; BitField<0, 1, u32> valid; BitField<4, 5, u32> index; }; @@ -167,14 +175,25 @@ public: static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); struct State { - struct ShaderInfo { + struct ConstBufferInfo { + GPUVAddr address; + u32 index; + u32 size; + bool enabled; + }; + + struct ShaderProgramInfo { Regs::ShaderType type; Regs::ShaderProgram program; GPUVAddr address; - GPUVAddr cb_address; }; - std::array shaders; + struct ShaderStageInfo { + std::array const_buffers; + }; + + std::array shader_stages; + std::array shader_programs; }; State state{}; @@ -185,6 +204,9 @@ private: /// Handles a write to the QUERY_GET register. void ProcessQueryGet(); + /// Handles a write to the CB_BIND register. + void ProcessCBBind(Regs::ShaderType stage); + /// Handles a write to the VERTEX_END_GL register, triggering a draw. void DrawArrays(); From ccb8da15129bc04017eb5da2ee67f6cdce22e320 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 17 Mar 2018 17:08:26 -0500 Subject: [PATCH 5/5] GPU: Renamed ShaderType to ShaderStage as that is less confusing. --- src/video_core/engines/maxwell_3d.cpp | 24 ++++++++++++------------ src/video_core/engines/maxwell_3d.h | 14 +++++++------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 50153eff36..db12fc7025 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -44,23 +44,23 @@ void Maxwell3D::WriteReg(u32 method, u32 value) { break; } case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { - ProcessCBBind(Regs::ShaderType::Vertex); + ProcessCBBind(Regs::ShaderStage::Vertex); break; } case MAXWELL3D_REG_INDEX(cb_bind[1].raw_config): { - ProcessCBBind(Regs::ShaderType::TesselationControl); + ProcessCBBind(Regs::ShaderStage::TesselationControl); break; } case MAXWELL3D_REG_INDEX(cb_bind[2].raw_config): { - ProcessCBBind(Regs::ShaderType::TesselationEval); + ProcessCBBind(Regs::ShaderStage::TesselationEval); break; } case MAXWELL3D_REG_INDEX(cb_bind[3].raw_config): { - ProcessCBBind(Regs::ShaderType::Geometry); + ProcessCBBind(Regs::ShaderStage::Geometry); break; } case MAXWELL3D_REG_INDEX(cb_bind[4].raw_config): { - ProcessCBBind(Regs::ShaderType::Fragment); + ProcessCBBind(Regs::ShaderStage::Fragment); break; } case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): { @@ -106,18 +106,18 @@ void Maxwell3D::SetShader(const std::vector& parameters) { * [0] = Shader Program. * [1] = Unknown, presumably the shader id. * [2] = Offset to the start of the shader, after the 0x30 bytes header. - * [3] = Shader Type. + * [3] = Shader Stage. * [4] = Const Buffer Address >> 8. */ auto shader_program = static_cast(parameters[0]); // TODO(Subv): This address is probably an offset from the CODE_ADDRESS register. GPUVAddr address = parameters[2]; - auto shader_type = static_cast(parameters[3]); + auto shader_stage = static_cast(parameters[3]); GPUVAddr cb_address = parameters[4] << 8; auto& shader = state.shader_programs[static_cast(shader_program)]; shader.program = shader_program; - shader.type = shader_type; + shader.stage = shader_stage; shader.address = address; // Perform the same operations as the real macro code. @@ -135,13 +135,13 @@ void Maxwell3D::SetShader(const std::vector& parameters) { // Write a hardcoded 0x11 to CB_BIND, this binds the current const buffer to buffer c1[] in the // shader. It's likely that these are the constants for the shader. - regs.cb_bind[static_cast(shader_type)].valid.Assign(1); - regs.cb_bind[static_cast(shader_type)].index.Assign(1); + regs.cb_bind[static_cast(shader_stage)].valid.Assign(1); + regs.cb_bind[static_cast(shader_stage)].index.Assign(1); - ProcessCBBind(shader_type); + ProcessCBBind(shader_stage); } -void Maxwell3D::ProcessCBBind(Regs::ShaderType stage) { +void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. auto& shader = state.shader_stages[static_cast(stage)]; auto& bind_data = regs.cb_bind[static_cast(stage)]; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 9e28d83198..98137f94b2 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -38,7 +38,7 @@ public: static constexpr size_t NumCBData = 16; static constexpr size_t NumVertexArrays = 32; static constexpr size_t MaxShaderProgram = 6; - static constexpr size_t MaxShaderType = 5; + static constexpr size_t MaxShaderStage = 5; // Maximum number of const buffers per shader stage. static constexpr size_t MaxConstBuffers = 16; @@ -56,7 +56,7 @@ public: Fragment = 5, }; - enum class ShaderType : u32 { + enum class ShaderStage : u32 { Vertex = 0, TesselationControl = 1, TesselationEval = 2, @@ -136,7 +136,7 @@ public: u32 start_id; INSERT_PADDING_WORDS(1); u32 gpr_alloc; - ShaderType type; + ShaderStage type; INSERT_PADDING_WORDS(9); } shader_config[MaxShaderProgram]; @@ -164,7 +164,7 @@ public: BitField<4, 5, u32> index; }; INSERT_PADDING_WORDS(7); - } cb_bind[MaxShaderType]; + } cb_bind[MaxShaderStage]; INSERT_PADDING_WORDS(0x50A); }; @@ -183,7 +183,7 @@ public: }; struct ShaderProgramInfo { - Regs::ShaderType type; + Regs::ShaderStage stage; Regs::ShaderProgram program; GPUVAddr address; }; @@ -192,7 +192,7 @@ public: std::array const_buffers; }; - std::array shader_stages; + std::array shader_stages; std::array shader_programs; }; @@ -205,7 +205,7 @@ private: void ProcessQueryGet(); /// Handles a write to the CB_BIND register. - void ProcessCBBind(Regs::ShaderType stage); + void ProcessCBBind(Regs::ShaderStage stage); /// Handles a write to the VERTEX_END_GL register, triggering a draw. void DrawArrays();