geometry_pipeline.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "video_core/geometry_pipeline.h"
  5. #include "video_core/pica_state.h"
  6. #include "video_core/regs.h"
  7. #include "video_core/renderer_base.h"
  8. #include "video_core/video_core.h"
  9. namespace Pica {
  10. /// An attribute buffering interface for different pipeline modes
  11. class GeometryPipelineBackend {
  12. public:
  13. virtual ~GeometryPipelineBackend() = default;
  14. /// Checks if there is no incomplete data transfer
  15. virtual bool IsEmpty() const = 0;
  16. /// Checks if the pipeline needs a direct input from index buffer
  17. virtual bool NeedIndexInput() const = 0;
  18. /// Submits an index from index buffer
  19. virtual void SubmitIndex(unsigned int val) = 0;
  20. /**
  21. * Submits vertex attributes
  22. * @param input attributes of a vertex output from vertex shader
  23. * @return if the buffer is full and the geometry shader should be invoked
  24. */
  25. virtual bool SubmitVertex(const Shader::AttributeBuffer& input) = 0;
  26. };
  27. // In the Point mode, vertex attributes are sent to the input registers in the geometry shader unit.
  28. // The size of vertex shader outputs and geometry shader inputs are constants. Geometry shader is
  29. // invoked upon inputs buffer filled up by vertex shader outputs. For example, if we have a geometry
  30. // shader that takes 6 inputs, and the vertex shader outputs 2 attributes, it would take 3 vertices
  31. // for one geometry shader invocation.
  32. // TODO: what happens when the input size is not divisible by the output size?
  33. class GeometryPipeline_Point : public GeometryPipelineBackend {
  34. public:
  35. GeometryPipeline_Point(const Regs& regs, Shader::GSUnitState& unit) : regs(regs), unit(unit) {
  36. ASSERT(regs.pipeline.variable_primitive == 0);
  37. ASSERT(regs.gs.input_to_uniform == 0);
  38. vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
  39. size_t gs_input_num = regs.gs.max_input_attribute_index + 1;
  40. ASSERT(gs_input_num % vs_output_num == 0);
  41. buffer_cur = attribute_buffer.attr;
  42. buffer_end = attribute_buffer.attr + gs_input_num;
  43. }
  44. bool IsEmpty() const override {
  45. return buffer_cur == attribute_buffer.attr;
  46. }
  47. bool NeedIndexInput() const override {
  48. return false;
  49. }
  50. void SubmitIndex(unsigned int val) override {
  51. UNREACHABLE();
  52. }
  53. bool SubmitVertex(const Shader::AttributeBuffer& input) override {
  54. buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur);
  55. if (buffer_cur == buffer_end) {
  56. buffer_cur = attribute_buffer.attr;
  57. unit.LoadInput(regs.gs, attribute_buffer);
  58. return true;
  59. }
  60. return false;
  61. }
  62. private:
  63. const Regs& regs;
  64. Shader::GSUnitState& unit;
  65. Shader::AttributeBuffer attribute_buffer;
  66. Math::Vec4<float24>* buffer_cur;
  67. Math::Vec4<float24>* buffer_end;
  68. unsigned int vs_output_num;
  69. };
  70. // In VariablePrimitive mode, vertex attributes are buffered into the uniform registers in the
  71. // geometry shader unit. The number of vertex is variable, which is specified by the first index
  72. // value in the batch. This mode is usually used for subdivision.
  73. class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
  74. public:
  75. GeometryPipeline_VariablePrimitive(const Regs& regs, Shader::ShaderSetup& setup)
  76. : regs(regs), setup(setup) {
  77. ASSERT(regs.pipeline.variable_primitive == 1);
  78. ASSERT(regs.gs.input_to_uniform == 1);
  79. vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
  80. }
  81. bool IsEmpty() const override {
  82. return need_index;
  83. }
  84. bool NeedIndexInput() const override {
  85. return need_index;
  86. }
  87. void SubmitIndex(unsigned int val) override {
  88. DEBUG_ASSERT(need_index);
  89. // The number of vertex input is put to the uniform register
  90. float24 vertex_num = float24::FromFloat32(static_cast<float>(val));
  91. setup.uniforms.f[0] = Math::MakeVec(vertex_num, vertex_num, vertex_num, vertex_num);
  92. // The second uniform register and so on are used for receiving input vertices
  93. buffer_cur = setup.uniforms.f + 1;
  94. main_vertex_num = regs.pipeline.variable_vertex_main_num_minus_1 + 1;
  95. total_vertex_num = val;
  96. need_index = false;
  97. }
  98. bool SubmitVertex(const Shader::AttributeBuffer& input) override {
  99. DEBUG_ASSERT(!need_index);
  100. if (main_vertex_num != 0) {
  101. // For main vertices, receive all attributes
  102. buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur);
  103. --main_vertex_num;
  104. } else {
  105. // For other vertices, only receive the first attribute (usually the position)
  106. *(buffer_cur++) = input.attr[0];
  107. }
  108. --total_vertex_num;
  109. if (total_vertex_num == 0) {
  110. need_index = true;
  111. return true;
  112. }
  113. return false;
  114. }
  115. private:
  116. bool need_index = true;
  117. const Regs& regs;
  118. Shader::ShaderSetup& setup;
  119. unsigned int main_vertex_num;
  120. unsigned int total_vertex_num;
  121. Math::Vec4<float24>* buffer_cur;
  122. unsigned int vs_output_num;
  123. };
  124. // In FixedPrimitive mode, vertex attributes are buffered into the uniform registers in the geometry
  125. // shader unit. The number of vertex per shader invocation is constant. This is usually used for
  126. // particle system.
  127. class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
  128. public:
  129. GeometryPipeline_FixedPrimitive(const Regs& regs, Shader::ShaderSetup& setup)
  130. : regs(regs), setup(setup) {
  131. ASSERT(regs.pipeline.variable_primitive == 0);
  132. ASSERT(regs.gs.input_to_uniform == 1);
  133. vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
  134. ASSERT(vs_output_num == regs.pipeline.gs_config.stride_minus_1 + 1);
  135. size_t vertex_num = regs.pipeline.gs_config.fixed_vertex_num_minus_1 + 1;
  136. buffer_cur = buffer_begin = setup.uniforms.f + regs.pipeline.gs_config.start_index;
  137. buffer_end = buffer_begin + vs_output_num * vertex_num;
  138. }
  139. bool IsEmpty() const override {
  140. return buffer_cur == buffer_begin;
  141. }
  142. bool NeedIndexInput() const override {
  143. return false;
  144. }
  145. void SubmitIndex(unsigned int val) override {
  146. UNREACHABLE();
  147. }
  148. bool SubmitVertex(const Shader::AttributeBuffer& input) override {
  149. buffer_cur = std::copy(input.attr, input.attr + vs_output_num, buffer_cur);
  150. if (buffer_cur == buffer_end) {
  151. buffer_cur = buffer_begin;
  152. return true;
  153. }
  154. return false;
  155. }
  156. private:
  157. const Regs& regs;
  158. Shader::ShaderSetup& setup;
  159. Math::Vec4<float24>* buffer_begin;
  160. Math::Vec4<float24>* buffer_cur;
  161. Math::Vec4<float24>* buffer_end;
  162. unsigned int vs_output_num;
  163. };
  164. GeometryPipeline::GeometryPipeline(State& state) : state(state) {}
  165. GeometryPipeline::~GeometryPipeline() = default;
  166. void GeometryPipeline::SetVertexHandler(Shader::VertexHandler vertex_handler) {
  167. this->vertex_handler = vertex_handler;
  168. }
  169. void GeometryPipeline::Setup(Shader::ShaderEngine* shader_engine) {
  170. if (!backend)
  171. return;
  172. this->shader_engine = shader_engine;
  173. shader_engine->SetupBatch(state.gs, state.regs.gs.main_offset);
  174. }
  175. void GeometryPipeline::Reconfigure() {
  176. ASSERT(!backend || backend->IsEmpty());
  177. if (state.regs.pipeline.use_gs == PipelineRegs::UseGS::No) {
  178. backend = nullptr;
  179. return;
  180. }
  181. ASSERT(state.regs.pipeline.use_gs == PipelineRegs::UseGS::Yes);
  182. // The following assumes that when geometry shader is in use, the shader unit 3 is configured as
  183. // a geometry shader unit.
  184. // TODO: what happens if this is not true?
  185. ASSERT(state.regs.pipeline.gs_unit_exclusive_configuration == 1);
  186. ASSERT(state.regs.gs.shader_mode == ShaderRegs::ShaderMode::GS);
  187. state.gs_unit.ConfigOutput(state.regs.gs);
  188. ASSERT(state.regs.pipeline.vs_outmap_total_minus_1_a ==
  189. state.regs.pipeline.vs_outmap_total_minus_1_b);
  190. switch (state.regs.pipeline.gs_config.mode) {
  191. case PipelineRegs::GSMode::Point:
  192. backend = std::make_unique<GeometryPipeline_Point>(state.regs, state.gs_unit);
  193. break;
  194. case PipelineRegs::GSMode::VariablePrimitive:
  195. backend = std::make_unique<GeometryPipeline_VariablePrimitive>(state.regs, state.gs);
  196. break;
  197. case PipelineRegs::GSMode::FixedPrimitive:
  198. backend = std::make_unique<GeometryPipeline_FixedPrimitive>(state.regs, state.gs);
  199. break;
  200. default:
  201. UNREACHABLE();
  202. }
  203. }
  204. bool GeometryPipeline::NeedIndexInput() const {
  205. if (!backend)
  206. return false;
  207. return backend->NeedIndexInput();
  208. }
  209. void GeometryPipeline::SubmitIndex(unsigned int val) {
  210. backend->SubmitIndex(val);
  211. }
  212. void GeometryPipeline::SubmitVertex(const Shader::AttributeBuffer& input) {
  213. if (!backend) {
  214. // No backend means the geometry shader is disabled, so we send the vertex shader output
  215. // directly to the primitive assembler.
  216. vertex_handler(input);
  217. } else {
  218. if (backend->SubmitVertex(input)) {
  219. shader_engine->Run(state.gs, state.gs_unit);
  220. // The uniform b15 is set to true after every geometry shader invocation. This is useful
  221. // for the shader to know if this is the first invocation in a batch, if the program set
  222. // b15 to false first.
  223. state.gs.uniforms.b[15] = true;
  224. }
  225. }
  226. }
  227. } // namespace Pica