diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/shader.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/shader/shader.h | 46 |
2 files changed, 84 insertions, 0 deletions
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 67ed19ba8..b12468d3a 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp | |||
| @@ -82,6 +82,44 @@ void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) { | |||
| 82 | } | 82 | } |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | UnitState::UnitState(GSEmitter* emitter) : emitter_ptr(emitter) {} | ||
| 86 | |||
| 87 | GSEmitter::GSEmitter() { | ||
| 88 | handlers = new Handlers; | ||
| 89 | } | ||
| 90 | |||
| 91 | GSEmitter::~GSEmitter() { | ||
| 92 | delete handlers; | ||
| 93 | } | ||
| 94 | |||
| 95 | void GSEmitter::Emit(Math::Vec4<float24> (&vertex)[16]) { | ||
| 96 | ASSERT(vertex_id < 3); | ||
| 97 | std::copy(std::begin(vertex), std::end(vertex), buffer[vertex_id].begin()); | ||
| 98 | if (prim_emit) { | ||
| 99 | if (winding) | ||
| 100 | handlers->winding_setter(); | ||
| 101 | for (size_t i = 0; i < buffer.size(); ++i) { | ||
| 102 | AttributeBuffer output; | ||
| 103 | unsigned int output_i = 0; | ||
| 104 | for (unsigned int reg : Common::BitSet<u32>(output_mask)) { | ||
| 105 | output.attr[output_i++] = buffer[i][reg]; | ||
| 106 | } | ||
| 107 | handlers->vertex_handler(output); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | GSUnitState::GSUnitState() : UnitState(&emitter) {} | ||
| 113 | |||
| 114 | void GSUnitState::SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter) { | ||
| 115 | emitter.handlers->vertex_handler = std::move(vertex_handler); | ||
| 116 | emitter.handlers->winding_setter = std::move(winding_setter); | ||
| 117 | } | ||
| 118 | |||
| 119 | void GSUnitState::ConfigOutput(const ShaderRegs& config) { | ||
| 120 | emitter.output_mask = config.output_mask; | ||
| 121 | } | ||
| 122 | |||
| 85 | MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); | 123 | MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); |
| 86 | 124 | ||
| 87 | #ifdef ARCHITECTURE_x86_64 | 125 | #ifdef ARCHITECTURE_x86_64 |
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index e156f6aef..caec96043 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <functional> | ||
| 9 | #include <type_traits> | 10 | #include <type_traits> |
| 10 | #include <nihstro/shader_bytecode.h> | 11 | #include <nihstro/shader_bytecode.h> |
| 11 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| @@ -31,6 +32,12 @@ struct AttributeBuffer { | |||
| 31 | alignas(16) Math::Vec4<float24> attr[16]; | 32 | alignas(16) Math::Vec4<float24> attr[16]; |
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| 35 | /// Handler type for receiving vertex outputs from vertex shader or geometry shader | ||
| 36 | using VertexHandler = std::function<void(const AttributeBuffer&)>; | ||
| 37 | |||
| 38 | /// Handler type for signaling to invert the vertex order of the next triangle | ||
| 39 | using WindingSetter = std::function<void()>; | ||
| 40 | |||
| 34 | struct OutputVertex { | 41 | struct OutputVertex { |
| 35 | Math::Vec4<float24> pos; | 42 | Math::Vec4<float24> pos; |
| 36 | Math::Vec4<float24> quat; | 43 | Math::Vec4<float24> quat; |
| @@ -61,12 +68,36 @@ static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | |||
| 61 | static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); | 68 | static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); |
| 62 | 69 | ||
| 63 | /** | 70 | /** |
| 71 | * This structure contains state information for primitive emitting in geometry shader. | ||
| 72 | */ | ||
| 73 | struct GSEmitter { | ||
| 74 | std::array<std::array<Math::Vec4<float24>, 16>, 3> buffer; | ||
| 75 | u8 vertex_id; | ||
| 76 | bool prim_emit; | ||
| 77 | bool winding; | ||
| 78 | u32 output_mask; | ||
| 79 | |||
| 80 | // Function objects are hidden behind a raw pointer to make the structure standard layout type, | ||
| 81 | // for JIT to use offsetof to access other members. | ||
| 82 | struct Handlers { | ||
| 83 | VertexHandler vertex_handler; | ||
| 84 | WindingSetter winding_setter; | ||
| 85 | } * handlers; | ||
| 86 | |||
| 87 | GSEmitter(); | ||
| 88 | ~GSEmitter(); | ||
| 89 | void Emit(Math::Vec4<float24> (&vertex)[16]); | ||
| 90 | }; | ||
| 91 | static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type"); | ||
| 92 | |||
| 93 | /** | ||
| 64 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS | 94 | * This structure contains the state information that needs to be unique for a shader unit. The 3DS |
| 65 | * has four shader units that process shaders in parallel. At the present, Citra only implements a | 95 | * has four shader units that process shaders in parallel. At the present, Citra only implements a |
| 66 | * single shader unit that processes all shaders serially. Putting the state information in a struct | 96 | * single shader unit that processes all shaders serially. Putting the state information in a struct |
| 67 | * here will make it easier for us to parallelize the shader processing later. | 97 | * here will make it easier for us to parallelize the shader processing later. |
| 68 | */ | 98 | */ |
| 69 | struct UnitState { | 99 | struct UnitState { |
| 100 | explicit UnitState(GSEmitter* emitter = nullptr); | ||
| 70 | struct Registers { | 101 | struct Registers { |
| 71 | // The registers are accessed by the shader JIT using SSE instructions, and are therefore | 102 | // The registers are accessed by the shader JIT using SSE instructions, and are therefore |
| 72 | // required to be 16-byte aligned. | 103 | // required to be 16-byte aligned. |
| @@ -82,6 +113,8 @@ struct UnitState { | |||
| 82 | // TODO: How many bits do these actually have? | 113 | // TODO: How many bits do these actually have? |
| 83 | s32 address_registers[3]; | 114 | s32 address_registers[3]; |
| 84 | 115 | ||
| 116 | GSEmitter* emitter_ptr; | ||
| 117 | |||
| 85 | static size_t InputOffset(const SourceRegister& reg) { | 118 | static size_t InputOffset(const SourceRegister& reg) { |
| 86 | switch (reg.GetRegisterType()) { | 119 | switch (reg.GetRegisterType()) { |
| 87 | case RegisterType::Input: | 120 | case RegisterType::Input: |
| @@ -125,6 +158,19 @@ struct UnitState { | |||
| 125 | void WriteOutput(const ShaderRegs& config, AttributeBuffer& output); | 158 | void WriteOutput(const ShaderRegs& config, AttributeBuffer& output); |
| 126 | }; | 159 | }; |
| 127 | 160 | ||
| 161 | /** | ||
| 162 | * This is an extended shader unit state that represents the special unit that can run both vertex | ||
| 163 | * shader and geometry shader. It contains an additional primitive emitter and utilities for | ||
| 164 | * geometry shader. | ||
| 165 | */ | ||
| 166 | struct GSUnitState : public UnitState { | ||
| 167 | GSUnitState(); | ||
| 168 | void SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter); | ||
| 169 | void ConfigOutput(const ShaderRegs& config); | ||
| 170 | |||
| 171 | GSEmitter emitter; | ||
| 172 | }; | ||
| 173 | |||
| 128 | struct ShaderSetup { | 174 | struct ShaderSetup { |
| 129 | struct { | 175 | struct { |
| 130 | // The float uniforms are accessed by the shader JIT using SSE instructions, and are | 176 | // The float uniforms are accessed by the shader JIT using SSE instructions, and are |