gl_rasterizer: Implement transform feedback bindings

This commit is contained in:
ReinUsesLisp 2020-03-02 19:31:26 -03:00
parent 4d711dface
commit 8e9f23f393
3 changed files with 83 additions and 10 deletions

View File

@ -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);

View File

@ -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

View File

@ -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;