From bbc7844021dc34e26285a495ed86bad088b87279 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 18 Dec 2016 15:39:56 -0800 Subject: VideoCore: Change misleading register names A few registers had names such as "count" or "number" when they actually contained the maximum (that is, count - 1). This can easily lead to hard to notice off by one errors. --- src/video_core/pica.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/video_core/pica.h') diff --git a/src/video_core/pica.h b/src/video_core/pica.h index b2db609ec..5afc9d5dd 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -868,7 +868,7 @@ struct Regs { LightSrc light[8]; LightColor global_ambient; // Emission + (material.ambient * lighting.ambient) INSERT_PADDING_WORDS(0x1); - BitField<0, 3, u32> num_lights; // Number of enabled lights - 1 + BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1 union { BitField<2, 2, LightingFresnelSelector> fresnel_selector; @@ -1045,7 +1045,7 @@ struct Regs { BitField<48, 12, u64> attribute_mask; // number of total attributes minus 1 - BitField<60, 4, u64> num_extra_attributes; + BitField<60, 4, u64> max_attribute_index; }; inline VertexAttributeFormat GetFormat(int n) const { @@ -1076,7 +1076,7 @@ struct Regs { } inline int GetNumTotalAttributes() const { - return (int)num_extra_attributes + 1; + return (int)max_attribute_index + 1; } // Attribute loaders map the source vertex data to input attributes @@ -1214,7 +1214,7 @@ struct Regs { union { // Number of input attributes to shader unit - 1 - BitField<0, 4, u32> num_input_attributes; + BitField<0, 4, u32> max_input_attribute_index; }; // Offset to shader program entry point (in words) -- cgit v1.2.3 From fccb28d2e9f2f813230912e5cf1fea7f352797c7 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 18 Dec 2016 16:50:04 -0800 Subject: VideoCore: Use correct register for immediate mode attribute count --- src/video_core/command_processor.cpp | 13 +++++++------ src/video_core/pica.h | 7 ++++++- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/video_core/pica.h') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 45b994b46..27b7a023f 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -128,17 +128,18 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { g_state.input_default_attributes.attr[setup.index] = attribute; setup.index++; } else { - // Put each attribute into an immediate input buffer. - // When all specified immediate attributes are present, the Vertex Shader is invoked - // and everything is - // sent to the primitive assembler. + // Put each attribute into an immediate input buffer. When all specified immediate + // attributes are present, the Vertex Shader is invoked and everything is sent to + // the primitive assembler. auto& immediate_input = g_state.immediate.input_vertex; auto& immediate_attribute_id = g_state.immediate.current_attribute; - immediate_input.attr[immediate_attribute_id++] = attribute; + immediate_input.attr[immediate_attribute_id] = attribute; - if (immediate_attribute_id > regs.vs.max_input_attribute_index) { + if (immediate_attribute_id < regs.max_input_attrib_index) { + immediate_attribute_id += 1; + } else { MICROPROFILE_SCOPE(GPU_Drawing); immediate_attribute_id = 0; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 5afc9d5dd..c772896e0 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -1176,7 +1176,12 @@ struct Regs { } } command_buffer; - INSERT_PADDING_WORDS(0x07); + INSERT_PADDING_WORDS(4); + + /// Number of input attributes to the vertex shader minus 1 + BitField<0, 4, u32> max_input_attrib_index; + + INSERT_PADDING_WORDS(2); enum class GPUMode : u32 { Drawing = 0, -- cgit v1.2.3 From 335df895b9f9e9760ed5cd0d6dfaea8befb94dac Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 18 Dec 2016 17:25:03 -0800 Subject: VideoCore: Consistently use shader configuration to load attributes --- .../debugger/graphics/graphics_vertex_shader.cpp | 6 ++-- src/video_core/command_processor.cpp | 4 +-- src/video_core/pica.h | 39 +++++----------------- src/video_core/shader/shader.cpp | 11 +++--- src/video_core/shader/shader.h | 6 ++-- src/video_core/shader/shader_interpreter.cpp | 4 +-- src/video_core/shader/shader_interpreter.h | 3 +- 7 files changed, 26 insertions(+), 47 deletions(-) (limited to 'src/video_core/pica.h') diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp index f37524190..489ec5f21 100644 --- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp @@ -511,7 +511,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d auto& shader_config = Pica::g_state.regs.vs; for (auto instr : shader_setup.program_code) info.code.push_back({instr}); - int num_attributes = Pica::g_state.regs.vertex_attributes.GetNumTotalAttributes(); + int num_attributes = shader_config.max_input_attribute_index + 1; for (auto pattern : shader_setup.swizzle_data) info.swizzle_info.push_back({pattern}); @@ -522,11 +522,11 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d // Generate debug information Pica::Shader::InterpreterEngine shader_engine; shader_engine.SetupBatch(shader_setup, entry_point); - debug_data = shader_engine.ProduceDebugInfo(shader_setup, input_vertex, num_attributes); + debug_data = shader_engine.ProduceDebugInfo(shader_setup, input_vertex, shader_config); // Reload widget state for (int attr = 0; attr < num_attributes; ++attr) { - unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); + unsigned source_attr = shader_config.GetRegisterForAttribute(attr); input_data_mapping[attr]->setText(QString("-> v%1").arg(source_attr)); input_data_container[attr]->setVisible(true); } diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 27b7a023f..fef0b4ceb 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -151,7 +151,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, static_cast(&immediate_input)); Shader::UnitState shader_unit; - shader_unit.LoadInput(immediate_input, regs.vs.max_input_attribute_index + 1); + shader_unit.LoadInput(regs.vs, immediate_input); shader_engine->Run(g_state.vs, shader_unit); auto output_vertex = Shader::OutputVertex::FromRegisters( shader_unit.registers.output, regs, regs.vs.output_mask); @@ -288,7 +288,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, (void*)&input); - shader_unit.LoadInput(input, loader.GetNumTotalAttributes()); + shader_unit.LoadInput(regs.vs, input); shader_engine->Run(g_state.vs, shader_unit); // Retrieve vertex from register data diff --git a/src/video_core/pica.h b/src/video_core/pica.h index c772896e0..ac81a3d0f 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -1225,36 +1225,15 @@ struct Regs { // Offset to shader program entry point (in words) BitField<0, 16, u32> main_offset; - union { - BitField<0, 4, u64> attribute0_register; - BitField<4, 4, u64> attribute1_register; - BitField<8, 4, u64> attribute2_register; - BitField<12, 4, u64> attribute3_register; - BitField<16, 4, u64> attribute4_register; - BitField<20, 4, u64> attribute5_register; - BitField<24, 4, u64> attribute6_register; - BitField<28, 4, u64> attribute7_register; - BitField<32, 4, u64> attribute8_register; - BitField<36, 4, u64> attribute9_register; - BitField<40, 4, u64> attribute10_register; - BitField<44, 4, u64> attribute11_register; - BitField<48, 4, u64> attribute12_register; - BitField<52, 4, u64> attribute13_register; - BitField<56, 4, u64> attribute14_register; - BitField<60, 4, u64> attribute15_register; - - int GetRegisterForAttribute(int attribute_index) const { - u64 fields[] = { - attribute0_register, attribute1_register, attribute2_register, - attribute3_register, attribute4_register, attribute5_register, - attribute6_register, attribute7_register, attribute8_register, - attribute9_register, attribute10_register, attribute11_register, - attribute12_register, attribute13_register, attribute14_register, - attribute15_register, - }; - return (int)fields[attribute_index]; - } - } input_register_map; + /// Maps input attributes to registers. 4-bits per attribute, specifying a register index + u32 input_attribute_to_register_map_low; + u32 input_attribute_to_register_map_high; + + unsigned int GetRegisterForAttribute(unsigned int attribute_index) const { + u64 map = ((u64)input_attribute_to_register_map_high << 32) | + (u64)input_attribute_to_register_map_low; + return (map >> (attribute_index * 4)) & 0b1111; + } BitField<0, 16, u32> output_mask; diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 971ce5b7a..dbad167e9 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -71,12 +71,13 @@ OutputVertex OutputVertex::FromRegisters(Math::Vec4 output_regs[16], co return ret; } -void UnitState::LoadInput(const AttributeBuffer& input, int num_attributes) { - // Setup input register table - const auto& attribute_register_map = g_state.regs.vs.input_register_map; +void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) { + const unsigned max_attribute = config.max_input_attribute_index; - for (int i = 0; i < num_attributes; i++) - registers.input[attribute_register_map.GetRegisterForAttribute(i)] = input.attr[i]; + for (unsigned attr = 0; attr <= max_attribute; ++attr) { + unsigned reg = config.GetRegisterForAttribute(attr); + registers.input[reg] = input.attr[attr]; + } } MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index cb38ec0a6..43a8b848c 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -137,10 +137,10 @@ struct UnitState { /** * Loads the unit state with an input vertex. * - * @param input Input vertex into the shader - * @param num_attributes The number of vertex shader attributes to load + * @param config Shader configuration registers corresponding to the unit. + * @param input Attribute buffer to load into the input registers. */ - void LoadInput(const AttributeBuffer& input, int num_attributes); + void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input); }; struct ShaderSetup { diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index d803aebbf..81522b8f5 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -669,13 +669,13 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const { DebugData InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input, - int num_attributes) const { + const Regs::ShaderConfig& config) const { UnitState state; DebugData debug_data; // Setup input register table boost::fill(state.registers.input, Math::Vec4::AssignToAll(float24::Zero())); - state.LoadInput(input, num_attributes); + state.LoadInput(config, input); RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point); return debug_data; } diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h index 593e02157..d7a61e122 100644 --- a/src/video_core/shader/shader_interpreter.h +++ b/src/video_core/shader/shader_interpreter.h @@ -19,12 +19,11 @@ public: /** * Produce debug information based on the given shader and input vertex * @param input Input vertex into the shader - * @param num_attributes The number of vertex shader attributes * @param config Configuration object for the shader pipeline * @return Debug information for this shader with regards to the given vertex */ DebugData ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input, - int num_attributes) const; + const Regs::ShaderConfig& config) const; }; } // namespace -- cgit v1.2.3 From 8ed9f9d49f716487f14736c48a7850129a5910ba Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 18 Dec 2016 23:42:29 -0800 Subject: VideoCore/Shader: Clean up OutputVertex::FromAttributeBuffer This also fixes a long-standing but neverthless harmless memory corruption bug, whech the padding of the OutputVertex struct would get corrupted by unused attributes. --- src/video_core/pica.h | 3 ++- src/video_core/shader/shader.cpp | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/video_core/pica.h') diff --git a/src/video_core/pica.h b/src/video_core/pica.h index ac81a3d0f..e326f7727 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -99,7 +99,8 @@ struct Regs { TEXCOORD1_U = 14, TEXCOORD1_V = 15, - // TODO: Not verified + TEXCOORD0_W = 16, + VIEW_X = 18, VIEW_Y = 19, VIEW_Z = 20, diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 99a22c2dd..2c6e45ac4 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -22,23 +22,28 @@ namespace Shader { OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) { // Setup output data - OutputVertex ret; + union { + OutputVertex ret{}; + std::array vertex_slots; + }; + static_assert(sizeof(vertex_slots) <= sizeof(ret), "Struct and array have different sizes."); unsigned int num_attributes = regs.vs_output_total; + ASSERT(num_attributes <= 7); for (unsigned int i = 0; i < num_attributes; ++i) { const auto& output_register_map = regs.vs_output_attributes[i]; - u32 semantics[4] = {output_register_map.map_x, output_register_map.map_y, - output_register_map.map_z, output_register_map.map_w}; + Regs::VSOutputAttributes::Semantic semantics[4] = { + output_register_map.map_x, output_register_map.map_y, output_register_map.map_z, + output_register_map.map_w}; for (unsigned comp = 0; comp < 4; ++comp) { - float24* out = ((float24*)&ret) + semantics[comp]; - if (semantics[comp] != Regs::VSOutputAttributes::INVALID) { + Regs::VSOutputAttributes::Semantic semantic = semantics[comp]; + float24* out = &vertex_slots[semantic]; + if (semantic < vertex_slots.size()) { *out = input.attr[i][comp]; - } else { - // Zero output so that attributes which aren't output won't have denormals in them, - // which would slow us down later. - memset(out, 0, sizeof(*out)); + } else if (semantic != Regs::VSOutputAttributes::INVALID) { + LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic); } } } -- cgit v1.2.3