summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/gl_rasterizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp127
1 files changed, 107 insertions, 20 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ae6aaee4c..a44bbfae8 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
has_ARB_direct_state_access = true;
} else if (extension == "GL_ARB_multi_bind") {
has_ARB_multi_bind = true;
- } else if (extension == "GL_ARB_separate_shader_objects") {
- has_ARB_separate_shader_objects = true;
- } else if (extension == "GL_ARB_vertex_attrib_binding") {
- has_ARB_vertex_attrib_binding = true;
}
}
- ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
OpenGLState::ApplyDefaultState();
// Create render framebuffer
@@ -118,10 +113,24 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
+ CheckExtensions();
}
RasterizerOpenGL::~RasterizerOpenGL() {}
+void RasterizerOpenGL::CheckExtensions() {
+ if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) {
+ LOG_WARNING(
+ Render_OpenGL,
+ "Anisotropic filter is not supported! This can cause graphical issues in some games.");
+ }
+ if (!GLAD_GL_ARB_buffer_storage) {
+ LOG_WARNING(
+ Render_OpenGL,
+ "Buffer storage control is not supported! This can cause performance degradation.");
+ }
+}
+
void RasterizerOpenGL::SetupVertexFormat() {
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
@@ -181,15 +190,25 @@ void RasterizerOpenGL::SetupVertexFormat() {
}
state.draw.vertex_array = VAO.handle;
state.ApplyVertexBufferState();
+
+ // Rebinding the VAO invalidates the vertex buffer bindings.
+ gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
}
void RasterizerOpenGL::SetupVertexBuffer() {
- MICROPROFILE_SCOPE(OpenGL_VB);
- const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
+ auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
+ if (!gpu.dirty_flags.vertex_array)
+ return;
+
+ MICROPROFILE_SCOPE(OpenGL_VB);
+
// Upload all guest vertex arrays sequentially to our buffer
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
+ if (~gpu.dirty_flags.vertex_array & (1u << index))
+ continue;
+
const auto& vertex_array = regs.vertex_array[index];
if (!vertex_array.IsEnabled())
continue;
@@ -216,6 +235,8 @@ void RasterizerOpenGL::SetupVertexBuffer() {
// Implicit set by glBindVertexBuffer. Stupid glstate handling...
state.draw.vertex_buffer = buffer_cache.GetHandle();
+
+ gpu.dirty_flags.vertex_array = 0;
}
DrawParameters RasterizerOpenGL::SetupDraw() {
@@ -542,6 +563,30 @@ void RasterizerOpenGL::Clear() {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
use_stencil = true;
clear_state.stencil.test_enabled = true;
+ if (regs.clear_flags.stencil) {
+ // Stencil affects the clear so fill it with the used masks
+ clear_state.stencil.front.test_func = GL_ALWAYS;
+ clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
+ clear_state.stencil.front.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.front.action_depth_fail = GL_KEEP;
+ clear_state.stencil.front.action_depth_pass = GL_KEEP;
+ clear_state.stencil.front.write_mask = regs.stencil_front_mask;
+ if (regs.stencil_two_side_enable) {
+ clear_state.stencil.back.test_func = GL_ALWAYS;
+ clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
+ clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_pass = GL_KEEP;
+ clear_state.stencil.back.write_mask = regs.stencil_back_mask;
+ } else {
+ clear_state.stencil.back.test_func = GL_ALWAYS;
+ clear_state.stencil.back.test_mask = 0xFFFFFFFF;
+ clear_state.stencil.back.write_mask = 0xFFFFFFFF;
+ clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_fail = GL_KEEP;
+ clear_state.stencil.back.action_depth_pass = GL_KEEP;
+ }
+ }
}
if (!use_color && !use_depth && !use_stencil) {
@@ -553,6 +598,14 @@ void RasterizerOpenGL::Clear() {
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
regs.clear_buffers.RT.Value());
+ if (regs.clear_flags.scissor) {
+ SyncScissorTest(clear_state);
+ }
+
+ if (regs.clear_flags.viewport) {
+ clear_state.EmulateViewportWithScissor();
+ }
+
clear_state.Apply();
if (use_color) {
@@ -573,7 +626,7 @@ void RasterizerOpenGL::DrawArrays() {
return;
MICROPROFILE_SCOPE(OpenGL_Drawing);
- const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
+ auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
ScopeAcquireGLContext acquire_context{emu_window};
@@ -588,12 +641,13 @@ void RasterizerOpenGL::DrawArrays() {
SyncLogicOpState();
SyncCullMode();
SyncPrimitiveRestart();
- SyncScissorTest();
+ SyncScissorTest(state);
+ SyncClipEnabled();
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
SyncPointState();
CheckAlphaTests();
-
+ SyncPolygonOffset();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -626,7 +680,11 @@ void RasterizerOpenGL::DrawArrays() {
// Add space for at least 18 constant buffers
buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment);
- buffer_cache.Map(buffer_size);
+ bool invalidate = buffer_cache.Map(buffer_size);
+ if (invalidate) {
+ // As all cached buffers are invalidated, we need to recheck their state.
+ gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
+ }
SetupVertexFormat();
SetupVertexBuffer();
@@ -815,7 +873,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
}
const u32 bias = config.mip_lod_bias.Value();
// Sign extend the 13-bit value.
- const u32 mask = 1U << (13 - 1);
+ constexpr u32 mask = 1U << (13 - 1);
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
if (lod_bias != bias_lod) {
lod_bias = bias_lod;
@@ -942,20 +1000,35 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
- const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
+ const bool geometry_shaders_enabled =
+ regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
+ const std::size_t viewport_count =
+ geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
+ for (std::size_t i = 0; i < viewport_count; i++) {
auto& viewport = current_state.viewports[i];
+ const auto& src = regs.viewports[i];
+ const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
viewport.x = viewport_rect.left;
viewport.y = viewport_rect.bottom;
- viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
- viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
+ viewport.width = viewport_rect.GetWidth();
+ viewport.height = viewport_rect.GetHeight();
viewport.depth_range_far = regs.viewports[i].depth_range_far;
viewport.depth_range_near = regs.viewports[i].depth_range_near;
}
+ state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
+ state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
}
void RasterizerOpenGL::SyncClipEnabled() {
- UNREACHABLE();
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0;
+ state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0;
+ state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0;
+ state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0;
+ state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0;
+ state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0;
+ state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0;
+ state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0;
}
void RasterizerOpenGL::SyncClipCoef() {
@@ -1120,11 +1193,15 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}
-void RasterizerOpenGL::SyncScissorTest() {
+void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
+ const bool geometry_shaders_enabled =
+ regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
+ const std::size_t viewport_count =
+ geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
+ for (std::size_t i = 0; i < viewport_count; i++) {
const auto& src = regs.scissor_test[i];
- auto& dst = state.viewports[i].scissor;
+ auto& dst = current_state.viewports[i].scissor;
dst.enabled = (src.enable != 0);
if (dst.enabled == 0) {
return;
@@ -1152,6 +1229,16 @@ void RasterizerOpenGL::SyncPointState() {
state.point.size = regs.point_size;
}
+void RasterizerOpenGL::SyncPolygonOffset() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
+ state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
+ state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
+ state.polygon_offset.units = regs.polygon_offset_units;
+ state.polygon_offset.factor = regs.polygon_offset_factor;
+ state.polygon_offset.clamp = regs.polygon_offset_clamp;
+}
+
void RasterizerOpenGL::CheckAlphaTests() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;