diff options
Diffstat (limited to 'src/video_core/geometry_pipeline.cpp')
-rw-r--r-- | src/video_core/geometry_pipeline.cpp | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/src/video_core/geometry_pipeline.cpp b/src/video_core/geometry_pipeline.cpp deleted file mode 100644 index 98ff2ccd38..0000000000 --- a/src/video_core/geometry_pipeline.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "video_core/geometry_pipeline.h" -#include "video_core/pica_state.h" -#include "video_core/regs.h" -#include "video_core/renderer_base.h" -#include "video_core/video_core.h" - -namespace Pica { - -/// An attribute buffering interface for different pipeline modes -class GeometryPipelineBackend { -public: - virtual ~GeometryPipelineBackend() = default; - - /// Checks if there is no incomplete data transfer - virtual bool IsEmpty() const = 0; - - /// Checks if the pipeline needs a direct input from index buffer - virtual bool NeedIndexInput() const = 0; - - /// Submits an index from index buffer - virtual void SubmitIndex(unsigned int val) = 0; - - /** - * Submits vertex attributes - * @param input attributes of a vertex output from vertex shader - * @return if the buffer is full and the geometry shader should be invoked - */ - virtual bool SubmitVertex(const Shader::AttributeBuffer& input) = 0; -}; - -// In the Point mode, vertex attributes are sent to the input registers in the geometry shader unit. -// The size of vertex shader outputs and geometry shader inputs are constants. Geometry shader is -// invoked upon inputs buffer filled up by vertex shader outputs. For example, if we have a geometry -// shader that takes 6 inputs, and the vertex shader outputs 2 attributes, it would take 3 vertices -// for one geometry shader invocation. -// TODO: what happens when the input size is not divisible by the output size? -class GeometryPipeline_Point : public GeometryPipelineBackend { -public: - GeometryPipeline_Point(const Regs& regs, Shader::GSUnitState& unit) : regs(regs), unit(unit) { - ASSERT(regs.pipeline.variable_primitive == 0); - ASSERT(regs.gs.input_to_uniform == 0); - vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1; - size_t gs_input_num = regs.gs.max_input_attribute_index + 1; - ASSERT(gs_input_num % vs_output_num == 0); - buffer_cur = attribute_buffer.attr; - buffer_end = attribute_buffer.attr + gs_input_num; - } - - bool IsEmpty() const override { - return buffer_cur == attribute_buffer.attr; - } - - bool NeedIndexInput() const override { - return false; - } - - void SubmitIndex(unsigned int val) override { - UNREACHABLE(); - } - - bool SubmitVertex(const Shader::AttributeBuffer& input) override { - buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur); - if (buffer_cur == buffer_end) { - buffer_cur = attribute_buffer.attr; - unit.LoadInput(regs.gs, attribute_buffer); - return true; - } - return false; - } - -private: - const Regs& regs; - Shader::GSUnitState& unit; - Shader::AttributeBuffer attribute_buffer; - Math::Vec4<float24>* buffer_cur; - Math::Vec4<float24>* buffer_end; - unsigned int vs_output_num; -}; - -// In VariablePrimitive mode, vertex attributes are buffered into the uniform registers in the -// geometry shader unit. The number of vertex is variable, which is specified by the first index -// value in the batch. This mode is usually used for subdivision. -class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend { -public: - GeometryPipeline_VariablePrimitive(const Regs& regs, Shader::ShaderSetup& setup) - : regs(regs), setup(setup) { - ASSERT(regs.pipeline.variable_primitive == 1); - ASSERT(regs.gs.input_to_uniform == 1); - vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1; - } - - bool IsEmpty() const override { - return need_index; - } - - bool NeedIndexInput() const override { - return need_index; - } - - void SubmitIndex(unsigned int val) override { - DEBUG_ASSERT(need_index); - - // The number of vertex input is put to the uniform register - float24 vertex_num = float24::FromFloat32(static_cast<float>(val)); - setup.uniforms.f[0] = Math::MakeVec(vertex_num, vertex_num, vertex_num, vertex_num); - - // The second uniform register and so on are used for receiving input vertices - buffer_cur = setup.uniforms.f + 1; - - main_vertex_num = regs.pipeline.variable_vertex_main_num_minus_1 + 1; - total_vertex_num = val; - need_index = false; - } - - bool SubmitVertex(const Shader::AttributeBuffer& input) override { - DEBUG_ASSERT(!need_index); - if (main_vertex_num != 0) { - // For main vertices, receive all attributes - buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur); - --main_vertex_num; - } else { - // For other vertices, only receive the first attribute (usually the position) - *(buffer_cur++) = input.attr[0]; - } - --total_vertex_num; - - if (total_vertex_num == 0) { - need_index = true; - return true; - } - - return false; - } - -private: - bool need_index = true; - const Regs& regs; - Shader::ShaderSetup& setup; - unsigned int main_vertex_num; - unsigned int total_vertex_num; - Math::Vec4<float24>* buffer_cur; - unsigned int vs_output_num; -}; - -// In FixedPrimitive mode, vertex attributes are buffered into the uniform registers in the geometry -// shader unit. The number of vertex per shader invocation is constant. This is usually used for -// particle system. -class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend { -public: - GeometryPipeline_FixedPrimitive(const Regs& regs, Shader::ShaderSetup& setup) - : regs(regs), setup(setup) { - ASSERT(regs.pipeline.variable_primitive == 0); - ASSERT(regs.gs.input_to_uniform == 1); - vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1; - ASSERT(vs_output_num == regs.pipeline.gs_config.stride_minus_1 + 1); - size_t vertex_num = regs.pipeline.gs_config.fixed_vertex_num_minus_1 + 1; - buffer_cur = buffer_begin = setup.uniforms.f + regs.pipeline.gs_config.start_index; - buffer_end = buffer_begin + vs_output_num * vertex_num; - } - - bool IsEmpty() const override { - return buffer_cur == buffer_begin; - } - - bool NeedIndexInput() const override { - return false; - } - - void SubmitIndex(unsigned int val) override { - UNREACHABLE(); - } - - bool SubmitVertex(const Shader::AttributeBuffer& input) override { - buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur); - if (buffer_cur == buffer_end) { - buffer_cur = buffer_begin; - return true; - } - return false; - } - -private: - const Regs& regs; - Shader::ShaderSetup& setup; - Math::Vec4<float24>* buffer_begin; - Math::Vec4<float24>* buffer_cur; - Math::Vec4<float24>* buffer_end; - unsigned int vs_output_num; -}; - -GeometryPipeline::GeometryPipeline(State& state) : state(state) {} - -GeometryPipeline::~GeometryPipeline() = default; - -void GeometryPipeline::SetVertexHandler(Shader::VertexHandler vertex_handler) { - this->vertex_handler = vertex_handler; -} - -void GeometryPipeline::Setup(Shader::ShaderEngine* shader_engine) { - if (!backend) - return; - - this->shader_engine = shader_engine; - shader_engine->SetupBatch(state.gs, state.regs.gs.main_offset); -} - -void GeometryPipeline::Reconfigure() { - ASSERT(!backend || backend->IsEmpty()); - - if (state.regs.pipeline.use_gs == PipelineRegs::UseGS::No) { - backend = nullptr; - return; - } - - ASSERT(state.regs.pipeline.use_gs == PipelineRegs::UseGS::Yes); - - // The following assumes that when geometry shader is in use, the shader unit 3 is configured as - // a geometry shader unit. - // TODO: what happens if this is not true? - ASSERT(state.regs.pipeline.gs_unit_exclusive_configuration == 1); - ASSERT(state.regs.gs.shader_mode == ShaderRegs::ShaderMode::GS); - - state.gs_unit.ConfigOutput(state.regs.gs); - - ASSERT(state.regs.pipeline.vs_outmap_total_minus_1_a == - state.regs.pipeline.vs_outmap_total_minus_1_b); - - switch (state.regs.pipeline.gs_config.mode) { - case PipelineRegs::GSMode::Point: - backend = std::make_unique<GeometryPipeline_Point>(state.regs, state.gs_unit); - break; - case PipelineRegs::GSMode::VariablePrimitive: - backend = std::make_unique<GeometryPipeline_VariablePrimitive>(state.regs, state.gs); - break; - case PipelineRegs::GSMode::FixedPrimitive: - backend = std::make_unique<GeometryPipeline_FixedPrimitive>(state.regs, state.gs); - break; - default: - UNREACHABLE(); - } -} - -bool GeometryPipeline::NeedIndexInput() const { - if (!backend) - return false; - return backend->NeedIndexInput(); -} - -void GeometryPipeline::SubmitIndex(unsigned int val) { - backend->SubmitIndex(val); -} - -void GeometryPipeline::SubmitVertex(const Shader::AttributeBuffer& input) { - if (!backend) { - // No backend means the geometry shader is disabled, so we send the vertex shader output - // directly to the primitive assembler. - vertex_handler(input); - } else { - if (backend->SubmitVertex(input)) { - shader_engine->Run(state.gs, state.gs_unit); - - // The uniform b15 is set to true after every geometry shader invocation. This is useful - // for the shader to know if this is the first invocation in a batch, if the program set - // b15 to false first. - state.gs.uniforms.b[15] = true; - } - } -} - -} // namespace Pica |