diff options
author | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2017-01-28 21:34:31 +0100 |
---|---|---|
committer | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2017-02-04 22:59:11 +0100 |
commit | 8fca90b5d56892758a98a0ece15b5845009893e3 (patch) | |
tree | 16cc7c03687ec58c209c90e5d54f34a2eb9dcf74 | |
parent | VideoCore: Split lighting regs from Regs struct (diff) | |
download | yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.gz yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.bz2 yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.lz yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.xz yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.zst yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.zip |
-rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/video_core/command_processor.cpp | 51 | ||||
-rw-r--r-- | src/video_core/pica.cpp | 2 | ||||
-rw-r--r-- | src/video_core/pica.h | 230 | ||||
-rw-r--r-- | src/video_core/primitive_assembly.cpp | 18 | ||||
-rw-r--r-- | src/video_core/primitive_assembly.h | 9 | ||||
-rw-r--r-- | src/video_core/regs_pipeline.h | 224 | ||||
-rw-r--r-- | src/video_core/vertex_loader.cpp | 15 | ||||
-rw-r--r-- | src/video_core/vertex_loader.h | 6 |
9 files changed, 292 insertions, 264 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3c6ea42be..c8d2675ae 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -34,6 +34,7 @@ set(HEADERS rasterizer_interface.h regs_framebuffer.h regs_lighting.h + regs_pipeline.h regs_rasterizer.h regs_texturing.h renderer_base.h diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index fa3432f60..c8064bf6a 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -74,23 +74,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); break; - case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): - g_state.primitive_assembler.Reconfigure(regs.triangle_topology); + case PICA_REG_INDEX(pipeline.triangle_topology): + g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology); break; - case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): + case PICA_REG_INDEX(pipeline.restart_primitive): g_state.primitive_assembler.Reset(); break; - case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): + case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index): g_state.immediate.current_attribute = 0; default_attr_counter = 0; break; // Load default vertex input attributes - case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): - case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): - case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): { + case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233): + case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234): + case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): { // TODO: Does actual hardware indeed keep an intermediate buffer or does // it directly write the values? default_attr_write_buffer[default_attr_counter++] = value; @@ -102,7 +102,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { if (default_attr_counter >= 3) { default_attr_counter = 0; - auto& setup = regs.vs_default_attributes_setup; + auto& setup = regs.pipeline.vs_default_attributes_setup; if (setup.index >= 16) { LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); @@ -137,7 +137,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { immediate_input.attr[immediate_attribute_id] = attribute; - if (immediate_attribute_id < regs.max_input_attrib_index) { + if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) { immediate_attribute_id += 1; } else { MICROPROFILE_SCOPE(GPU_Drawing); @@ -173,8 +173,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { break; } - case PICA_REG_INDEX(gpu_mode): - if (regs.gpu_mode == Regs::GPUMode::Configuring) { + case PICA_REG_INDEX(pipeline.gpu_mode): + if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) { MICROPROFILE_SCOPE(GPU_Drawing); // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring @@ -186,19 +186,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { } break; - case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): - case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): { - unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); - u32* head_ptr = - (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); + case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c): + case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): { + unsigned index = + static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0])); + u32* head_ptr = (u32*)Memory::GetPhysicalPointer( + regs.pipeline.command_buffer.GetPhysicalAddress(index)); g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; - g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); + g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32); break; } // It seems like these trigger vertex rendering - case PICA_REG_INDEX(trigger_draw): - case PICA_REG_INDEX(trigger_draw_indexed): { + case PICA_REG_INDEX(pipeline.trigger_draw): + case PICA_REG_INDEX(pipeline.trigger_draw_indexed): { MICROPROFILE_SCOPE(GPU_Drawing); #if PICA_LOG_TEV @@ -210,13 +211,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // Processes information about internal vertex attributes to figure out how a vertex is // loaded. // Later, these can be compiled and cached. - const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress(); - VertexLoader loader(regs); + const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress(); + VertexLoader loader(regs.pipeline); // Load vertices - bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); + bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); - const auto& index_info = regs.index_array; + const auto& index_info = regs.pipeline.index_array; const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8); bool index_u16 = index_info.format != 0; @@ -254,11 +255,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); - for (unsigned int index = 0; index < regs.num_vertices; ++index) { + for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) { // Indexed rendering doesn't use the start offset unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) - : (index + regs.vertex_offset); + : (index + regs.pipeline.vertex_offset); // -1 is a common special value used for primitive restart. Since it's unknown if // the PICA supports it, and it would mess up the caching, guard against it here. diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index b4a77c632..6604ce83c 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp @@ -513,6 +513,6 @@ void State::Reset() { Zero(gs); Zero(cmd_list); Zero(immediate); - primitive_assembler.Reconfigure(Regs::TriangleTopology::List); + primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List); } } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 371bcdb84..765fa5dd4 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -20,6 +20,7 @@ #include "common/vector_math.h" #include "video_core/regs_framebuffer.h" #include "video_core/regs_lighting.h" +#include "video_core/regs_pipeline.h" #include "video_core/regs_rasterizer.h" #include "video_core/regs_texturing.h" @@ -55,210 +56,7 @@ struct Regs { TexturingRegs texturing; FramebufferRegs framebuffer; LightingRegs lighting; - - enum class VertexAttributeFormat : u64 { - BYTE = 0, - UBYTE = 1, - SHORT = 2, - FLOAT = 3, - }; - - struct { - BitField<0, 29, u32> base_address; - - u32 GetPhysicalBaseAddress() const { - return DecodeAddressRegister(base_address); - } - - // Descriptor for internal vertex attributes - union { - BitField<0, 2, VertexAttributeFormat> format0; // size of one element - BitField<2, 2, u64> size0; // number of elements minus 1 - BitField<4, 2, VertexAttributeFormat> format1; - BitField<6, 2, u64> size1; - BitField<8, 2, VertexAttributeFormat> format2; - BitField<10, 2, u64> size2; - BitField<12, 2, VertexAttributeFormat> format3; - BitField<14, 2, u64> size3; - BitField<16, 2, VertexAttributeFormat> format4; - BitField<18, 2, u64> size4; - BitField<20, 2, VertexAttributeFormat> format5; - BitField<22, 2, u64> size5; - BitField<24, 2, VertexAttributeFormat> format6; - BitField<26, 2, u64> size6; - BitField<28, 2, VertexAttributeFormat> format7; - BitField<30, 2, u64> size7; - BitField<32, 2, VertexAttributeFormat> format8; - BitField<34, 2, u64> size8; - BitField<36, 2, VertexAttributeFormat> format9; - BitField<38, 2, u64> size9; - BitField<40, 2, VertexAttributeFormat> format10; - BitField<42, 2, u64> size10; - BitField<44, 2, VertexAttributeFormat> format11; - BitField<46, 2, u64> size11; - - BitField<48, 12, u64> attribute_mask; - - // number of total attributes minus 1 - BitField<60, 4, u64> max_attribute_index; - }; - - inline VertexAttributeFormat GetFormat(int n) const { - VertexAttributeFormat formats[] = {format0, format1, format2, format3, - format4, format5, format6, format7, - format8, format9, format10, format11}; - return formats[n]; - } - - inline int GetNumElements(int n) const { - u64 sizes[] = {size0, size1, size2, size3, size4, size5, - size6, size7, size8, size9, size10, size11}; - return (int)sizes[n] + 1; - } - - inline int GetElementSizeInBytes(int n) const { - return (GetFormat(n) == VertexAttributeFormat::FLOAT) - ? 4 - : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1; - } - - inline int GetStride(int n) const { - return GetNumElements(n) * GetElementSizeInBytes(n); - } - - inline bool IsDefaultAttribute(int id) const { - return (id >= 12) || (attribute_mask & (1ULL << id)) != 0; - } - - inline int GetNumTotalAttributes() const { - return (int)max_attribute_index + 1; - } - - // Attribute loaders map the source vertex data to input attributes - // This e.g. allows to load different attributes from different memory locations - struct { - // Source attribute data offset from the base address - u32 data_offset; - - union { - BitField<0, 4, u64> comp0; - BitField<4, 4, u64> comp1; - BitField<8, 4, u64> comp2; - BitField<12, 4, u64> comp3; - BitField<16, 4, u64> comp4; - BitField<20, 4, u64> comp5; - BitField<24, 4, u64> comp6; - BitField<28, 4, u64> comp7; - BitField<32, 4, u64> comp8; - BitField<36, 4, u64> comp9; - BitField<40, 4, u64> comp10; - BitField<44, 4, u64> comp11; - - // bytes for a single vertex in this loader - BitField<48, 8, u64> byte_count; - - BitField<60, 4, u64> component_count; - }; - - inline int GetComponent(int n) const { - u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5, - comp6, comp7, comp8, comp9, comp10, comp11}; - return (int)components[n]; - } - } attribute_loaders[12]; - } vertex_attributes; - - struct { - enum IndexFormat : u32 { - BYTE = 0, - SHORT = 1, - }; - - union { - BitField<0, 31, u32> offset; // relative to base attribute address - BitField<31, 1, IndexFormat> format; - }; - } index_array; - - // Number of vertices to render - u32 num_vertices; - - INSERT_PADDING_WORDS(0x1); - - // The index of the first vertex to render - u32 vertex_offset; - - INSERT_PADDING_WORDS(0x3); - - // These two trigger rendering of triangles - u32 trigger_draw; - u32 trigger_draw_indexed; - - INSERT_PADDING_WORDS(0x2); - - // These registers are used to setup the default "fall-back" vertex shader attributes - struct { - // Index of the current default attribute - u32 index; - - // Writing to these registers sets the "current" default attribute. - u32 set_value[3]; - } vs_default_attributes_setup; - - INSERT_PADDING_WORDS(0x2); - - struct { - // There are two channels that can be used to configure the next command buffer, which - // can be then executed by writing to the "trigger" registers. There are two reasons why a - // game might use this feature: - // 1) With this, an arbitrary number of additional command buffers may be executed in - // sequence without requiring any intervention of the CPU after the initial one is - // kicked off. - // 2) Games can configure these registers to provide a command list subroutine mechanism. - - BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer - BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer - u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to - - unsigned GetSize(unsigned index) const { - ASSERT(index < 2); - return 8 * size[index]; - } - - PAddr GetPhysicalAddress(unsigned index) const { - ASSERT(index < 2); - return (PAddr)(8 * addr[index]); - } - } command_buffer; - - 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, - Configuring = 1, - }; - - GPUMode gpu_mode; - - INSERT_PADDING_WORDS(0x18); - - enum class TriangleTopology : u32 { - List = 0, - Strip = 1, - Fan = 2, - Shader = 3, // Programmable setup unit implemented in a geometry shader - }; - - BitField<8, 2, TriangleTopology> triangle_topology; - - u32 restart_primitive; - - INSERT_PADDING_WORDS(0x20); + PipelineRegs pipeline; struct ShaderConfig { BitField<0, 16, u32> bool_uniforms; @@ -430,17 +228,19 @@ ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110); ASSERT_REG_POSITION(lighting, 0x140); -ASSERT_REG_POSITION(vertex_attributes, 0x200); -ASSERT_REG_POSITION(index_array, 0x227); -ASSERT_REG_POSITION(num_vertices, 0x228); -ASSERT_REG_POSITION(vertex_offset, 0x22a); -ASSERT_REG_POSITION(trigger_draw, 0x22e); -ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); -ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); -ASSERT_REG_POSITION(command_buffer, 0x238); -ASSERT_REG_POSITION(gpu_mode, 0x245); -ASSERT_REG_POSITION(triangle_topology, 0x25e); -ASSERT_REG_POSITION(restart_primitive, 0x25f); +ASSERT_REG_POSITION(pipeline, 0x200); +ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200); +ASSERT_REG_POSITION(pipeline.index_array, 0x227); +ASSERT_REG_POSITION(pipeline.num_vertices, 0x228); +ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a); +ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e); +ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f); +ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232); +ASSERT_REG_POSITION(pipeline.command_buffer, 0x238); +ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245); +ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e); +ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f); + ASSERT_REG_POSITION(gs, 0x280); ASSERT_REG_POSITION(vs, 0x2b0); diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp index e71ff5719..acd2ac5e2 100644 --- a/src/video_core/primitive_assembly.cpp +++ b/src/video_core/primitive_assembly.cpp @@ -3,14 +3,14 @@ // Refer to the license.txt file included. #include "common/logging/log.h" -#include "video_core/pica.h" #include "video_core/primitive_assembly.h" +#include "video_core/regs_pipeline.h" #include "video_core/shader/shader.h" namespace Pica { template <typename VertexType> -PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology) +PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology) : topology(topology), buffer_index(0) {} template <typename VertexType> @@ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, TriangleHandler triangle_handler) { switch (topology) { // TODO: Figure out what's different with TriangleTopology::Shader. - case Regs::TriangleTopology::List: - case Regs::TriangleTopology::Shader: + case PipelineRegs::TriangleTopology::List: + case PipelineRegs::TriangleTopology::Shader: if (buffer_index < 2) { buffer[buffer_index++] = vtx; } else { @@ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, } break; - case Regs::TriangleTopology::Strip: - case Regs::TriangleTopology::Fan: + case PipelineRegs::TriangleTopology::Strip: + case PipelineRegs::TriangleTopology::Fan: if (strip_ready) triangle_handler(buffer[0], buffer[1], vtx); @@ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, strip_ready |= (buffer_index == 1); - if (topology == Regs::TriangleTopology::Strip) + if (topology == PipelineRegs::TriangleTopology::Strip) buffer_index = !buffer_index; - else if (topology == Regs::TriangleTopology::Fan) + else if (topology == PipelineRegs::TriangleTopology::Fan) buffer_index = 1; break; @@ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() { } template <typename VertexType> -void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) { +void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) { Reset(); this->topology = topology; } diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h index 24da47382..e8eccdf27 100644 --- a/src/video_core/primitive_assembly.h +++ b/src/video_core/primitive_assembly.h @@ -5,7 +5,7 @@ #pragma once #include <functional> -#include "video_core/pica.h" +#include "video_core/regs_pipeline.h" namespace Pica { @@ -18,7 +18,8 @@ struct PrimitiveAssembler { using TriangleHandler = std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>; - PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List); + PrimitiveAssembler( + PipelineRegs::TriangleTopology topology = PipelineRegs::TriangleTopology::List); /* * Queues a vertex, builds primitives from the vertex queue according to the given @@ -36,10 +37,10 @@ struct PrimitiveAssembler { /** * Reconfigures the PrimitiveAssembler to use a different triangle topology. */ - void Reconfigure(Regs::TriangleTopology topology); + void Reconfigure(PipelineRegs::TriangleTopology topology); private: - Regs::TriangleTopology topology; + PipelineRegs::TriangleTopology topology; int buffer_index; VertexType buffer[2]; diff --git a/src/video_core/regs_pipeline.h b/src/video_core/regs_pipeline.h new file mode 100644 index 000000000..5844a66ee --- /dev/null +++ b/src/video_core/regs_pipeline.h @@ -0,0 +1,224 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> + +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Pica { + +struct PipelineRegs { + enum class VertexAttributeFormat : u64 { + BYTE = 0, + UBYTE = 1, + SHORT = 2, + FLOAT = 3, + }; + + struct { + BitField<0, 29, u32> base_address; + + PAddr GetPhysicalBaseAddress() const { + return base_address * 8; + } + + // Descriptor for internal vertex attributes + union { + BitField<0, 2, VertexAttributeFormat> format0; // size of one element + BitField<2, 2, u64> size0; // number of elements minus 1 + BitField<4, 2, VertexAttributeFormat> format1; + BitField<6, 2, u64> size1; + BitField<8, 2, VertexAttributeFormat> format2; + BitField<10, 2, u64> size2; + BitField<12, 2, VertexAttributeFormat> format3; + BitField<14, 2, u64> size3; + BitField<16, 2, VertexAttributeFormat> format4; + BitField<18, 2, u64> size4; + BitField<20, 2, VertexAttributeFormat> format5; + BitField<22, 2, u64> size5; + BitField<24, 2, VertexAttributeFormat> format6; + BitField<26, 2, u64> size6; + BitField<28, 2, VertexAttributeFormat> format7; + BitField<30, 2, u64> size7; + BitField<32, 2, VertexAttributeFormat> format8; + BitField<34, 2, u64> size8; + BitField<36, 2, VertexAttributeFormat> format9; + BitField<38, 2, u64> size9; + BitField<40, 2, VertexAttributeFormat> format10; + BitField<42, 2, u64> size10; + BitField<44, 2, VertexAttributeFormat> format11; + BitField<46, 2, u64> size11; + + BitField<48, 12, u64> attribute_mask; + + // number of total attributes minus 1 + BitField<60, 4, u64> max_attribute_index; + }; + + inline VertexAttributeFormat GetFormat(int n) const { + VertexAttributeFormat formats[] = {format0, format1, format2, format3, + format4, format5, format6, format7, + format8, format9, format10, format11}; + return formats[n]; + } + + inline int GetNumElements(int n) const { + u64 sizes[] = {size0, size1, size2, size3, size4, size5, + size6, size7, size8, size9, size10, size11}; + return (int)sizes[n] + 1; + } + + inline int GetElementSizeInBytes(int n) const { + return (GetFormat(n) == VertexAttributeFormat::FLOAT) + ? 4 + : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1; + } + + inline int GetStride(int n) const { + return GetNumElements(n) * GetElementSizeInBytes(n); + } + + inline bool IsDefaultAttribute(int id) const { + return (id >= 12) || (attribute_mask & (1ULL << id)) != 0; + } + + inline int GetNumTotalAttributes() const { + return (int)max_attribute_index + 1; + } + + // Attribute loaders map the source vertex data to input attributes + // This e.g. allows to load different attributes from different memory locations + struct { + // Source attribute data offset from the base address + u32 data_offset; + + union { + BitField<0, 4, u64> comp0; + BitField<4, 4, u64> comp1; + BitField<8, 4, u64> comp2; + BitField<12, 4, u64> comp3; + BitField<16, 4, u64> comp4; + BitField<20, 4, u64> comp5; + BitField<24, 4, u64> comp6; + BitField<28, 4, u64> comp7; + BitField<32, 4, u64> comp8; + BitField<36, 4, u64> comp9; + BitField<40, 4, u64> comp10; + BitField<44, 4, u64> comp11; + + // bytes for a single vertex in this loader + BitField<48, 8, u64> byte_count; + + BitField<60, 4, u64> component_count; + }; + + inline int GetComponent(int n) const { + u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5, + comp6, comp7, comp8, comp9, comp10, comp11}; + return (int)components[n]; + } + } attribute_loaders[12]; + } vertex_attributes; + + struct { + enum IndexFormat : u32 { + BYTE = 0, + SHORT = 1, + }; + + union { + BitField<0, 31, u32> offset; // relative to base attribute address + BitField<31, 1, IndexFormat> format; + }; + } index_array; + + // Number of vertices to render + u32 num_vertices; + + INSERT_PADDING_WORDS(0x1); + + // The index of the first vertex to render + u32 vertex_offset; + + INSERT_PADDING_WORDS(0x3); + + // These two trigger rendering of triangles + u32 trigger_draw; + u32 trigger_draw_indexed; + + INSERT_PADDING_WORDS(0x2); + + // These registers are used to setup the default "fall-back" vertex shader attributes + struct { + // Index of the current default attribute + u32 index; + + // Writing to these registers sets the "current" default attribute. + u32 set_value[3]; + } vs_default_attributes_setup; + + INSERT_PADDING_WORDS(0x2); + + struct { + // There are two channels that can be used to configure the next command buffer, which can + // be then executed by writing to the "trigger" registers. There are two reasons why a game + // might use this feature: + // 1) With this, an arbitrary number of additional command buffers may be executed in + // sequence without requiring any intervention of the CPU after the initial one is + // kicked off. + // 2) Games can configure these registers to provide a command list subroutine mechanism. + + BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer + BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer + u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to + + unsigned GetSize(unsigned index) const { + ASSERT(index < 2); + return 8 * size[index]; + } + + PAddr GetPhysicalAddress(unsigned index) const { + ASSERT(index < 2); + return (PAddr)(8 * addr[index]); + } + } command_buffer; + + 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, + Configuring = 1, + }; + + GPUMode gpu_mode; + + INSERT_PADDING_WORDS(0x18); + + enum class TriangleTopology : u32 { + List = 0, + Strip = 1, + Fan = 2, + Shader = 3, // Programmable setup unit implemented in a geometry shader + }; + + BitField<8, 2, TriangleTopology> triangle_topology; + + u32 restart_primitive; + + INSERT_PADDING_WORDS(0x20); +}; + +static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size"); + +} // namespace Pica diff --git a/src/video_core/vertex_loader.cpp b/src/video_core/vertex_loader.cpp index bf83b61ca..20e2370be 100644 --- a/src/video_core/vertex_loader.cpp +++ b/src/video_core/vertex_loader.cpp @@ -16,7 +16,7 @@ namespace Pica { -void VertexLoader::Setup(const Pica::Regs& regs) { +void VertexLoader::Setup(const PipelineRegs& regs) { ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once."); const auto& attribute_config = regs.vertex_attributes; @@ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, memory_accesses.AddAccess( source_addr, vertex_attribute_elements[i] * - ((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) + ((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT) ? 4 - : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) + : (vertex_attribute_formats[i] == + PipelineRegs::VertexAttributeFormat::SHORT) ? 2 : 1)); } switch (vertex_attribute_formats[i]) { - case Regs::VertexAttributeFormat::BYTE: { + case PipelineRegs::VertexAttributeFormat::BYTE: { const s8* srcdata = reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr)); for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { @@ -101,7 +102,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, } break; } - case Regs::VertexAttributeFormat::UBYTE: { + case PipelineRegs::VertexAttributeFormat::UBYTE: { const u8* srcdata = reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr)); for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { @@ -109,7 +110,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, } break; } - case Regs::VertexAttributeFormat::SHORT: { + case PipelineRegs::VertexAttributeFormat::SHORT: { const s16* srcdata = reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr)); for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { @@ -117,7 +118,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, } break; } - case Regs::VertexAttributeFormat::FLOAT: { + case PipelineRegs::VertexAttributeFormat::FLOAT: { const float* srcdata = reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr)); for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { diff --git a/src/video_core/vertex_loader.h b/src/video_core/vertex_loader.h index 51f3d45b4..7815715bc 100644 --- a/src/video_core/vertex_loader.h +++ b/src/video_core/vertex_loader.h @@ -17,11 +17,11 @@ struct AttributeBuffer; class VertexLoader { public: VertexLoader() = default; - explicit VertexLoader(const Pica::Regs& regs) { + explicit VertexLoader(const PipelineRegs& regs) { Setup(regs); } - void Setup(const Pica::Regs& regs); + void Setup(const PipelineRegs& regs); void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, DebugUtils::MemoryAccessTracker& memory_accesses); @@ -32,7 +32,7 @@ public: private: std::array<u32, 16> vertex_attribute_sources; std::array<u32, 16> vertex_attribute_strides{}; - std::array<Regs::VertexAttributeFormat, 16> vertex_attribute_formats; + std::array<PipelineRegs::VertexAttributeFormat, 16> vertex_attribute_formats; std::array<u32, 16> vertex_attribute_elements{}; std::array<bool, 16> vertex_attribute_is_default; int num_total_attributes = 0; |