summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp90
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
3 files changed, 96 insertions, 1 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index b772c37d9..8b424e2cb 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -206,7 +206,8 @@ Device::Device()
206 has_precise_bug = TestPreciseBug(); 206 has_precise_bug = TestPreciseBug();
207 has_fast_buffer_sub_data = is_nvidia; 207 has_fast_buffer_sub_data = is_nvidia;
208 use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 && 208 use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 &&
209 GLAD_GL_NV_compute_program5; 209 GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback &&
210 GLAD_GL_NV_transform_feedback2;
210 211
211 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); 212 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
212 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); 213 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 55e79aaf6..f802fd384 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -93,6 +93,34 @@ std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
93 return buffer.size; 93 return buffer.size;
94} 94}
95 95
96/// Translates hardware transform feedback indices
97/// @param location Hardware location
98/// @return Pair of ARB_transform_feedback3 token stream first and third arguments
99/// @note Read https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_transform_feedback3.txt
100std::pair<GLint, GLint> TransformFeedbackEnum(u8 location) {
101 const u8 index = location / 4;
102 if (index >= 8 && index <= 39) {
103 return {GL_GENERIC_ATTRIB_NV, index - 8};
104 }
105 if (index >= 48 && index <= 55) {
106 return {GL_TEXTURE_COORD_NV, index - 48};
107 }
108 switch (index) {
109 case 7:
110 return {GL_POSITION, 0};
111 case 40:
112 return {GL_PRIMARY_COLOR_NV, 0};
113 case 41:
114 return {GL_SECONDARY_COLOR_NV, 0};
115 case 42:
116 return {GL_BACK_PRIMARY_COLOR_NV, 0};
117 case 43:
118 return {GL_BACK_SECONDARY_COLOR_NV, 0};
119 }
120 UNIMPLEMENTED_MSG("index={}", static_cast<int>(index));
121 return {GL_POSITION, 0};
122}
123
96void oglEnable(GLenum cap, bool state) { 124void oglEnable(GLenum cap, bool state) {
97 (state ? glEnable : glDisable)(cap); 125 (state ? glEnable : glDisable)(cap);
98} 126}
@@ -1547,12 +1575,70 @@ void RasterizerOpenGL::SyncFramebufferSRGB() {
1547 oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb); 1575 oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb);
1548} 1576}
1549 1577
1578void RasterizerOpenGL::SyncTransformFeedback() {
1579 // TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
1580 // when this is required.
1581 const auto& regs = system.GPU().Maxwell3D().regs;
1582
1583 static constexpr std::size_t STRIDE = 3;
1584 std::array<GLint, 128 * STRIDE * Maxwell::NumTransformFeedbackBuffers> attribs;
1585 std::array<GLint, Maxwell::NumTransformFeedbackBuffers> streams;
1586
1587 GLint* cursor = attribs.data();
1588 GLint* current_stream = streams.data();
1589
1590 for (std::size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
1591 const auto& layout = regs.tfb_layouts[feedback];
1592 UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding");
1593 if (layout.varying_count == 0) {
1594 continue;
1595 }
1596
1597 *current_stream = static_cast<GLint>(feedback);
1598 if (current_stream != streams.data()) {
1599 // When stepping one stream, push the expected token
1600 cursor[0] = GL_NEXT_BUFFER_NV;
1601 cursor[1] = 0;
1602 cursor[2] = 0;
1603 cursor += STRIDE;
1604 }
1605 ++current_stream;
1606
1607 const auto& locations = regs.tfb_varying_locs[feedback];
1608 std::optional<u8> current_index;
1609 for (u32 offset = 0; offset < layout.varying_count; ++offset) {
1610 const u8 location = locations[offset];
1611 const u8 index = location / 4;
1612
1613 if (current_index == index) {
1614 // Increase number of components of the previous attachment
1615 ++cursor[-2];
1616 continue;
1617 }
1618 current_index = index;
1619
1620 std::tie(cursor[0], cursor[2]) = TransformFeedbackEnum(location);
1621 cursor[1] = 1;
1622 cursor += STRIDE;
1623 }
1624 }
1625
1626 const GLsizei num_attribs = static_cast<GLsizei>((cursor - attribs.data()) / STRIDE);
1627 const GLsizei num_strides = static_cast<GLsizei>(current_stream - streams.data());
1628 glTransformFeedbackStreamAttribsNV(num_attribs, attribs.data(), num_strides, streams.data(),
1629 GL_INTERLEAVED_ATTRIBS);
1630}
1631
1550void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) { 1632void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
1551 const auto& regs = system.GPU().Maxwell3D().regs; 1633 const auto& regs = system.GPU().Maxwell3D().regs;
1552 if (regs.tfb_enabled == 0) { 1634 if (regs.tfb_enabled == 0) {
1553 return; 1635 return;
1554 } 1636 }
1555 1637
1638 if (device.UseAssemblyShaders()) {
1639 SyncTransformFeedback();
1640 }
1641
1556 UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) || 1642 UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) ||
1557 regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) || 1643 regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) ||
1558 regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry)); 1644 regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry));
@@ -1579,6 +1665,10 @@ void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
1579 static_cast<GLsizeiptr>(size)); 1665 static_cast<GLsizeiptr>(size));
1580 } 1666 }
1581 1667
1668 // We may have to call BeginTransformFeedbackNV here since they seem to call different
1669 // implementations on Nvidia's driver (the pointer is different) but we are using
1670 // ARB_transform_feedback3 features with NV_transform_feedback interactions and the ARB
1671 // extension doesn't define BeginTransformFeedback (without NV) interactions. It just works.
1582 glBeginTransformFeedback(GL_POINTS); 1672 glBeginTransformFeedback(GL_POINTS);
1583} 1673}
1584 1674
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index f5dc56a0e..7abc8fdbd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -202,6 +202,10 @@ private:
202 /// Syncs the framebuffer sRGB state to match the guest state 202 /// Syncs the framebuffer sRGB state to match the guest state
203 void SyncFramebufferSRGB(); 203 void SyncFramebufferSRGB();
204 204
205 /// Syncs transform feedback state to match guest state
206 /// @note Only valid on assembly shaders
207 void SyncTransformFeedback();
208
205 /// Begin a transform feedback 209 /// Begin a transform feedback
206 void BeginTransformFeedback(GLenum primitive_mode); 210 void BeginTransformFeedback(GLenum primitive_mode);
207 211