mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-12-28 19:30:58 +01:00
gl_rasterizer: Implement transform feedback bindings
This commit is contained in:
parent
4d711dface
commit
8e9f23f393
3 changed files with 83 additions and 10 deletions
|
@ -634,6 +634,11 @@ public:
|
|||
u32 address_low;
|
||||
s32 buffer_size;
|
||||
s32 buffer_offset;
|
||||
|
||||
GPUVAddr Address() const {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
|
||||
address_low);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(TransformFeedbackBinding) == 32);
|
||||
|
||||
|
@ -652,6 +657,10 @@ public:
|
|||
return shader_config[index].enable != 0;
|
||||
}
|
||||
|
||||
bool IsShaderConfigEnabled(Regs::ShaderProgram type) const {
|
||||
return IsShaderConfigEnabled(static_cast<std::size_t>(type));
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
INSERT_UNION_PADDING_WORDS(0x45);
|
||||
|
|
|
@ -496,7 +496,6 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
|||
SyncCullMode();
|
||||
SyncPrimitiveRestart();
|
||||
SyncScissorTest();
|
||||
SyncTransformFeedback();
|
||||
SyncPointState();
|
||||
SyncPolygonOffset();
|
||||
SyncAlphaTest();
|
||||
|
@ -569,7 +568,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
|||
glTextureBarrier();
|
||||
}
|
||||
|
||||
++num_queued_commands;
|
||||
BeginTransformFeedback(primitive_mode);
|
||||
|
||||
const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance);
|
||||
const GLsizei num_instances =
|
||||
|
@ -608,6 +607,10 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
|||
num_instances, base_instance);
|
||||
}
|
||||
}
|
||||
|
||||
EndTransformFeedback();
|
||||
|
||||
++num_queued_commands;
|
||||
}
|
||||
|
||||
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() {
|
||||
auto& gpu = system.GPU().Maxwell3D();
|
||||
auto& flags = gpu.dirty.flags;
|
||||
|
@ -1370,4 +1368,62 @@ void RasterizerOpenGL::SyncFramebufferSRGB() {
|
|||
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
|
||||
|
|
|
@ -168,9 +168,6 @@ private:
|
|||
/// Syncs the scissor test state to match the guest state
|
||||
void SyncScissorTest();
|
||||
|
||||
/// Syncs the transform feedback state to match the guest state
|
||||
void SyncTransformFeedback();
|
||||
|
||||
/// Syncs the point state to match the guest state
|
||||
void SyncPointState();
|
||||
|
||||
|
@ -192,6 +189,12 @@ private:
|
|||
/// Syncs the framebuffer sRGB state to match the guest state
|
||||
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
|
||||
void CheckExtensions();
|
||||
|
||||
|
@ -229,6 +232,11 @@ private:
|
|||
BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_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.
|
||||
std::size_t num_queued_commands = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue