gl_rasterizer: Implement transform feedback bindings
This commit is contained in:
		| @@ -634,6 +634,11 @@ public: | |||||||
|             u32 address_low; |             u32 address_low; | ||||||
|             s32 buffer_size; |             s32 buffer_size; | ||||||
|             s32 buffer_offset; |             s32 buffer_offset; | ||||||
|  |  | ||||||
|  |             GPUVAddr Address() const { | ||||||
|  |                 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||||||
|  |                                              address_low); | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         static_assert(sizeof(TransformFeedbackBinding) == 32); |         static_assert(sizeof(TransformFeedbackBinding) == 32); | ||||||
|  |  | ||||||
| @@ -652,6 +657,10 @@ public: | |||||||
|             return shader_config[index].enable != 0; |             return shader_config[index].enable != 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         bool IsShaderConfigEnabled(Regs::ShaderProgram type) const { | ||||||
|  |             return IsShaderConfigEnabled(static_cast<std::size_t>(type)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         union { |         union { | ||||||
|             struct { |             struct { | ||||||
|                 INSERT_UNION_PADDING_WORDS(0x45); |                 INSERT_UNION_PADDING_WORDS(0x45); | ||||||
|   | |||||||
| @@ -496,7 +496,6 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | |||||||
|     SyncCullMode(); |     SyncCullMode(); | ||||||
|     SyncPrimitiveRestart(); |     SyncPrimitiveRestart(); | ||||||
|     SyncScissorTest(); |     SyncScissorTest(); | ||||||
|     SyncTransformFeedback(); |  | ||||||
|     SyncPointState(); |     SyncPointState(); | ||||||
|     SyncPolygonOffset(); |     SyncPolygonOffset(); | ||||||
|     SyncAlphaTest(); |     SyncAlphaTest(); | ||||||
| @@ -569,7 +568,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | |||||||
|         glTextureBarrier(); |         glTextureBarrier(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ++num_queued_commands; |     BeginTransformFeedback(primitive_mode); | ||||||
|  |  | ||||||
|     const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance); |     const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance); | ||||||
|     const GLsizei num_instances = |     const GLsizei num_instances = | ||||||
| @@ -608,6 +607,10 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | |||||||
|                                               num_instances, base_instance); |                                               num_instances, base_instance); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     EndTransformFeedback(); | ||||||
|  |  | ||||||
|  |     ++num_queued_commands; | ||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | ||||||
| @@ -1290,11 +1293,6 @@ void RasterizerOpenGL::SyncScissorTest() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::SyncTransformFeedback() { |  | ||||||
|     const auto& regs = system.GPU().Maxwell3D().regs; |  | ||||||
|     UNIMPLEMENTED_IF_MSG(regs.tfb_enabled != 0, "Transform feedbacks are not implemented"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void RasterizerOpenGL::SyncPointState() { | void RasterizerOpenGL::SyncPointState() { | ||||||
|     auto& gpu = system.GPU().Maxwell3D(); |     auto& gpu = system.GPU().Maxwell3D(); | ||||||
|     auto& flags = gpu.dirty.flags; |     auto& flags = gpu.dirty.flags; | ||||||
| @@ -1370,4 +1368,62 @@ void RasterizerOpenGL::SyncFramebufferSRGB() { | |||||||
|     oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb); |     oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) { | ||||||
|  |     const auto& regs = system.GPU().Maxwell3D().regs; | ||||||
|  |     if (regs.tfb_enabled == 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) || | ||||||
|  |                      regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) || | ||||||
|  |                      regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry)); | ||||||
|  |  | ||||||
|  |     for (std::size_t index = 0; index < Maxwell::NumTransformFeedbackBuffers; ++index) { | ||||||
|  |         const auto& binding = regs.tfb_bindings[index]; | ||||||
|  |         if (!binding.buffer_enable) { | ||||||
|  |             if (enabled_transform_feedback_buffers[index]) { | ||||||
|  |                 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index), 0, 0, | ||||||
|  |                                   0); | ||||||
|  |             } | ||||||
|  |             enabled_transform_feedback_buffers[index] = false; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         enabled_transform_feedback_buffers[index] = true; | ||||||
|  |  | ||||||
|  |         auto& tfb_buffer = transform_feedback_buffers[index]; | ||||||
|  |         tfb_buffer.Create(); | ||||||
|  |  | ||||||
|  |         const GLuint handle = tfb_buffer.handle; | ||||||
|  |         const std::size_t size = binding.buffer_size; | ||||||
|  |         glNamedBufferData(handle, static_cast<GLsizeiptr>(size), nullptr, GL_STREAM_COPY); | ||||||
|  |         glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index), handle, 0, | ||||||
|  |                           static_cast<GLsizeiptr>(size)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     glBeginTransformFeedback(GL_POINTS); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void RasterizerOpenGL::EndTransformFeedback() { | ||||||
|  |     const auto& regs = system.GPU().Maxwell3D().regs; | ||||||
|  |     if (regs.tfb_enabled == 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     glEndTransformFeedback(); | ||||||
|  |  | ||||||
|  |     for (std::size_t index = 0; index < Maxwell::NumTransformFeedbackBuffers; ++index) { | ||||||
|  |         const auto& binding = regs.tfb_bindings[index]; | ||||||
|  |         if (!binding.buffer_enable) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         UNIMPLEMENTED_IF(binding.buffer_offset != 0); | ||||||
|  |  | ||||||
|  |         const GLuint handle = transform_feedback_buffers[index].handle; | ||||||
|  |         const GPUVAddr gpu_addr = binding.Address(); | ||||||
|  |         const std::size_t size = binding.buffer_size; | ||||||
|  |         const auto [dest_buffer, offset] = buffer_cache.UploadMemory(gpu_addr, size, 4, true); | ||||||
|  |         glCopyNamedBufferSubData(handle, *dest_buffer, 0, offset, static_cast<GLsizeiptr>(size)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| } // namespace OpenGL | } // namespace OpenGL | ||||||
|   | |||||||
| @@ -168,9 +168,6 @@ private: | |||||||
|     /// Syncs the scissor test state to match the guest state |     /// Syncs the scissor test state to match the guest state | ||||||
|     void SyncScissorTest(); |     void SyncScissorTest(); | ||||||
|  |  | ||||||
|     /// Syncs the transform feedback state to match the guest state |  | ||||||
|     void SyncTransformFeedback(); |  | ||||||
|  |  | ||||||
|     /// Syncs the point state to match the guest state |     /// Syncs the point state to match the guest state | ||||||
|     void SyncPointState(); |     void SyncPointState(); | ||||||
|  |  | ||||||
| @@ -192,6 +189,12 @@ private: | |||||||
|     /// Syncs the framebuffer sRGB state to match the guest state |     /// Syncs the framebuffer sRGB state to match the guest state | ||||||
|     void SyncFramebufferSRGB(); |     void SyncFramebufferSRGB(); | ||||||
|  |  | ||||||
|  |     /// Begin a transform feedback | ||||||
|  |     void BeginTransformFeedback(GLenum primitive_mode); | ||||||
|  |  | ||||||
|  |     /// End a transform feedback | ||||||
|  |     void EndTransformFeedback(); | ||||||
|  |  | ||||||
|     /// Check for extension that are not strictly required but are needed for correct emulation |     /// Check for extension that are not strictly required but are needed for correct emulation | ||||||
|     void CheckExtensions(); |     void CheckExtensions(); | ||||||
|  |  | ||||||
| @@ -229,6 +232,11 @@ private: | |||||||
|     BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; |     BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; | ||||||
|     BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; |     BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; | ||||||
|  |  | ||||||
|  |     std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::NumTransformFeedbackBuffers> | ||||||
|  |         transform_feedback_buffers; | ||||||
|  |     std::bitset<Tegra::Engines::Maxwell3D::Regs::NumTransformFeedbackBuffers> | ||||||
|  |         enabled_transform_feedback_buffers; | ||||||
|  |  | ||||||
|     /// Number of commands queued to the OpenGL driver. Reseted on flush. |     /// Number of commands queued to the OpenGL driver. Reseted on flush. | ||||||
|     std::size_t num_queued_commands = 0; |     std::size_t num_queued_commands = 0; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user