diff options
Diffstat (limited to 'src/video_core/shader')
| -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) {      }  } +UnitState::UnitState(GSEmitter* emitter) : emitter_ptr(emitter) {} + +GSEmitter::GSEmitter() { +    handlers = new Handlers; +} + +GSEmitter::~GSEmitter() { +    delete handlers; +} + +void GSEmitter::Emit(Math::Vec4<float24> (&vertex)[16]) { +    ASSERT(vertex_id < 3); +    std::copy(std::begin(vertex), std::end(vertex), buffer[vertex_id].begin()); +    if (prim_emit) { +        if (winding) +            handlers->winding_setter(); +        for (size_t i = 0; i < buffer.size(); ++i) { +            AttributeBuffer output; +            unsigned int output_i = 0; +            for (unsigned int reg : Common::BitSet<u32>(output_mask)) { +                output.attr[output_i++] = buffer[i][reg]; +            } +            handlers->vertex_handler(output); +        } +    } +} + +GSUnitState::GSUnitState() : UnitState(&emitter) {} + +void GSUnitState::SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter) { +    emitter.handlers->vertex_handler = std::move(vertex_handler); +    emitter.handlers->winding_setter = std::move(winding_setter); +} + +void GSUnitState::ConfigOutput(const ShaderRegs& config) { +    emitter.output_mask = config.output_mask; +} +  MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));  #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 @@  #include <array>  #include <cstddef> +#include <functional>  #include <type_traits>  #include <nihstro/shader_bytecode.h>  #include "common/assert.h" @@ -31,6 +32,12 @@ struct AttributeBuffer {      alignas(16) Math::Vec4<float24> attr[16];  }; +/// Handler type for receiving vertex outputs from vertex shader or geometry shader +using VertexHandler = std::function<void(const AttributeBuffer&)>; + +/// Handler type for signaling to invert the vertex order of the next triangle +using WindingSetter = std::function<void()>; +  struct OutputVertex {      Math::Vec4<float24> pos;      Math::Vec4<float24> quat; @@ -61,12 +68,36 @@ static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");  static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");  /** + * This structure contains state information for primitive emitting in geometry shader. + */ +struct GSEmitter { +    std::array<std::array<Math::Vec4<float24>, 16>, 3> buffer; +    u8 vertex_id; +    bool prim_emit; +    bool winding; +    u32 output_mask; + +    // Function objects are hidden behind a raw pointer to make the structure standard layout type, +    // for JIT to use offsetof to access other members. +    struct Handlers { +        VertexHandler vertex_handler; +        WindingSetter winding_setter; +    } * handlers; + +    GSEmitter(); +    ~GSEmitter(); +    void Emit(Math::Vec4<float24> (&vertex)[16]); +}; +static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type"); + +/**   * This structure contains the state information that needs to be unique for a shader unit. The 3DS   * has four shader units that process shaders in parallel. At the present, Citra only implements a   * single shader unit that processes all shaders serially. Putting the state information in a struct   * here will make it easier for us to parallelize the shader processing later.   */  struct UnitState { +    explicit UnitState(GSEmitter* emitter = nullptr);      struct Registers {          // The registers are accessed by the shader JIT using SSE instructions, and are therefore          // required to be 16-byte aligned. @@ -82,6 +113,8 @@ struct UnitState {      // TODO: How many bits do these actually have?      s32 address_registers[3]; +    GSEmitter* emitter_ptr; +      static size_t InputOffset(const SourceRegister& reg) {          switch (reg.GetRegisterType()) {          case RegisterType::Input: @@ -125,6 +158,19 @@ struct UnitState {      void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);  }; +/** + * This is an extended shader unit state that represents the special unit that can run both vertex + * shader and geometry shader. It contains an additional primitive emitter and utilities for + * geometry shader. + */ +struct GSUnitState : public UnitState { +    GSUnitState(); +    void SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter); +    void ConfigOutput(const ShaderRegs& config); + +    GSEmitter emitter; +}; +  struct ShaderSetup {      struct {          // The float uniforms are accessed by the shader JIT using SSE instructions, and are | 
