gl_rasterizer: Implement transform feedback bindings
This commit is contained in:
parent
4d711dface
commit
8e9f23f393
|
@ -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