summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-06-03 02:48:41 -0300
committerGravatar ReinUsesLisp2020-06-03 20:22:12 -0300
commit3d99b449d3c285a50ffb68ae077882cc2998d62f (patch)
tree42f989734b20efec9901e0d5c9bb84eefc55161f
parentMerge pull request #4014 from ReinUsesLisp/astc-nvidia (diff)
downloadyuzu-3d99b449d3c285a50ffb68ae077882cc2998d62f.tar.gz
yuzu-3d99b449d3c285a50ffb68ae077882cc2998d62f.tar.xz
yuzu-3d99b449d3c285a50ffb68ae077882cc2998d62f.zip
gl_rasterizer: Use NV_transform_feedback for XFB on assembly shaders
NV_transform_feedback, NV_transform_feedback2 and ARB_transform_feedback3 with NV_transform_feedback interactions allows implementing transform feedbacks as dynamic state. Maxwell implements transform feedbacks as dynamic state, so using these extensions with TransformFeedbackStreamAttribsNV allows us to properly emulate transform feedbacks without having to recompile shaders when the state changes.
-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