summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/math_util.h16
-rw-r--r--src/core/core.cpp1
-rw-r--r--src/video_core/CMakeLists.txt8
-rw-r--r--src/video_core/dirty_flags.cpp46
-rw-r--r--src/video_core/dirty_flags.h51
-rw-r--r--src/video_core/dma_pusher.cpp2
-rw-r--r--src/video_core/engines/kepler_compute.cpp2
-rw-r--r--src/video_core/engines/kepler_memory.cpp2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp187
-rw-r--r--src/video_core/engines/maxwell_3d.h150
-rw-r--r--src/video_core/engines/maxwell_dma.cpp2
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_opengl/gl_framebuffer_cache.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_framebuffer_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp869
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h45
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp28
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h25
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h18
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp569
-rw-r--r--src/video_core/renderer_opengl/gl_state.h251
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.cpp238
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.h204
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp47
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h10
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h14
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp206
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h14
-rw-r--r--src/video_core/renderer_opengl/utils.cpp13
-rw-r--r--src/video_core/renderer_opengl/utils.h9
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp15
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h8
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp14
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp8
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp69
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h17
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp21
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h42
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp101
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h79
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp1
-rw-r--r--src/video_core/texture_cache/texture_cache.h18
50 files changed, 1578 insertions, 1891 deletions
diff --git a/src/common/math_util.h b/src/common/math_util.h
index d6c35ee89..83ef0201f 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -24,17 +24,29 @@ struct Rectangle {
24 : left(left), top(top), right(right), bottom(bottom) {} 24 : left(left), top(top), right(right), bottom(bottom) {}
25 25
26 T GetWidth() const { 26 T GetWidth() const {
27 return std::abs(static_cast<std::make_signed_t<T>>(right - left)); 27 if constexpr (std::is_floating_point_v<T>) {
28 return std::abs(right - left);
29 } else {
30 return std::abs(static_cast<std::make_signed_t<T>>(right - left));
31 }
28 } 32 }
33
29 T GetHeight() const { 34 T GetHeight() const {
30 return std::abs(static_cast<std::make_signed_t<T>>(bottom - top)); 35 if constexpr (std::is_floating_point_v<T>) {
36 return std::abs(bottom - top);
37 } else {
38 return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
39 }
31 } 40 }
41
32 Rectangle<T> TranslateX(const T x) const { 42 Rectangle<T> TranslateX(const T x) const {
33 return Rectangle{left + x, top, right + x, bottom}; 43 return Rectangle{left + x, top, right + x, bottom};
34 } 44 }
45
35 Rectangle<T> TranslateY(const T y) const { 46 Rectangle<T> TranslateY(const T y) const {
36 return Rectangle{left, top + y, right, bottom + y}; 47 return Rectangle{left, top + y, right, bottom + y};
37 } 48 }
49
38 Rectangle<T> Scale(const float s) const { 50 Rectangle<T> Scale(const float s) const {
39 return Rectangle{left, top, static_cast<T>(left + GetWidth() * s), 51 return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
40 static_cast<T>(top + GetHeight() * s)}; 52 static_cast<T>(top + GetHeight() * s)};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index a82faf127..218508126 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -174,6 +174,7 @@ struct System::Impl {
174 } 174 }
175 interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); 175 interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
176 gpu_core = VideoCore::CreateGPU(system); 176 gpu_core = VideoCore::CreateGPU(system);
177 renderer->Rasterizer().SetupDirtyFlags();
177 178
178 is_powered_on = true; 179 is_powered_on = true;
179 exit_lock = false; 180 exit_lock = false;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 4b0c6346f..14f3b4569 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -2,6 +2,8 @@ add_library(video_core STATIC
2 buffer_cache/buffer_block.h 2 buffer_cache/buffer_block.h
3 buffer_cache/buffer_cache.h 3 buffer_cache/buffer_cache.h
4 buffer_cache/map_interval.h 4 buffer_cache/map_interval.h
5 dirty_flags.cpp
6 dirty_flags.h
5 dma_pusher.cpp 7 dma_pusher.cpp
6 dma_pusher.h 8 dma_pusher.h
7 engines/const_buffer_engine_interface.h 9 engines/const_buffer_engine_interface.h
@@ -69,8 +71,8 @@ add_library(video_core STATIC
69 renderer_opengl/gl_shader_manager.h 71 renderer_opengl/gl_shader_manager.h
70 renderer_opengl/gl_shader_util.cpp 72 renderer_opengl/gl_shader_util.cpp
71 renderer_opengl/gl_shader_util.h 73 renderer_opengl/gl_shader_util.h
72 renderer_opengl/gl_state.cpp 74 renderer_opengl/gl_state_tracker.cpp
73 renderer_opengl/gl_state.h 75 renderer_opengl/gl_state_tracker.h
74 renderer_opengl/gl_stream_buffer.cpp 76 renderer_opengl/gl_stream_buffer.cpp
75 renderer_opengl/gl_stream_buffer.h 77 renderer_opengl/gl_stream_buffer.h
76 renderer_opengl/gl_texture_cache.cpp 78 renderer_opengl/gl_texture_cache.cpp
@@ -198,6 +200,8 @@ if (ENABLE_VULKAN)
198 renderer_vulkan/vk_shader_util.h 200 renderer_vulkan/vk_shader_util.h
199 renderer_vulkan/vk_staging_buffer_pool.cpp 201 renderer_vulkan/vk_staging_buffer_pool.cpp
200 renderer_vulkan/vk_staging_buffer_pool.h 202 renderer_vulkan/vk_staging_buffer_pool.h
203 renderer_vulkan/vk_state_tracker.cpp
204 renderer_vulkan/vk_state_tracker.h
201 renderer_vulkan/vk_stream_buffer.cpp 205 renderer_vulkan/vk_stream_buffer.cpp
202 renderer_vulkan/vk_stream_buffer.h 206 renderer_vulkan/vk_stream_buffer.h
203 renderer_vulkan/vk_swapchain.cpp 207 renderer_vulkan/vk_swapchain.cpp
diff --git a/src/video_core/dirty_flags.cpp b/src/video_core/dirty_flags.cpp
new file mode 100644
index 000000000..4429f3405
--- /dev/null
+++ b/src/video_core/dirty_flags.cpp
@@ -0,0 +1,46 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7
8#include "common/common_types.h"
9#include "video_core/dirty_flags.h"
10
11#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
12#define NUM(field_name) (sizeof(::Tegra::Engines::Maxwell3D::Regs::field_name) / sizeof(u32))
13
14namespace VideoCommon::Dirty {
15
16using Tegra::Engines::Maxwell3D;
17
18void SetupCommonOnWriteStores(Tegra::Engines::Maxwell3D::DirtyState::Flags& store) {
19 store[RenderTargets] = true;
20 store[ZetaBuffer] = true;
21 for (std::size_t i = 0; i < Maxwell3D::Regs::NumRenderTargets; ++i) {
22 store[ColorBuffer0 + i] = true;
23 }
24}
25
26void SetupDirtyRenderTargets(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables) {
27 static constexpr std::size_t num_per_rt = NUM(rt[0]);
28 static constexpr std::size_t begin = OFF(rt);
29 static constexpr std::size_t num = num_per_rt * Maxwell3D::Regs::NumRenderTargets;
30 for (std::size_t rt = 0; rt < Maxwell3D::Regs::NumRenderTargets; ++rt) {
31 FillBlock(tables[0], begin + rt * num_per_rt, num_per_rt, ColorBuffer0 + rt);
32 }
33 FillBlock(tables[1], begin, num, RenderTargets);
34
35 static constexpr std::array zeta_flags{ZetaBuffer, RenderTargets};
36 for (std::size_t i = 0; i < std::size(zeta_flags); ++i) {
37 const u8 flag = zeta_flags[i];
38 auto& table = tables[i];
39 table[OFF(zeta_enable)] = flag;
40 table[OFF(zeta_width)] = flag;
41 table[OFF(zeta_height)] = flag;
42 FillBlock(table, OFF(zeta), NUM(zeta), flag);
43 }
44}
45
46} // namespace VideoCommon::Dirty
diff --git a/src/video_core/dirty_flags.h b/src/video_core/dirty_flags.h
new file mode 100644
index 000000000..0dbafd3ef
--- /dev/null
+++ b/src/video_core/dirty_flags.h
@@ -0,0 +1,51 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <algorithm>
8#include <cstddef>
9#include <iterator>
10
11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h"
13
14namespace VideoCommon::Dirty {
15
16enum : u8 {
17 NullEntry = 0,
18
19 RenderTargets,
20 ColorBuffer0,
21 ColorBuffer1,
22 ColorBuffer2,
23 ColorBuffer3,
24 ColorBuffer4,
25 ColorBuffer5,
26 ColorBuffer6,
27 ColorBuffer7,
28 ZetaBuffer,
29
30 LastCommonEntry,
31};
32
33template <typename Integer>
34void FillBlock(Tegra::Engines::Maxwell3D::DirtyState::Table& table, std::size_t begin,
35 std::size_t num, Integer dirty_index) {
36 const auto it = std::begin(table) + begin;
37 std::fill(it, it + num, static_cast<u8>(dirty_index));
38}
39
40template <typename Integer1, typename Integer2>
41void FillBlock(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables, std::size_t begin,
42 std::size_t num, Integer1 index_a, Integer2 index_b) {
43 FillBlock(tables[0], begin, num, index_a);
44 FillBlock(tables[1], begin, num, index_b);
45}
46
47void SetupCommonOnWriteStores(Tegra::Engines::Maxwell3D::DirtyState::Flags& store);
48
49void SetupDirtyRenderTargets(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables);
50
51} // namespace VideoCommon::Dirty
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 0094fd715..713c14182 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -22,7 +22,7 @@ void DmaPusher::DispatchCalls() {
22 MICROPROFILE_SCOPE(DispatchCalls); 22 MICROPROFILE_SCOPE(DispatchCalls);
23 23
24 // On entering GPU code, assume all memory may be touched by the ARM core. 24 // On entering GPU code, assume all memory may be touched by the ARM core.
25 gpu.Maxwell3D().dirty.OnMemoryWrite(); 25 gpu.Maxwell3D().OnMemoryWrite();
26 26
27 dma_pushbuffer_subindex = 0; 27 dma_pushbuffer_subindex = 0;
28 28
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 4b824aa4e..ae52afa79 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -39,7 +39,7 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
39 const bool is_last_call = method_call.IsLastCall(); 39 const bool is_last_call = method_call.IsLastCall();
40 upload_state.ProcessData(method_call.argument, is_last_call); 40 upload_state.ProcessData(method_call.argument, is_last_call);
41 if (is_last_call) { 41 if (is_last_call) {
42 system.GPU().Maxwell3D().dirty.OnMemoryWrite(); 42 system.GPU().Maxwell3D().OnMemoryWrite();
43 } 43 }
44 break; 44 break;
45 } 45 }
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index fa4a7c5c1..597872e43 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -34,7 +34,7 @@ void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) {
34 const bool is_last_call = method_call.IsLastCall(); 34 const bool is_last_call = method_call.IsLastCall();
35 upload_state.ProcessData(method_call.argument, is_last_call); 35 upload_state.ProcessData(method_call.argument, is_last_call);
36 if (is_last_call) { 36 if (is_last_call) {
37 system.GPU().Maxwell3D().dirty.OnMemoryWrite(); 37 system.GPU().Maxwell3D().OnMemoryWrite();
38 } 38 }
39 break; 39 break;
40 } 40 }
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index b28de1092..89050361e 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -26,7 +26,8 @@ Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& raste
26 MemoryManager& memory_manager) 26 MemoryManager& memory_manager)
27 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, 27 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager},
28 macro_interpreter{*this}, upload_state{memory_manager, regs.upload} { 28 macro_interpreter{*this}, upload_state{memory_manager, regs.upload} {
29 InitDirtySettings(); 29 dirty.flags.flip();
30
30 InitializeRegisterDefaults(); 31 InitializeRegisterDefaults();
31} 32}
32 33
@@ -75,8 +76,8 @@ void Maxwell3D::InitializeRegisterDefaults() {
75 regs.stencil_back_mask = 0xFFFFFFFF; 76 regs.stencil_back_mask = 0xFFFFFFFF;
76 77
77 regs.depth_test_func = Regs::ComparisonOp::Always; 78 regs.depth_test_func = Regs::ComparisonOp::Always;
78 regs.cull.front_face = Regs::Cull::FrontFace::CounterClockWise; 79 regs.front_face = Regs::FrontFace::CounterClockWise;
79 regs.cull.cull_face = Regs::Cull::CullFace::Back; 80 regs.cull_face = Regs::CullFace::Back;
80 81
81 // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a 82 // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
82 // register carrying a default value. Assume it's OpenGL's default (1). 83 // register carrying a default value. Assume it's OpenGL's default (1).
@@ -95,7 +96,7 @@ void Maxwell3D::InitializeRegisterDefaults() {
95 regs.rasterize_enable = 1; 96 regs.rasterize_enable = 1;
96 regs.rt_separate_frag_data = 1; 97 regs.rt_separate_frag_data = 1;
97 regs.framebuffer_srgb = 1; 98 regs.framebuffer_srgb = 1;
98 regs.cull.front_face = Maxwell3D::Regs::Cull::FrontFace::ClockWise; 99 regs.front_face = Maxwell3D::Regs::FrontFace::ClockWise;
99 100
100 mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; 101 mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true;
101 mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; 102 mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true;
@@ -103,164 +104,6 @@ void Maxwell3D::InitializeRegisterDefaults() {
103 mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true; 104 mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
104} 105}
105 106
106#define DIRTY_REGS_POS(field_name) static_cast<u8>(offsetof(Maxwell3D::DirtyRegs, field_name))
107
108void Maxwell3D::InitDirtySettings() {
109 const auto set_block = [this](std::size_t start, std::size_t range, u8 position) {
110 const auto start_itr = dirty_pointers.begin() + start;
111 const auto end_itr = start_itr + range;
112 std::fill(start_itr, end_itr, position);
113 };
114 dirty.regs.fill(true);
115
116 // Init Render Targets
117 constexpr u32 registers_per_rt = sizeof(regs.rt[0]) / sizeof(u32);
118 constexpr u32 rt_start_reg = MAXWELL3D_REG_INDEX(rt);
119 constexpr u32 rt_end_reg = rt_start_reg + registers_per_rt * 8;
120 u8 rt_dirty_reg = DIRTY_REGS_POS(render_target);
121 for (u32 rt_reg = rt_start_reg; rt_reg < rt_end_reg; rt_reg += registers_per_rt) {
122 set_block(rt_reg, registers_per_rt, rt_dirty_reg);
123 ++rt_dirty_reg;
124 }
125 constexpr u32 depth_buffer_flag = DIRTY_REGS_POS(depth_buffer);
126 dirty_pointers[MAXWELL3D_REG_INDEX(zeta_enable)] = depth_buffer_flag;
127 dirty_pointers[MAXWELL3D_REG_INDEX(zeta_width)] = depth_buffer_flag;
128 dirty_pointers[MAXWELL3D_REG_INDEX(zeta_height)] = depth_buffer_flag;
129 constexpr u32 registers_in_zeta = sizeof(regs.zeta) / sizeof(u32);
130 constexpr u32 zeta_reg = MAXWELL3D_REG_INDEX(zeta);
131 set_block(zeta_reg, registers_in_zeta, depth_buffer_flag);
132
133 // Init Vertex Arrays
134 constexpr u32 vertex_array_start = MAXWELL3D_REG_INDEX(vertex_array);
135 constexpr u32 vertex_array_size = sizeof(regs.vertex_array[0]) / sizeof(u32);
136 constexpr u32 vertex_array_end = vertex_array_start + vertex_array_size * Regs::NumVertexArrays;
137 u8 va_dirty_reg = DIRTY_REGS_POS(vertex_array);
138 u8 vi_dirty_reg = DIRTY_REGS_POS(vertex_instance);
139 for (u32 vertex_reg = vertex_array_start; vertex_reg < vertex_array_end;
140 vertex_reg += vertex_array_size) {
141 set_block(vertex_reg, 3, va_dirty_reg);
142 // The divisor concerns vertex array instances
143 dirty_pointers[static_cast<std::size_t>(vertex_reg) + 3] = vi_dirty_reg;
144 ++va_dirty_reg;
145 ++vi_dirty_reg;
146 }
147 constexpr u32 vertex_limit_start = MAXWELL3D_REG_INDEX(vertex_array_limit);
148 constexpr u32 vertex_limit_size = sizeof(regs.vertex_array_limit[0]) / sizeof(u32);
149 constexpr u32 vertex_limit_end = vertex_limit_start + vertex_limit_size * Regs::NumVertexArrays;
150 va_dirty_reg = DIRTY_REGS_POS(vertex_array);
151 for (u32 vertex_reg = vertex_limit_start; vertex_reg < vertex_limit_end;
152 vertex_reg += vertex_limit_size) {
153 set_block(vertex_reg, vertex_limit_size, va_dirty_reg);
154 va_dirty_reg++;
155 }
156 constexpr u32 vertex_instance_start = MAXWELL3D_REG_INDEX(instanced_arrays);
157 constexpr u32 vertex_instance_size =
158 sizeof(regs.instanced_arrays.is_instanced[0]) / sizeof(u32);
159 constexpr u32 vertex_instance_end =
160 vertex_instance_start + vertex_instance_size * Regs::NumVertexArrays;
161 vi_dirty_reg = DIRTY_REGS_POS(vertex_instance);
162 for (u32 vertex_reg = vertex_instance_start; vertex_reg < vertex_instance_end;
163 vertex_reg += vertex_instance_size) {
164 set_block(vertex_reg, vertex_instance_size, vi_dirty_reg);
165 vi_dirty_reg++;
166 }
167 set_block(MAXWELL3D_REG_INDEX(vertex_attrib_format), regs.vertex_attrib_format.size(),
168 DIRTY_REGS_POS(vertex_attrib_format));
169
170 // Init Shaders
171 constexpr u32 shader_registers_count =
172 sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32);
173 set_block(MAXWELL3D_REG_INDEX(shader_config[0]), shader_registers_count,
174 DIRTY_REGS_POS(shaders));
175
176 // State
177
178 // Viewport
179 constexpr u8 viewport_dirty_reg = DIRTY_REGS_POS(viewport);
180 constexpr u32 viewport_start = MAXWELL3D_REG_INDEX(viewports);
181 constexpr u32 viewport_size = sizeof(regs.viewports) / sizeof(u32);
182 set_block(viewport_start, viewport_size, viewport_dirty_reg);
183 constexpr u32 view_volume_start = MAXWELL3D_REG_INDEX(view_volume_clip_control);
184 constexpr u32 view_volume_size = sizeof(regs.view_volume_clip_control) / sizeof(u32);
185 set_block(view_volume_start, view_volume_size, viewport_dirty_reg);
186
187 // Viewport transformation
188 constexpr u32 viewport_trans_start = MAXWELL3D_REG_INDEX(viewport_transform);
189 constexpr u32 viewport_trans_size = sizeof(regs.viewport_transform) / sizeof(u32);
190 set_block(viewport_trans_start, viewport_trans_size, DIRTY_REGS_POS(viewport_transform));
191
192 // Cullmode
193 constexpr u32 cull_mode_start = MAXWELL3D_REG_INDEX(cull);
194 constexpr u32 cull_mode_size = sizeof(regs.cull) / sizeof(u32);
195 set_block(cull_mode_start, cull_mode_size, DIRTY_REGS_POS(cull_mode));
196
197 // Screen y control
198 dirty_pointers[MAXWELL3D_REG_INDEX(screen_y_control)] = DIRTY_REGS_POS(screen_y_control);
199
200 // Primitive Restart
201 constexpr u32 primitive_restart_start = MAXWELL3D_REG_INDEX(primitive_restart);
202 constexpr u32 primitive_restart_size = sizeof(regs.primitive_restart) / sizeof(u32);
203 set_block(primitive_restart_start, primitive_restart_size, DIRTY_REGS_POS(primitive_restart));
204
205 // Depth Test
206 constexpr u8 depth_test_dirty_reg = DIRTY_REGS_POS(depth_test);
207 dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_enable)] = depth_test_dirty_reg;
208 dirty_pointers[MAXWELL3D_REG_INDEX(depth_write_enabled)] = depth_test_dirty_reg;
209 dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_func)] = depth_test_dirty_reg;
210
211 // Stencil Test
212 constexpr u32 stencil_test_dirty_reg = DIRTY_REGS_POS(stencil_test);
213 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_enable)] = stencil_test_dirty_reg;
214 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_func)] = stencil_test_dirty_reg;
215 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_ref)] = stencil_test_dirty_reg;
216 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_mask)] = stencil_test_dirty_reg;
217 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_fail)] = stencil_test_dirty_reg;
218 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zfail)] = stencil_test_dirty_reg;
219 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zpass)] = stencil_test_dirty_reg;
220 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_mask)] = stencil_test_dirty_reg;
221 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_two_side_enable)] = stencil_test_dirty_reg;
222 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_func)] = stencil_test_dirty_reg;
223 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_ref)] = stencil_test_dirty_reg;
224 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_mask)] = stencil_test_dirty_reg;
225 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_fail)] = stencil_test_dirty_reg;
226 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zfail)] = stencil_test_dirty_reg;
227 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zpass)] = stencil_test_dirty_reg;
228 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_mask)] = stencil_test_dirty_reg;
229
230 // Color Mask
231 constexpr u8 color_mask_dirty_reg = DIRTY_REGS_POS(color_mask);
232 dirty_pointers[MAXWELL3D_REG_INDEX(color_mask_common)] = color_mask_dirty_reg;
233 set_block(MAXWELL3D_REG_INDEX(color_mask), sizeof(regs.color_mask) / sizeof(u32),
234 color_mask_dirty_reg);
235 // Blend State
236 constexpr u8 blend_state_dirty_reg = DIRTY_REGS_POS(blend_state);
237 set_block(MAXWELL3D_REG_INDEX(blend_color), sizeof(regs.blend_color) / sizeof(u32),
238 blend_state_dirty_reg);
239 dirty_pointers[MAXWELL3D_REG_INDEX(independent_blend_enable)] = blend_state_dirty_reg;
240 set_block(MAXWELL3D_REG_INDEX(blend), sizeof(regs.blend) / sizeof(u32), blend_state_dirty_reg);
241 set_block(MAXWELL3D_REG_INDEX(independent_blend), sizeof(regs.independent_blend) / sizeof(u32),
242 blend_state_dirty_reg);
243
244 // Scissor State
245 constexpr u8 scissor_test_dirty_reg = DIRTY_REGS_POS(scissor_test);
246 set_block(MAXWELL3D_REG_INDEX(scissor_test), sizeof(regs.scissor_test) / sizeof(u32),
247 scissor_test_dirty_reg);
248
249 // Polygon Offset
250 constexpr u8 polygon_offset_dirty_reg = DIRTY_REGS_POS(polygon_offset);
251 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_fill_enable)] = polygon_offset_dirty_reg;
252 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_line_enable)] = polygon_offset_dirty_reg;
253 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_point_enable)] = polygon_offset_dirty_reg;
254 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_units)] = polygon_offset_dirty_reg;
255 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_factor)] = polygon_offset_dirty_reg;
256 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg;
257
258 // Depth bounds
259 constexpr u8 depth_bounds_values_dirty_reg = DIRTY_REGS_POS(depth_bounds_values);
260 dirty_pointers[MAXWELL3D_REG_INDEX(depth_bounds[0])] = depth_bounds_values_dirty_reg;
261 dirty_pointers[MAXWELL3D_REG_INDEX(depth_bounds[1])] = depth_bounds_values_dirty_reg;
262}
263
264void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters) { 107void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters) {
265 // Reset the current macro. 108 // Reset the current macro.
266 executing_macro = 0; 109 executing_macro = 0;
@@ -319,19 +162,9 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
319 162
320 if (regs.reg_array[method] != method_call.argument) { 163 if (regs.reg_array[method] != method_call.argument) {
321 regs.reg_array[method] = method_call.argument; 164 regs.reg_array[method] = method_call.argument;
322 const std::size_t dirty_reg = dirty_pointers[method]; 165
323 if (dirty_reg) { 166 for (const auto& table : dirty.tables) {
324 dirty.regs[dirty_reg] = true; 167 dirty.flags[table[method]] = true;
325 if (dirty_reg >= DIRTY_REGS_POS(vertex_array) &&
326 dirty_reg < DIRTY_REGS_POS(vertex_array_buffers)) {
327 dirty.vertex_array_buffers = true;
328 } else if (dirty_reg >= DIRTY_REGS_POS(vertex_instance) &&
329 dirty_reg < DIRTY_REGS_POS(vertex_instances)) {
330 dirty.vertex_instances = true;
331 } else if (dirty_reg >= DIRTY_REGS_POS(render_target) &&
332 dirty_reg < DIRTY_REGS_POS(render_settings)) {
333 dirty.render_settings = true;
334 }
335 } 168 }
336 } 169 }
337 170
@@ -419,7 +252,7 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
419 const bool is_last_call = method_call.IsLastCall(); 252 const bool is_last_call = method_call.IsLastCall();
420 upload_state.ProcessData(method_call.argument, is_last_call); 253 upload_state.ProcessData(method_call.argument, is_last_call);
421 if (is_last_call) { 254 if (is_last_call) {
422 dirty.OnMemoryWrite(); 255 OnMemoryWrite();
423 } 256 }
424 break; 257 break;
425 } 258 }
@@ -727,7 +560,7 @@ void Maxwell3D::FinishCBData() {
727 560
728 const u32 id = cb_data_state.id; 561 const u32 id = cb_data_state.id;
729 memory_manager.WriteBlock(address, cb_data_state.buffer[id].data(), size); 562 memory_manager.WriteBlock(address, cb_data_state.buffer[id].data(), size);
730 dirty.OnMemoryWrite(); 563 OnMemoryWrite();
731 564
732 cb_data_state.id = null_cb_data; 565 cb_data_state.id = null_cb_data;
733 cb_data_state.current = null_cb_data; 566 cb_data_state.current = null_cb_data;
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 6ea7cc6a5..491cff370 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <bitset> 8#include <bitset>
9#include <limits>
9#include <optional> 10#include <optional>
10#include <type_traits> 11#include <type_traits>
11#include <unordered_map> 12#include <unordered_map>
@@ -431,21 +432,15 @@ public:
431 GeneratedPrimitives = 0x1F, 432 GeneratedPrimitives = 0x1F,
432 }; 433 };
433 434
434 struct Cull { 435 enum class FrontFace : u32 {
435 enum class FrontFace : u32 { 436 ClockWise = 0x0900,
436 ClockWise = 0x0900, 437 CounterClockWise = 0x0901,
437 CounterClockWise = 0x0901, 438 };
438 };
439
440 enum class CullFace : u32 {
441 Front = 0x0404,
442 Back = 0x0405,
443 FrontAndBack = 0x0408,
444 };
445 439
446 u32 enabled; 440 enum class CullFace : u32 {
447 FrontFace front_face; 441 Front = 0x0404,
448 CullFace cull_face; 442 Back = 0x0405,
443 FrontAndBack = 0x0408,
449 }; 444 };
450 445
451 struct Blend { 446 struct Blend {
@@ -574,7 +569,7 @@ public:
574 f32 translate_z; 569 f32 translate_z;
575 INSERT_UNION_PADDING_WORDS(2); 570 INSERT_UNION_PADDING_WORDS(2);
576 571
577 Common::Rectangle<s32> GetRect() const { 572 Common::Rectangle<f32> GetRect() const {
578 return { 573 return {
579 GetX(), // left 574 GetX(), // left
580 GetY() + GetHeight(), // top 575 GetY() + GetHeight(), // top
@@ -583,20 +578,20 @@ public:
583 }; 578 };
584 }; 579 };
585 580
586 s32 GetX() const { 581 f32 GetX() const {
587 return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x))); 582 return std::max(0.0f, translate_x - std::fabs(scale_x));
588 } 583 }
589 584
590 s32 GetY() const { 585 f32 GetY() const {
591 return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y))); 586 return std::max(0.0f, translate_y - std::fabs(scale_y));
592 } 587 }
593 588
594 s32 GetWidth() const { 589 f32 GetWidth() const {
595 return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX(); 590 return translate_x + std::fabs(scale_x) - GetX();
596 } 591 }
597 592
598 s32 GetHeight() const { 593 f32 GetHeight() const {
599 return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY(); 594 return translate_y + std::fabs(scale_y) - GetY();
600 } 595 }
601 }; 596 };
602 597
@@ -872,16 +867,7 @@ public:
872 867
873 INSERT_UNION_PADDING_WORDS(0x35); 868 INSERT_UNION_PADDING_WORDS(0x35);
874 869
875 union { 870 u32 clip_distance_enabled;
876 BitField<0, 1, u32> c0;
877 BitField<1, 1, u32> c1;
878 BitField<2, 1, u32> c2;
879 BitField<3, 1, u32> c3;
880 BitField<4, 1, u32> c4;
881 BitField<5, 1, u32> c5;
882 BitField<6, 1, u32> c6;
883 BitField<7, 1, u32> c7;
884 } clip_distance_enabled;
885 871
886 u32 samplecnt_enable; 872 u32 samplecnt_enable;
887 873
@@ -1060,7 +1046,9 @@ public:
1060 1046
1061 INSERT_UNION_PADDING_WORDS(1); 1047 INSERT_UNION_PADDING_WORDS(1);
1062 1048
1063 Cull cull; 1049 u32 cull_test_enabled;
1050 FrontFace front_face;
1051 CullFace cull_face;
1064 1052
1065 u32 pixel_center_integer; 1053 u32 pixel_center_integer;
1066 1054
@@ -1238,79 +1226,6 @@ public:
1238 1226
1239 State state{}; 1227 State state{};
1240 1228
1241 struct DirtyRegs {
1242 static constexpr std::size_t NUM_REGS = 256;
1243 static_assert(NUM_REGS - 1 <= std::numeric_limits<u8>::max());
1244
1245 union {
1246 struct {
1247 bool null_dirty;
1248
1249 // Vertex Attributes
1250 bool vertex_attrib_format;
1251
1252 // Vertex Arrays
1253 std::array<bool, 32> vertex_array;
1254
1255 bool vertex_array_buffers;
1256
1257 // Vertex Instances
1258 std::array<bool, 32> vertex_instance;
1259
1260 bool vertex_instances;
1261
1262 // Render Targets
1263 std::array<bool, 8> render_target;
1264 bool depth_buffer;
1265
1266 bool render_settings;
1267
1268 // Shaders
1269 bool shaders;
1270
1271 // Rasterizer State
1272 bool viewport;
1273 bool clip_coefficient;
1274 bool cull_mode;
1275 bool primitive_restart;
1276 bool depth_test;
1277 bool stencil_test;
1278 bool blend_state;
1279 bool scissor_test;
1280 bool transform_feedback;
1281 bool color_mask;
1282 bool polygon_offset;
1283 bool depth_bounds_values;
1284
1285 // Complementary
1286 bool viewport_transform;
1287 bool screen_y_control;
1288
1289 bool memory_general;
1290 };
1291 std::array<bool, NUM_REGS> regs;
1292 };
1293
1294 void ResetVertexArrays() {
1295 vertex_array.fill(true);
1296 vertex_array_buffers = true;
1297 }
1298
1299 void ResetRenderTargets() {
1300 depth_buffer = true;
1301 render_target.fill(true);
1302 render_settings = true;
1303 }
1304
1305 void OnMemoryWrite() {
1306 shaders = true;
1307 memory_general = true;
1308 ResetRenderTargets();
1309 ResetVertexArrays();
1310 }
1311
1312 } dirty{};
1313
1314 /// Reads a register value located at the input method address 1229 /// Reads a register value located at the input method address
1315 u32 GetRegisterValue(u32 method) const; 1230 u32 GetRegisterValue(u32 method) const;
1316 1231
@@ -1356,6 +1271,11 @@ public:
1356 return execute_on; 1271 return execute_on;
1357 } 1272 }
1358 1273
1274 /// Notify a memory write has happened.
1275 void OnMemoryWrite() {
1276 dirty.flags |= dirty.on_write_stores;
1277 }
1278
1359 enum class MMEDrawMode : u32 { 1279 enum class MMEDrawMode : u32 {
1360 Undefined, 1280 Undefined,
1361 Array, 1281 Array,
@@ -1371,6 +1291,16 @@ public:
1371 u32 gl_end_count{}; 1291 u32 gl_end_count{};
1372 } mme_draw; 1292 } mme_draw;
1373 1293
1294 struct DirtyState {
1295 using Flags = std::bitset<std::numeric_limits<u8>::max()>;
1296 using Table = std::array<u8, Regs::NUM_REGS>;
1297 using Tables = std::array<Table, 2>;
1298
1299 Flags flags;
1300 Flags on_write_stores;
1301 Tables tables{};
1302 } dirty;
1303
1374private: 1304private:
1375 void InitializeRegisterDefaults(); 1305 void InitializeRegisterDefaults();
1376 1306
@@ -1417,8 +1347,6 @@ private:
1417 /// Retrieves information about a specific TSC entry from the TSC buffer. 1347 /// Retrieves information about a specific TSC entry from the TSC buffer.
1418 Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; 1348 Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
1419 1349
1420 void InitDirtySettings();
1421
1422 /** 1350 /**
1423 * Call a macro on this engine. 1351 * Call a macro on this engine.
1424 * @param method Method to call 1352 * @param method Method to call
@@ -1561,7 +1489,9 @@ ASSERT_REG_POSITION(index_array, 0x5F2);
1561ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); 1489ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
1562ASSERT_REG_POSITION(instanced_arrays, 0x620); 1490ASSERT_REG_POSITION(instanced_arrays, 0x620);
1563ASSERT_REG_POSITION(vp_point_size, 0x644); 1491ASSERT_REG_POSITION(vp_point_size, 0x644);
1564ASSERT_REG_POSITION(cull, 0x646); 1492ASSERT_REG_POSITION(cull_test_enabled, 0x646);
1493ASSERT_REG_POSITION(front_face, 0x647);
1494ASSERT_REG_POSITION(cull_face, 0x648);
1565ASSERT_REG_POSITION(pixel_center_integer, 0x649); 1495ASSERT_REG_POSITION(pixel_center_integer, 0x649);
1566ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); 1496ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
1567ASSERT_REG_POSITION(view_volume_clip_control, 0x64F); 1497ASSERT_REG_POSITION(view_volume_clip_control, 0x64F);
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index ad8453c5f..c2610f992 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -57,7 +57,7 @@ void MaxwellDMA::HandleCopy() {
57 } 57 }
58 58
59 // All copies here update the main memory, so mark all rasterizer states as invalid. 59 // All copies here update the main memory, so mark all rasterizer states as invalid.
60 system.GPU().Maxwell3D().dirty.OnMemoryWrite(); 60 system.GPU().Maxwell3D().OnMemoryWrite();
61 61
62 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { 62 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
63 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D 63 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index f18eaf4bc..3e4514b94 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -89,6 +89,9 @@ public:
89 virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false, 89 virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false,
90 const DiskResourceLoadCallback& callback = {}) {} 90 const DiskResourceLoadCallback& callback = {}) {}
91 91
92 /// Initializes renderer dirty flags
93 virtual void SetupDirtyFlags() {}
94
92 /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver. 95 /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
93 GuestDriverProfile& AccessGuestDriverProfile() { 96 GuestDriverProfile& AccessGuestDriverProfile() {
94 return guest_driver_profile; 97 return guest_driver_profile;
diff --git a/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp b/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
index 874ed3c6e..b8a512cb6 100644
--- a/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
@@ -11,7 +11,6 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/renderer_opengl/gl_framebuffer_cache.h" 13#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
14#include "video_core/renderer_opengl/gl_state.h"
15 14
16namespace OpenGL { 15namespace OpenGL {
17 16
@@ -36,8 +35,7 @@ OGLFramebuffer FramebufferCacheOpenGL::CreateFramebuffer(const FramebufferCacheK
36 framebuffer.Create(); 35 framebuffer.Create();
37 36
38 // TODO(Rodrigo): Use DSA here after Nvidia fixes their framebuffer DSA bugs. 37 // TODO(Rodrigo): Use DSA here after Nvidia fixes their framebuffer DSA bugs.
39 local_state.draw.draw_framebuffer = framebuffer.handle; 38 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle);
40 local_state.ApplyFramebufferState();
41 39
42 if (key.zeta) { 40 if (key.zeta) {
43 const bool stencil = key.zeta->GetSurfaceParams().type == SurfaceType::DepthStencil; 41 const bool stencil = key.zeta->GetSurfaceParams().type == SurfaceType::DepthStencil;
diff --git a/src/video_core/renderer_opengl/gl_framebuffer_cache.h b/src/video_core/renderer_opengl/gl_framebuffer_cache.h
index 02ec80ae9..8f698fee0 100644
--- a/src/video_core/renderer_opengl/gl_framebuffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_framebuffer_cache.h
@@ -13,7 +13,6 @@
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "video_core/engines/maxwell_3d.h" 14#include "video_core/engines/maxwell_3d.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h" 15#include "video_core/renderer_opengl/gl_resource_manager.h"
16#include "video_core/renderer_opengl/gl_state.h"
17#include "video_core/renderer_opengl/gl_texture_cache.h" 16#include "video_core/renderer_opengl/gl_texture_cache.h"
18 17
19namespace OpenGL { 18namespace OpenGL {
@@ -63,7 +62,6 @@ public:
63private: 62private:
64 OGLFramebuffer CreateFramebuffer(const FramebufferCacheKey& key); 63 OGLFramebuffer CreateFramebuffer(const FramebufferCacheKey& key);
65 64
66 OpenGLState local_state;
67 std::unordered_map<FramebufferCacheKey, OGLFramebuffer> cache; 65 std::unordered_map<FramebufferCacheKey, OGLFramebuffer> cache;
68}; 66};
69 67
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 3fcd319fd..55324e6d5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -55,6 +55,8 @@ MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255
55 55
56namespace { 56namespace {
57 57
58constexpr std::size_t NumSupportedVertexAttributes = 16;
59
58template <typename Engine, typename Entry> 60template <typename Engine, typename Entry>
59Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry, 61Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
60 ShaderType shader_type, std::size_t index = 0) { 62 ShaderType shader_type, std::size_t index = 0) {
@@ -88,18 +90,23 @@ std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
88 return buffer.size; 90 return buffer.size;
89} 91}
90 92
93void oglEnable(GLenum cap, bool state) {
94 (state ? glEnable : glDisable)(cap);
95}
96
97void oglEnablei(GLenum cap, bool state, GLuint index) {
98 (state ? glEnablei : glDisablei)(cap, index);
99}
100
91} // Anonymous namespace 101} // Anonymous namespace
92 102
93RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 103RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
94 ScreenInfo& info) 104 ScreenInfo& info, GLShader::ProgramManager& program_manager,
95 : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device}, 105 StateTracker& state_tracker)
106 : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device, state_tracker},
96 shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system}, 107 shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
97 screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} { 108 screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
98 shader_program_manager = std::make_unique<GLShader::ProgramManager>(); 109 buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
99 state.draw.shader_program = 0;
100 state.Apply();
101
102 LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here");
103 CheckExtensions(); 110 CheckExtensions();
104} 111}
105 112
@@ -113,93 +120,72 @@ void RasterizerOpenGL::CheckExtensions() {
113 } 120 }
114} 121}
115 122
116GLuint RasterizerOpenGL::SetupVertexFormat() { 123void RasterizerOpenGL::SetupVertexFormat() {
117 auto& gpu = system.GPU().Maxwell3D(); 124 auto& gpu = system.GPU().Maxwell3D();
118 const auto& regs = gpu.regs; 125 auto& flags = gpu.dirty.flags;
119 126 if (!flags[Dirty::VertexFormats]) {
120 if (!gpu.dirty.vertex_attrib_format) { 127 return;
121 return state.draw.vertex_array;
122 } 128 }
123 gpu.dirty.vertex_attrib_format = false; 129 flags[Dirty::VertexFormats] = false;
124 130
125 MICROPROFILE_SCOPE(OpenGL_VAO); 131 MICROPROFILE_SCOPE(OpenGL_VAO);
126 132
127 auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); 133 // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. Enables
128 auto& vao_entry = iter->second; 134 // the first 16 vertex attributes always, as we don't know which ones are actually used until
129 135 // shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now to
130 if (is_cache_miss) { 136 // avoid OpenGL errors.
131 vao_entry.Create(); 137 // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
132 const GLuint vao = vao_entry.handle; 138 // assume every shader uses them all.
133 139 for (std::size_t index = 0; index < NumSupportedVertexAttributes; ++index) {
134 // Eventhough we are using DSA to create this vertex array, there is a bug on Intel's blob 140 if (!flags[Dirty::VertexFormat0 + index]) {
135 // that fails to properly create the vertex array if it's not bound even after creating it 141 continue;
136 // with glCreateVertexArrays
137 state.draw.vertex_array = vao;
138 state.ApplyVertexArrayState();
139
140 // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
141 // Enables the first 16 vertex attributes always, as we don't know which ones are actually
142 // used until shader time. Note, Tegra technically supports 32, but we're capping this to 16
143 // for now to avoid OpenGL errors.
144 // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
145 // assume every shader uses them all.
146 for (u32 index = 0; index < 16; ++index) {
147 const auto& attrib = regs.vertex_attrib_format[index];
148
149 // Ignore invalid attributes.
150 if (!attrib.IsValid())
151 continue;
152
153 const auto& buffer = regs.vertex_array[attrib.buffer];
154 LOG_TRACE(Render_OpenGL,
155 "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
156 index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
157 attrib.offset.Value(), attrib.IsNormalized());
158
159 ASSERT(buffer.IsEnabled());
160
161 glEnableVertexArrayAttrib(vao, index);
162 if (attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SignedInt ||
163 attrib.type ==
164 Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnsignedInt) {
165 glVertexArrayAttribIFormat(vao, index, attrib.ComponentCount(),
166 MaxwellToGL::VertexType(attrib), attrib.offset);
167 } else {
168 glVertexArrayAttribFormat(
169 vao, index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
170 attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
171 }
172 glVertexArrayAttribBinding(vao, index, attrib.buffer);
173 } 142 }
174 } 143 flags[Dirty::VertexFormat0 + index] = false;
144
145 const auto attrib = gpu.regs.vertex_attrib_format[index];
146 const auto gl_index = static_cast<GLuint>(index);
175 147
176 // Rebinding the VAO invalidates the vertex buffer bindings. 148 // Ignore invalid attributes.
177 gpu.dirty.ResetVertexArrays(); 149 if (!attrib.IsValid()) {
150 glDisableVertexAttribArray(gl_index);
151 continue;
152 }
153 glEnableVertexAttribArray(gl_index);
178 154
179 state.draw.vertex_array = vao_entry.handle; 155 if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt ||
180 return vao_entry.handle; 156 attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) {
157 glVertexAttribIFormat(gl_index, attrib.ComponentCount(),
158 MaxwellToGL::VertexType(attrib), attrib.offset);
159 } else {
160 glVertexAttribFormat(gl_index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
161 attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
162 }
163 glVertexAttribBinding(gl_index, attrib.buffer);
164 }
181} 165}
182 166
183void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { 167void RasterizerOpenGL::SetupVertexBuffer() {
184 auto& gpu = system.GPU().Maxwell3D(); 168 auto& gpu = system.GPU().Maxwell3D();
185 if (!gpu.dirty.vertex_array_buffers) 169 auto& flags = gpu.dirty.flags;
170 if (!flags[Dirty::VertexBuffers]) {
186 return; 171 return;
187 gpu.dirty.vertex_array_buffers = false; 172 }
188 173 flags[Dirty::VertexBuffers] = false;
189 const auto& regs = gpu.regs;
190 174
191 MICROPROFILE_SCOPE(OpenGL_VB); 175 MICROPROFILE_SCOPE(OpenGL_VB);
192 176
193 // Upload all guest vertex arrays sequentially to our buffer 177 // Upload all guest vertex arrays sequentially to our buffer
194 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 178 const auto& regs = gpu.regs;
195 if (!gpu.dirty.vertex_array[index]) 179 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
180 if (!flags[Dirty::VertexBuffer0 + index]) {
196 continue; 181 continue;
197 gpu.dirty.vertex_array[index] = false; 182 }
198 gpu.dirty.vertex_instance[index] = false; 183 flags[Dirty::VertexBuffer0 + index] = false;
199 184
200 const auto& vertex_array = regs.vertex_array[index]; 185 const auto& vertex_array = regs.vertex_array[index];
201 if (!vertex_array.IsEnabled()) 186 if (!vertex_array.IsEnabled()) {
202 continue; 187 continue;
188 }
203 189
204 const GPUVAddr start = vertex_array.StartAddress(); 190 const GPUVAddr start = vertex_array.StartAddress();
205 const GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); 191 const GPUVAddr end = regs.vertex_array_limit[index].LimitAddress();
@@ -209,42 +195,30 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) {
209 const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size); 195 const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size);
210 196
211 // Bind the vertex array to the buffer at the current offset. 197 // Bind the vertex array to the buffer at the current offset.
212 vertex_array_pushbuffer.SetVertexBuffer(index, vertex_buffer, vertex_buffer_offset, 198 vertex_array_pushbuffer.SetVertexBuffer(static_cast<GLuint>(index), vertex_buffer,
213 vertex_array.stride); 199 vertex_buffer_offset, vertex_array.stride);
214
215 if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) {
216 // Enable vertex buffer instancing with the specified divisor.
217 glVertexArrayBindingDivisor(vao, index, vertex_array.divisor);
218 } else {
219 // Disable the vertex buffer instancing.
220 glVertexArrayBindingDivisor(vao, index, 0);
221 }
222 } 200 }
223} 201}
224 202
225void RasterizerOpenGL::SetupVertexInstances(GLuint vao) { 203void RasterizerOpenGL::SetupVertexInstances() {
226 auto& gpu = system.GPU().Maxwell3D(); 204 auto& gpu = system.GPU().Maxwell3D();
227 205 auto& flags = gpu.dirty.flags;
228 if (!gpu.dirty.vertex_instances) 206 if (!flags[Dirty::VertexInstances]) {
229 return; 207 return;
230 gpu.dirty.vertex_instances = false; 208 }
209 flags[Dirty::VertexInstances] = false;
231 210
232 const auto& regs = gpu.regs; 211 const auto& regs = gpu.regs;
233 // Upload all guest vertex arrays sequentially to our buffer 212 for (std::size_t index = 0; index < NumSupportedVertexAttributes; ++index) {
234 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 213 if (!flags[Dirty::VertexInstance0 + index]) {
235 if (!gpu.dirty.vertex_instance[index])
236 continue; 214 continue;
237
238 gpu.dirty.vertex_instance[index] = false;
239
240 if (regs.instanced_arrays.IsInstancingEnabled(index) &&
241 regs.vertex_array[index].divisor != 0) {
242 // Enable vertex buffer instancing with the specified divisor.
243 glVertexArrayBindingDivisor(vao, index, regs.vertex_array[index].divisor);
244 } else {
245 // Disable the vertex buffer instancing.
246 glVertexArrayBindingDivisor(vao, index, 0);
247 } 215 }
216 flags[Dirty::VertexInstance0 + index] = false;
217
218 const auto gl_index = static_cast<GLuint>(index);
219 const bool instancing_enabled = regs.instanced_arrays.IsInstancingEnabled(gl_index);
220 const GLuint divisor = instancing_enabled ? regs.vertex_array[index].divisor : 0;
221 glVertexBindingDivisor(gl_index, divisor);
248 } 222 }
249} 223}
250 224
@@ -260,8 +234,7 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
260void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { 234void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
261 MICROPROFILE_SCOPE(OpenGL_Shader); 235 MICROPROFILE_SCOPE(OpenGL_Shader);
262 auto& gpu = system.GPU().Maxwell3D(); 236 auto& gpu = system.GPU().Maxwell3D();
263 237 u32 clip_distances = 0;
264 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
265 238
266 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 239 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
267 const auto& shader_config = gpu.regs.shader_config[index]; 240 const auto& shader_config = gpu.regs.shader_config[index];
@@ -271,10 +244,10 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
271 if (!gpu.regs.IsShaderConfigEnabled(index)) { 244 if (!gpu.regs.IsShaderConfigEnabled(index)) {
272 switch (program) { 245 switch (program) {
273 case Maxwell::ShaderProgram::Geometry: 246 case Maxwell::ShaderProgram::Geometry:
274 shader_program_manager->UseTrivialGeometryShader(); 247 program_manager.UseGeometryShader(0);
275 break; 248 break;
276 case Maxwell::ShaderProgram::Fragment: 249 case Maxwell::ShaderProgram::Fragment:
277 shader_program_manager->UseTrivialFragmentShader(); 250 program_manager.UseFragmentShader(0);
278 break; 251 break;
279 default: 252 default:
280 break; 253 break;
@@ -305,13 +278,13 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
305 switch (program) { 278 switch (program) {
306 case Maxwell::ShaderProgram::VertexA: 279 case Maxwell::ShaderProgram::VertexA:
307 case Maxwell::ShaderProgram::VertexB: 280 case Maxwell::ShaderProgram::VertexB:
308 shader_program_manager->UseProgrammableVertexShader(program_handle); 281 program_manager.UseVertexShader(program_handle);
309 break; 282 break;
310 case Maxwell::ShaderProgram::Geometry: 283 case Maxwell::ShaderProgram::Geometry:
311 shader_program_manager->UseProgrammableGeometryShader(program_handle); 284 program_manager.UseGeometryShader(program_handle);
312 break; 285 break;
313 case Maxwell::ShaderProgram::Fragment: 286 case Maxwell::ShaderProgram::Fragment:
314 shader_program_manager->UseProgrammableFragmentShader(program_handle); 287 program_manager.UseFragmentShader(program_handle);
315 break; 288 break;
316 default: 289 default:
317 UNIMPLEMENTED_MSG("Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, 290 UNIMPLEMENTED_MSG("Unimplemented shader index={}, enable={}, offset=0x{:08X}", index,
@@ -322,9 +295,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
322 // When a clip distance is enabled but not set in the shader it crops parts of the screen 295 // When a clip distance is enabled but not set in the shader it crops parts of the screen
323 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the 296 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
324 // clip distances only when it's written by a shader stage. 297 // clip distances only when it's written by a shader stage.
325 for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) { 298 clip_distances |= shader->GetShaderEntries().clip_distances;
326 clip_distances[i] = clip_distances[i] || shader->GetShaderEntries().clip_distances[i];
327 }
328 299
329 // When VertexA is enabled, we have dual vertex shaders 300 // When VertexA is enabled, we have dual vertex shaders
330 if (program == Maxwell::ShaderProgram::VertexA) { 301 if (program == Maxwell::ShaderProgram::VertexA) {
@@ -334,8 +305,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
334 } 305 }
335 306
336 SyncClipEnabled(clip_distances); 307 SyncClipEnabled(clip_distances);
337 308 gpu.dirty.flags[Dirty::Shaders] = false;
338 gpu.dirty.shaders = false;
339} 309}
340 310
341std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 311std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -368,20 +338,23 @@ void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading,
368 shader_cache.LoadDiskCache(stop_loading, callback); 338 shader_cache.LoadDiskCache(stop_loading, callback);
369} 339}
370 340
341void RasterizerOpenGL::SetupDirtyFlags() {
342 state_tracker.Initialize();
343}
344
371void RasterizerOpenGL::ConfigureFramebuffers() { 345void RasterizerOpenGL::ConfigureFramebuffers() {
372 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 346 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
373 auto& gpu = system.GPU().Maxwell3D(); 347 auto& gpu = system.GPU().Maxwell3D();
374 if (!gpu.dirty.render_settings) { 348 if (!gpu.dirty.flags[VideoCommon::Dirty::RenderTargets]) {
375 return; 349 return;
376 } 350 }
377 gpu.dirty.render_settings = false; 351 gpu.dirty.flags[VideoCommon::Dirty::RenderTargets] = false;
378 352
379 texture_cache.GuardRenderTargets(true); 353 texture_cache.GuardRenderTargets(true);
380 354
381 View depth_surface = texture_cache.GetDepthBufferSurface(true); 355 View depth_surface = texture_cache.GetDepthBufferSurface(true);
382 356
383 const auto& regs = gpu.regs; 357 const auto& regs = gpu.regs;
384 state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
385 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); 358 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0);
386 359
387 // Bind the framebuffer surfaces 360 // Bind the framebuffer surfaces
@@ -409,14 +382,11 @@ void RasterizerOpenGL::ConfigureFramebuffers() {
409 382
410 texture_cache.GuardRenderTargets(false); 383 texture_cache.GuardRenderTargets(false);
411 384
412 state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(key); 385 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer_cache.GetFramebuffer(key));
413 SyncViewport(state);
414} 386}
415 387
416void RasterizerOpenGL::ConfigureClearFramebuffer(OpenGLState& current_state, bool using_color_fb, 388void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color_fb, bool using_depth_fb,
417 bool using_depth_fb, bool using_stencil_fb) { 389 bool using_stencil_fb) {
418 using VideoCore::Surface::SurfaceType;
419
420 auto& gpu = system.GPU().Maxwell3D(); 390 auto& gpu = system.GPU().Maxwell3D();
421 const auto& regs = gpu.regs; 391 const auto& regs = gpu.regs;
422 392
@@ -435,80 +405,44 @@ void RasterizerOpenGL::ConfigureClearFramebuffer(OpenGLState& current_state, boo
435 key.colors[0] = color_surface; 405 key.colors[0] = color_surface;
436 key.zeta = depth_surface; 406 key.zeta = depth_surface;
437 407
438 current_state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(key); 408 state_tracker.NotifyFramebuffer();
439 current_state.ApplyFramebufferState(); 409 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer_cache.GetFramebuffer(key));
440} 410}
441 411
442void RasterizerOpenGL::Clear() { 412void RasterizerOpenGL::Clear() {
443 const auto& maxwell3d = system.GPU().Maxwell3D(); 413 const auto& gpu = system.GPU().Maxwell3D();
444 414 if (!gpu.ShouldExecute()) {
445 if (!maxwell3d.ShouldExecute()) {
446 return; 415 return;
447 } 416 }
448 417
449 const auto& regs = maxwell3d.regs; 418 const auto& regs = gpu.regs;
450 bool use_color{}; 419 bool use_color{};
451 bool use_depth{}; 420 bool use_depth{};
452 bool use_stencil{}; 421 bool use_stencil{};
453 422
454 OpenGLState prev_state{OpenGLState::GetCurState()};
455 SCOPE_EXIT({
456 prev_state.AllDirty();
457 prev_state.Apply();
458 });
459
460 OpenGLState clear_state{OpenGLState::GetCurState()};
461 clear_state.SetDefaultViewports();
462 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 423 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
463 regs.clear_buffers.A) { 424 regs.clear_buffers.A) {
464 use_color = true; 425 use_color = true;
465 } 426 }
466 if (use_color) { 427 if (use_color) {
467 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; 428 state_tracker.NotifyColorMask0();
468 clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; 429 glColorMaski(0, regs.clear_buffers.R != 0, regs.clear_buffers.G != 0,
469 clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; 430 regs.clear_buffers.B != 0, regs.clear_buffers.A != 0);
470 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; 431
432 // TODO(Rodrigo): Determine if clamping is used on clears
433 SyncFragmentColorClampState();
434 SyncFramebufferSRGB();
471 } 435 }
472 if (regs.clear_buffers.Z) { 436 if (regs.clear_buffers.Z) {
473 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); 437 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
474 use_depth = true; 438 use_depth = true;
475 439
476 // Always enable the depth write when clearing the depth buffer. The depth write mask is 440 state_tracker.NotifyDepthMask();
477 // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to 441 glDepthMask(GL_TRUE);
478 // true.
479 clear_state.depth.test_enabled = true;
480 clear_state.depth.test_func = GL_ALWAYS;
481 clear_state.depth.write_mask = GL_TRUE;
482 } 442 }
483 if (regs.clear_buffers.S) { 443 if (regs.clear_buffers.S) {
484 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); 444 ASSERT_MSG(regs.zeta_enable, "Tried to clear stencil but buffer is not enabled!");
485 use_stencil = true; 445 use_stencil = true;
486 clear_state.stencil.test_enabled = true;
487
488 if (regs.clear_flags.stencil) {
489 // Stencil affects the clear so fill it with the used masks
490 clear_state.stencil.front.test_func = GL_ALWAYS;
491 clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
492 clear_state.stencil.front.action_stencil_fail = GL_KEEP;
493 clear_state.stencil.front.action_depth_fail = GL_KEEP;
494 clear_state.stencil.front.action_depth_pass = GL_KEEP;
495 clear_state.stencil.front.write_mask = regs.stencil_front_mask;
496 if (regs.stencil_two_side_enable) {
497 clear_state.stencil.back.test_func = GL_ALWAYS;
498 clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
499 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
500 clear_state.stencil.back.action_depth_fail = GL_KEEP;
501 clear_state.stencil.back.action_depth_pass = GL_KEEP;
502 clear_state.stencil.back.write_mask = regs.stencil_back_mask;
503 } else {
504 clear_state.stencil.back.test_func = GL_ALWAYS;
505 clear_state.stencil.back.test_mask = 0xFFFFFFFF;
506 clear_state.stencil.back.write_mask = 0xFFFFFFFF;
507 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
508 clear_state.stencil.back.action_depth_fail = GL_KEEP;
509 clear_state.stencil.back.action_depth_pass = GL_KEEP;
510 }
511 }
512 } 446 }
513 447
514 if (!use_color && !use_depth && !use_stencil) { 448 if (!use_color && !use_depth && !use_stencil) {
@@ -516,20 +450,18 @@ void RasterizerOpenGL::Clear() {
516 return; 450 return;
517 } 451 }
518 452
519 ConfigureClearFramebuffer(clear_state, use_color, use_depth, use_stencil); 453 SyncRasterizeEnable();
520 454
521 SyncViewport(clear_state);
522 SyncRasterizeEnable(clear_state);
523 if (regs.clear_flags.scissor) { 455 if (regs.clear_flags.scissor) {
524 SyncScissorTest(clear_state); 456 SyncScissorTest();
457 } else {
458 state_tracker.NotifyScissor0();
459 glDisablei(GL_SCISSOR_TEST, 0);
525 } 460 }
526 461
527 if (regs.clear_flags.viewport) { 462 UNIMPLEMENTED_IF(regs.clear_flags.viewport);
528 clear_state.EmulateViewportWithScissor();
529 }
530 463
531 clear_state.AllDirty(); 464 ConfigureClearFramebuffer(use_color, use_depth, use_stencil);
532 clear_state.Apply();
533 465
534 if (use_color) { 466 if (use_color) {
535 glClearBufferfv(GL_COLOR, 0, regs.clear_color); 467 glClearBufferfv(GL_COLOR, 0, regs.clear_color);
@@ -553,21 +485,24 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
553 485
554 query_cache.UpdateCounters(); 486 query_cache.UpdateCounters();
555 487
556 SyncRasterizeEnable(state); 488 SyncViewport();
489 SyncRasterizeEnable();
557 SyncColorMask(); 490 SyncColorMask();
558 SyncFragmentColorClampState(); 491 SyncFragmentColorClampState();
559 SyncMultiSampleState(); 492 SyncMultiSampleState();
560 SyncDepthTestState(); 493 SyncDepthTestState();
494 SyncDepthClamp();
561 SyncStencilTestState(); 495 SyncStencilTestState();
562 SyncBlendState(); 496 SyncBlendState();
563 SyncLogicOpState(); 497 SyncLogicOpState();
564 SyncCullMode(); 498 SyncCullMode();
565 SyncPrimitiveRestart(); 499 SyncPrimitiveRestart();
566 SyncScissorTest(state); 500 SyncScissorTest();
567 SyncTransformFeedback(); 501 SyncTransformFeedback();
568 SyncPointState(); 502 SyncPointState();
569 SyncPolygonOffset(); 503 SyncPolygonOffset();
570 SyncAlphaTest(); 504 SyncAlphaTest();
505 SyncFramebufferSRGB();
571 506
572 buffer_cache.Acquire(); 507 buffer_cache.Acquire();
573 508
@@ -591,13 +526,12 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
591 buffer_cache.Map(buffer_size); 526 buffer_cache.Map(buffer_size);
592 527
593 // Prepare vertex array format. 528 // Prepare vertex array format.
594 const GLuint vao = SetupVertexFormat(); 529 SetupVertexFormat();
595 vertex_array_pushbuffer.Setup(vao); 530 vertex_array_pushbuffer.Setup();
596 531
597 // Upload vertex and index data. 532 // Upload vertex and index data.
598 SetupVertexBuffer(vao); 533 SetupVertexBuffer();
599 SetupVertexInstances(vao); 534 SetupVertexInstances();
600
601 GLintptr index_buffer_offset; 535 GLintptr index_buffer_offset;
602 if (is_indexed) { 536 if (is_indexed) {
603 index_buffer_offset = SetupIndexBuffer(); 537 index_buffer_offset = SetupIndexBuffer();
@@ -631,14 +565,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
631 bind_ubo_pushbuffer.Bind(); 565 bind_ubo_pushbuffer.Bind();
632 bind_ssbo_pushbuffer.Bind(); 566 bind_ssbo_pushbuffer.Bind();
633 567
634 if (invalidate) { 568 program_manager.Update();
635 // As all cached buffers are invalidated, we need to recheck their state.
636 gpu.dirty.ResetVertexArrays();
637 }
638 gpu.dirty.memory_general = false;
639
640 shader_program_manager->ApplyTo(state);
641 state.Apply();
642 569
643 if (texture_cache.TextureBarrier()) { 570 if (texture_cache.TextureBarrier()) {
644 glTextureBarrier(); 571 glTextureBarrier();
@@ -700,8 +627,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
700 const ProgramVariant variant(launch_desc.block_dim_x, launch_desc.block_dim_y, 627 const ProgramVariant variant(launch_desc.block_dim_x, launch_desc.block_dim_y,
701 launch_desc.block_dim_z, launch_desc.shared_alloc, 628 launch_desc.block_dim_z, launch_desc.shared_alloc,
702 launch_desc.local_pos_alloc); 629 launch_desc.local_pos_alloc);
703 state.draw.shader_program = kernel->GetHandle(variant); 630 glUseProgramStages(program_manager.GetHandle(), GL_COMPUTE_SHADER_BIT,
704 state.draw.program_pipeline = 0; 631 kernel->GetHandle(variant));
705 632
706 const std::size_t buffer_size = 633 const std::size_t buffer_size =
707 Tegra::Engines::KeplerCompute::NumConstBuffers * 634 Tegra::Engines::KeplerCompute::NumConstBuffers *
@@ -719,11 +646,6 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
719 bind_ubo_pushbuffer.Bind(); 646 bind_ubo_pushbuffer.Bind();
720 bind_ssbo_pushbuffer.Bind(); 647 bind_ssbo_pushbuffer.Bind();
721 648
722 state.ApplyTextures();
723 state.ApplyImages();
724 state.ApplyShaderProgram();
725 state.ApplyProgramPipeline();
726
727 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); 649 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z);
728 ++num_queued_commands; 650 ++num_queued_commands;
729} 651}
@@ -935,20 +857,20 @@ void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextu
935 const auto view = texture_cache.GetTextureSurface(texture.tic, entry); 857 const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
936 if (!view) { 858 if (!view) {
937 // Can occur when texture addr is null or its memory is unmapped/invalid 859 // Can occur when texture addr is null or its memory is unmapped/invalid
938 state.samplers[binding] = 0; 860 glBindSampler(binding, 0);
939 state.textures[binding] = 0; 861 glBindTextureUnit(binding, 0);
940 return; 862 return;
941 } 863 }
942 state.textures[binding] = view->GetTexture(); 864 glBindTextureUnit(binding, view->GetTexture());
943 865
944 if (view->GetSurfaceParams().IsBuffer()) { 866 if (view->GetSurfaceParams().IsBuffer()) {
945 return; 867 return;
946 } 868 }
947 state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
948
949 // Apply swizzle to textures that are not buffers. 869 // Apply swizzle to textures that are not buffers.
950 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, 870 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
951 texture.tic.w_source); 871 texture.tic.w_source);
872
873 glBindSampler(binding, sampler_cache.GetSampler(texture.tsc));
952} 874}
953 875
954void RasterizerOpenGL::SetupDrawImages(std::size_t stage_index, const Shader& shader) { 876void RasterizerOpenGL::SetupDrawImages(std::size_t stage_index, const Shader& shader) {
@@ -974,7 +896,7 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
974 const GLShader::ImageEntry& entry) { 896 const GLShader::ImageEntry& entry) {
975 const auto view = texture_cache.GetImageSurface(tic, entry); 897 const auto view = texture_cache.GetImageSurface(tic, entry);
976 if (!view) { 898 if (!view) {
977 state.images[binding] = 0; 899 glBindImageTexture(binding, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
978 return; 900 return;
979 } 901 }
980 if (!tic.IsBuffer()) { 902 if (!tic.IsBuffer()) {
@@ -983,55 +905,85 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
983 if (entry.IsWritten()) { 905 if (entry.IsWritten()) {
984 view->MarkAsModified(texture_cache.Tick()); 906 view->MarkAsModified(texture_cache.Tick());
985 } 907 }
986 state.images[binding] = view->GetTexture(); 908 glBindImageTexture(binding, view->GetTexture(), 0, GL_TRUE, 0, GL_READ_WRITE,
909 view->GetFormat());
987} 910}
988 911
989void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 912void RasterizerOpenGL::SyncViewport() {
990 const auto& regs = system.GPU().Maxwell3D().regs; 913 auto& gpu = system.GPU().Maxwell3D();
991 const bool geometry_shaders_enabled = 914 auto& flags = gpu.dirty.flags;
992 regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); 915 const auto& regs = gpu.regs;
993 const std::size_t viewport_count = 916
994 geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; 917 const bool dirty_viewport = flags[Dirty::Viewports];
995 for (std::size_t i = 0; i < viewport_count; i++) { 918 if (dirty_viewport || flags[Dirty::ClipControl]) {
996 auto& viewport = current_state.viewports[i]; 919 flags[Dirty::ClipControl] = false;
997 const auto& src = regs.viewports[i]; 920
998 const Common::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; 921 bool flip_y = false;
999 viewport.x = viewport_rect.left; 922 if (regs.viewport_transform[0].scale_y < 0.0) {
1000 viewport.y = viewport_rect.bottom; 923 flip_y = !flip_y;
1001 viewport.width = viewport_rect.GetWidth(); 924 }
1002 viewport.height = viewport_rect.GetHeight(); 925 if (regs.screen_y_control.y_negate != 0) {
1003 viewport.depth_range_far = src.depth_range_far; 926 flip_y = !flip_y;
1004 viewport.depth_range_near = src.depth_range_near; 927 }
1005 } 928 glClipControl(flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT,
1006 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; 929 regs.depth_mode == Maxwell::DepthMode::ZeroToOne ? GL_ZERO_TO_ONE
1007 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; 930 : GL_NEGATIVE_ONE_TO_ONE);
1008 931 }
1009 bool flip_y = false; 932
1010 if (regs.viewport_transform[0].scale_y < 0.0) { 933 if (dirty_viewport) {
1011 flip_y = !flip_y; 934 flags[Dirty::Viewports] = false;
1012 } 935
1013 if (regs.screen_y_control.y_negate != 0) { 936 const bool force = flags[Dirty::ViewportTransform];
1014 flip_y = !flip_y; 937 flags[Dirty::ViewportTransform] = false;
1015 } 938
1016 state.clip_control.origin = flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT; 939 for (std::size_t i = 0; i < Maxwell::NumViewports; ++i) {
1017 state.clip_control.depth_mode = 940 if (!force && !flags[Dirty::Viewport0 + i]) {
1018 regs.depth_mode == Tegra::Engines::Maxwell3D::Regs::DepthMode::ZeroToOne 941 continue;
1019 ? GL_ZERO_TO_ONE 942 }
1020 : GL_NEGATIVE_ONE_TO_ONE; 943 flags[Dirty::Viewport0 + i] = false;
944
945 const Common::Rectangle<f32> rect{regs.viewport_transform[i].GetRect()};
946 glViewportIndexedf(static_cast<GLuint>(i), rect.left, rect.bottom, rect.GetWidth(),
947 rect.GetHeight());
948
949 const auto& src = regs.viewports[i];
950 glDepthRangeIndexed(static_cast<GLuint>(i), static_cast<GLdouble>(src.depth_range_near),
951 static_cast<GLdouble>(src.depth_range_far));
952 }
953 }
1021} 954}
1022 955
1023void RasterizerOpenGL::SyncClipEnabled( 956void RasterizerOpenGL::SyncDepthClamp() {
1024 const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) { 957 auto& gpu = system.GPU().Maxwell3D();
958 auto& flags = gpu.dirty.flags;
959 if (!flags[Dirty::DepthClampEnabled]) {
960 return;
961 }
962 flags[Dirty::DepthClampEnabled] = false;
1025 963
1026 const auto& regs = system.GPU().Maxwell3D().regs; 964 const auto& state = gpu.regs.view_volume_clip_control;
1027 const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{ 965 UNIMPLEMENTED_IF_MSG(state.depth_clamp_far != state.depth_clamp_near,
1028 regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0, 966 "Unimplemented depth clamp separation!");
1029 regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0, 967
1030 regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0, 968 oglEnable(GL_DEPTH_CLAMP, state.depth_clamp_far || state.depth_clamp_near);
1031 regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0}; 969}
970
971void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) {
972 auto& gpu = system.GPU().Maxwell3D();
973 auto& flags = gpu.dirty.flags;
974 if (!flags[Dirty::ClipDistances] && !flags[Dirty::Shaders]) {
975 return;
976 }
977 flags[Dirty::ClipDistances] = false;
978
979 clip_mask &= gpu.regs.clip_distance_enabled;
980 if (clip_mask == last_clip_distance_mask) {
981 return;
982 }
983 last_clip_distance_mask = clip_mask;
1032 984
1033 for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) { 985 for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
1034 state.clip_distance[i] = reg_state[i] && clip_mask[i]; 986 oglEnable(static_cast<GLenum>(GL_CLIP_DISTANCE0 + i), (clip_mask >> i) & 1);
1035 } 987 }
1036} 988}
1037 989
@@ -1040,199 +992,269 @@ void RasterizerOpenGL::SyncClipCoef() {
1040} 992}
1041 993
1042void RasterizerOpenGL::SyncCullMode() { 994void RasterizerOpenGL::SyncCullMode() {
1043 const auto& regs = system.GPU().Maxwell3D().regs; 995 auto& gpu = system.GPU().Maxwell3D();
996 auto& flags = gpu.dirty.flags;
997 const auto& regs = gpu.regs;
1044 998
1045 state.cull.enabled = regs.cull.enabled != 0; 999 if (flags[Dirty::CullTest]) {
1046 if (state.cull.enabled) { 1000 flags[Dirty::CullTest] = false;
1047 state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); 1001
1002 if (regs.cull_test_enabled) {
1003 glEnable(GL_CULL_FACE);
1004 glCullFace(MaxwellToGL::CullFace(regs.cull_face));
1005 } else {
1006 glDisable(GL_CULL_FACE);
1007 }
1048 } 1008 }
1049 1009
1050 state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); 1010 if (flags[Dirty::FrontFace]) {
1011 flags[Dirty::FrontFace] = false;
1012 glFrontFace(MaxwellToGL::FrontFace(regs.front_face));
1013 }
1051} 1014}
1052 1015
1053void RasterizerOpenGL::SyncPrimitiveRestart() { 1016void RasterizerOpenGL::SyncPrimitiveRestart() {
1054 const auto& regs = system.GPU().Maxwell3D().regs; 1017 auto& gpu = system.GPU().Maxwell3D();
1018 auto& flags = gpu.dirty.flags;
1019 if (!flags[Dirty::PrimitiveRestart]) {
1020 return;
1021 }
1022 flags[Dirty::PrimitiveRestart] = false;
1055 1023
1056 state.primitive_restart.enabled = regs.primitive_restart.enabled; 1024 if (gpu.regs.primitive_restart.enabled) {
1057 state.primitive_restart.index = regs.primitive_restart.index; 1025 glEnable(GL_PRIMITIVE_RESTART);
1026 glPrimitiveRestartIndex(gpu.regs.primitive_restart.index);
1027 } else {
1028 glDisable(GL_PRIMITIVE_RESTART);
1029 }
1058} 1030}
1059 1031
1060void RasterizerOpenGL::SyncDepthTestState() { 1032void RasterizerOpenGL::SyncDepthTestState() {
1061 const auto& regs = system.GPU().Maxwell3D().regs; 1033 auto& gpu = system.GPU().Maxwell3D();
1062 1034 auto& flags = gpu.dirty.flags;
1063 state.depth.test_enabled = regs.depth_test_enable != 0;
1064 state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE;
1065 1035
1066 if (!state.depth.test_enabled) { 1036 const auto& regs = gpu.regs;
1067 return; 1037 if (flags[Dirty::DepthMask]) {
1038 flags[Dirty::DepthMask] = false;
1039 glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE);
1068 } 1040 }
1069 1041
1070 state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); 1042 if (flags[Dirty::DepthTest]) {
1043 flags[Dirty::DepthTest] = false;
1044 if (regs.depth_test_enable) {
1045 glEnable(GL_DEPTH_TEST);
1046 glDepthFunc(MaxwellToGL::ComparisonOp(regs.depth_test_func));
1047 } else {
1048 glDisable(GL_DEPTH_TEST);
1049 }
1050 }
1071} 1051}
1072 1052
1073void RasterizerOpenGL::SyncStencilTestState() { 1053void RasterizerOpenGL::SyncStencilTestState() {
1074 auto& maxwell3d = system.GPU().Maxwell3D(); 1054 auto& gpu = system.GPU().Maxwell3D();
1075 if (!maxwell3d.dirty.stencil_test) { 1055 auto& flags = gpu.dirty.flags;
1056 if (!flags[Dirty::StencilTest]) {
1076 return; 1057 return;
1077 } 1058 }
1078 maxwell3d.dirty.stencil_test = false; 1059 flags[Dirty::StencilTest] = false;
1079
1080 const auto& regs = maxwell3d.regs;
1081 state.stencil.test_enabled = regs.stencil_enable != 0;
1082 state.MarkDirtyStencilState();
1083 1060
1061 const auto& regs = gpu.regs;
1084 if (!regs.stencil_enable) { 1062 if (!regs.stencil_enable) {
1063 glDisable(GL_STENCIL_TEST);
1085 return; 1064 return;
1086 } 1065 }
1087 1066
1088 state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); 1067 glEnable(GL_STENCIL_TEST);
1089 state.stencil.front.test_ref = regs.stencil_front_func_ref; 1068 glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func),
1090 state.stencil.front.test_mask = regs.stencil_front_func_mask; 1069 regs.stencil_front_func_ref, regs.stencil_front_func_mask);
1091 state.stencil.front.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_fail); 1070 glStencilOpSeparate(GL_FRONT, MaxwellToGL::StencilOp(regs.stencil_front_op_fail),
1092 state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); 1071 MaxwellToGL::StencilOp(regs.stencil_front_op_zfail),
1093 state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); 1072 MaxwellToGL::StencilOp(regs.stencil_front_op_zpass));
1094 state.stencil.front.write_mask = regs.stencil_front_mask; 1073 glStencilMaskSeparate(GL_FRONT, regs.stencil_front_mask);
1074
1095 if (regs.stencil_two_side_enable) { 1075 if (regs.stencil_two_side_enable) {
1096 state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); 1076 glStencilFuncSeparate(GL_BACK, MaxwellToGL::ComparisonOp(regs.stencil_back_func_func),
1097 state.stencil.back.test_ref = regs.stencil_back_func_ref; 1077 regs.stencil_back_func_ref, regs.stencil_back_func_mask);
1098 state.stencil.back.test_mask = regs.stencil_back_func_mask; 1078 glStencilOpSeparate(GL_BACK, MaxwellToGL::StencilOp(regs.stencil_back_op_fail),
1099 state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); 1079 MaxwellToGL::StencilOp(regs.stencil_back_op_zfail),
1100 state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); 1080 MaxwellToGL::StencilOp(regs.stencil_back_op_zpass));
1101 state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); 1081 glStencilMaskSeparate(GL_BACK, regs.stencil_back_mask);
1102 state.stencil.back.write_mask = regs.stencil_back_mask;
1103 } else { 1082 } else {
1104 state.stencil.back.test_func = GL_ALWAYS; 1083 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 0xFFFFFFFF);
1105 state.stencil.back.test_ref = 0; 1084 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
1106 state.stencil.back.test_mask = 0xFFFFFFFF; 1085 glStencilMaskSeparate(GL_BACK, 0xFFFFFFFF);
1107 state.stencil.back.write_mask = 0xFFFFFFFF;
1108 state.stencil.back.action_stencil_fail = GL_KEEP;
1109 state.stencil.back.action_depth_fail = GL_KEEP;
1110 state.stencil.back.action_depth_pass = GL_KEEP;
1111 } 1086 }
1112} 1087}
1113 1088
1114void RasterizerOpenGL::SyncRasterizeEnable(OpenGLState& current_state) { 1089void RasterizerOpenGL::SyncRasterizeEnable() {
1115 const auto& regs = system.GPU().Maxwell3D().regs; 1090 auto& gpu = system.GPU().Maxwell3D();
1116 current_state.rasterizer_discard = regs.rasterize_enable == 0; 1091 auto& flags = gpu.dirty.flags;
1092 if (!flags[Dirty::RasterizeEnable]) {
1093 return;
1094 }
1095 flags[Dirty::RasterizeEnable] = false;
1096
1097 oglEnable(GL_RASTERIZER_DISCARD, gpu.regs.rasterize_enable == 0);
1117} 1098}
1118 1099
1119void RasterizerOpenGL::SyncColorMask() { 1100void RasterizerOpenGL::SyncColorMask() {
1120 auto& maxwell3d = system.GPU().Maxwell3D(); 1101 auto& gpu = system.GPU().Maxwell3D();
1121 if (!maxwell3d.dirty.color_mask) { 1102 auto& flags = gpu.dirty.flags;
1103 if (!flags[Dirty::ColorMasks]) {
1122 return; 1104 return;
1123 } 1105 }
1124 const auto& regs = maxwell3d.regs; 1106 flags[Dirty::ColorMasks] = false;
1125 1107
1126 const std::size_t count = 1108 const bool force = flags[Dirty::ColorMaskCommon];
1127 regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; 1109 flags[Dirty::ColorMaskCommon] = false;
1128 for (std::size_t i = 0; i < count; i++) { 1110
1129 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i]; 1111 const auto& regs = gpu.regs;
1130 auto& dest = state.color_mask[i]; 1112 if (regs.color_mask_common) {
1131 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE; 1113 if (!force && !flags[Dirty::ColorMask0]) {
1132 dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE; 1114 return;
1133 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; 1115 }
1134 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; 1116 flags[Dirty::ColorMask0] = false;
1117
1118 auto& mask = regs.color_mask[0];
1119 glColorMask(mask.R != 0, mask.B != 0, mask.G != 0, mask.A != 0);
1120 return;
1135 } 1121 }
1136 1122
1137 state.MarkDirtyColorMask(); 1123 // Path without color_mask_common set
1138 maxwell3d.dirty.color_mask = false; 1124 for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
1125 if (!force && !flags[Dirty::ColorMask0 + i]) {
1126 continue;
1127 }
1128 flags[Dirty::ColorMask0 + i] = false;
1129
1130 const auto& mask = regs.color_mask[i];
1131 glColorMaski(static_cast<GLuint>(i), mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0);
1132 }
1139} 1133}
1140 1134
1141void RasterizerOpenGL::SyncMultiSampleState() { 1135void RasterizerOpenGL::SyncMultiSampleState() {
1136 auto& gpu = system.GPU().Maxwell3D();
1137 auto& flags = gpu.dirty.flags;
1138 if (!flags[Dirty::MultisampleControl]) {
1139 return;
1140 }
1141 flags[Dirty::MultisampleControl] = false;
1142
1142 const auto& regs = system.GPU().Maxwell3D().regs; 1143 const auto& regs = system.GPU().Maxwell3D().regs;
1143 state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0; 1144 oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage);
1144 state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0; 1145 oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one);
1145} 1146}
1146 1147
1147void RasterizerOpenGL::SyncFragmentColorClampState() { 1148void RasterizerOpenGL::SyncFragmentColorClampState() {
1148 const auto& regs = system.GPU().Maxwell3D().regs; 1149 auto& gpu = system.GPU().Maxwell3D();
1149 state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; 1150 auto& flags = gpu.dirty.flags;
1151 if (!flags[Dirty::FragmentClampColor]) {
1152 return;
1153 }
1154 flags[Dirty::FragmentClampColor] = false;
1155
1156 glClampColor(GL_CLAMP_FRAGMENT_COLOR, gpu.regs.frag_color_clamp ? GL_TRUE : GL_FALSE);
1150} 1157}
1151 1158
1152void RasterizerOpenGL::SyncBlendState() { 1159void RasterizerOpenGL::SyncBlendState() {
1153 auto& maxwell3d = system.GPU().Maxwell3D(); 1160 auto& gpu = system.GPU().Maxwell3D();
1154 if (!maxwell3d.dirty.blend_state) { 1161 auto& flags = gpu.dirty.flags;
1162 const auto& regs = gpu.regs;
1163
1164 if (flags[Dirty::BlendColor]) {
1165 flags[Dirty::BlendColor] = false;
1166 glBlendColor(regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
1167 regs.blend_color.a);
1168 }
1169
1170 // TODO(Rodrigo): Revisit blending, there are several registers we are not reading
1171
1172 if (!flags[Dirty::BlendStates]) {
1155 return; 1173 return;
1156 } 1174 }
1157 const auto& regs = maxwell3d.regs; 1175 flags[Dirty::BlendStates] = false;
1158 1176
1159 state.blend_color.red = regs.blend_color.r; 1177 if (!regs.independent_blend_enable) {
1160 state.blend_color.green = regs.blend_color.g; 1178 if (!regs.blend.enable[0]) {
1161 state.blend_color.blue = regs.blend_color.b; 1179 glDisable(GL_BLEND);
1162 state.blend_color.alpha = regs.blend_color.a; 1180 return;
1163
1164 state.independant_blend.enabled = regs.independent_blend_enable;
1165 if (!state.independant_blend.enabled) {
1166 auto& blend = state.blend[0];
1167 const auto& src = regs.blend;
1168 blend.enabled = src.enable[0] != 0;
1169 if (blend.enabled) {
1170 blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
1171 blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
1172 blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
1173 blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
1174 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
1175 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
1176 }
1177 for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1178 state.blend[i].enabled = false;
1179 } 1181 }
1180 maxwell3d.dirty.blend_state = false; 1182 glEnable(GL_BLEND);
1181 state.MarkDirtyBlendState(); 1183 glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb),
1184 MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb),
1185 MaxwellToGL::BlendFunc(regs.blend.factor_source_a),
1186 MaxwellToGL::BlendFunc(regs.blend.factor_dest_a));
1187 glBlendEquationSeparate(MaxwellToGL::BlendEquation(regs.blend.equation_rgb),
1188 MaxwellToGL::BlendEquation(regs.blend.equation_a));
1182 return; 1189 return;
1183 } 1190 }
1184 1191
1185 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1192 const bool force = flags[Dirty::BlendIndependentEnabled];
1186 auto& blend = state.blend[i]; 1193 flags[Dirty::BlendIndependentEnabled] = false;
1187 const auto& src = regs.independent_blend[i]; 1194
1188 blend.enabled = regs.blend.enable[i] != 0; 1195 for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
1189 if (!blend.enabled) 1196 if (!force && !flags[Dirty::BlendState0 + i]) {
1190 continue; 1197 continue;
1191 blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb); 1198 }
1192 blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb); 1199 flags[Dirty::BlendState0 + i] = false;
1193 blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb); 1200
1194 blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a); 1201 if (!regs.blend.enable[i]) {
1195 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); 1202 glDisablei(GL_BLEND, static_cast<GLuint>(i));
1196 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); 1203 continue;
1197 } 1204 }
1205 glEnablei(GL_BLEND, static_cast<GLuint>(i));
1198 1206
1199 state.MarkDirtyBlendState(); 1207 const auto& src = regs.independent_blend[i];
1200 maxwell3d.dirty.blend_state = false; 1208 glBlendFuncSeparatei(static_cast<GLuint>(i), MaxwellToGL::BlendFunc(src.factor_source_rgb),
1209 MaxwellToGL::BlendFunc(src.factor_dest_rgb),
1210 MaxwellToGL::BlendFunc(src.factor_source_a),
1211 MaxwellToGL::BlendFunc(src.factor_dest_a));
1212 glBlendEquationSeparatei(static_cast<GLuint>(i),
1213 MaxwellToGL::BlendEquation(src.equation_rgb),
1214 MaxwellToGL::BlendEquation(src.equation_a));
1215 }
1201} 1216}
1202 1217
1203void RasterizerOpenGL::SyncLogicOpState() { 1218void RasterizerOpenGL::SyncLogicOpState() {
1204 const auto& regs = system.GPU().Maxwell3D().regs; 1219 auto& gpu = system.GPU().Maxwell3D();
1220 auto& flags = gpu.dirty.flags;
1221 if (!flags[Dirty::LogicOp]) {
1222 return;
1223 }
1224 flags[Dirty::LogicOp] = false;
1205 1225
1206 state.logic_op.enabled = regs.logic_op.enable != 0; 1226 const auto& regs = gpu.regs;
1227 if (regs.logic_op.enable) {
1228 glEnable(GL_COLOR_LOGIC_OP);
1229 glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation));
1230 } else {
1231 glDisable(GL_COLOR_LOGIC_OP);
1232 }
1233}
1207 1234
1208 if (!state.logic_op.enabled) 1235void RasterizerOpenGL::SyncScissorTest() {
1236 auto& gpu = system.GPU().Maxwell3D();
1237 auto& flags = gpu.dirty.flags;
1238 if (!flags[Dirty::Scissors]) {
1209 return; 1239 return;
1240 }
1241 flags[Dirty::Scissors] = false;
1210 1242
1211 ASSERT_MSG(regs.blend.enable[0] == 0, 1243 const auto& regs = gpu.regs;
1212 "Blending and logic op can't be enabled at the same time."); 1244 for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) {
1213 1245 if (!flags[Dirty::Scissor0 + index]) {
1214 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); 1246 continue;
1215} 1247 }
1248 flags[Dirty::Scissor0 + index] = false;
1216 1249
1217void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { 1250 const auto& src = regs.scissor_test[index];
1218 const auto& regs = system.GPU().Maxwell3D().regs; 1251 if (src.enable) {
1219 const bool geometry_shaders_enabled = 1252 glEnablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
1220 regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); 1253 glScissorIndexed(static_cast<GLuint>(index), src.min_x, src.min_y,
1221 const std::size_t viewport_count = 1254 src.max_x - src.min_x, src.max_y - src.min_y);
1222 geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; 1255 } else {
1223 for (std::size_t i = 0; i < viewport_count; i++) { 1256 glDisablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
1224 const auto& src = regs.scissor_test[i];
1225 auto& dst = current_state.viewports[i].scissor;
1226 dst.enabled = (src.enable != 0);
1227 if (dst.enabled == 0) {
1228 return;
1229 } 1257 }
1230 const u32 width = src.max_x - src.min_x;
1231 const u32 height = src.max_y - src.min_y;
1232 dst.x = src.min_x;
1233 dst.y = src.min_y;
1234 dst.width = width;
1235 dst.height = height;
1236 } 1258 }
1237} 1259}
1238 1260
@@ -1242,45 +1264,78 @@ void RasterizerOpenGL::SyncTransformFeedback() {
1242} 1264}
1243 1265
1244void RasterizerOpenGL::SyncPointState() { 1266void RasterizerOpenGL::SyncPointState() {
1245 const auto& regs = system.GPU().Maxwell3D().regs; 1267 auto& gpu = system.GPU().Maxwell3D();
1268 auto& flags = gpu.dirty.flags;
1269 if (!flags[Dirty::PointSize]) {
1270 return;
1271 }
1272 flags[Dirty::PointSize] = false;
1273
1274 oglEnable(GL_POINT_SPRITE, gpu.regs.point_sprite_enable);
1275
1276 if (gpu.regs.vp_point_size.enable) {
1277 // By definition of GL_POINT_SIZE, it only matters if GL_PROGRAM_POINT_SIZE is disabled.
1278 glEnable(GL_PROGRAM_POINT_SIZE);
1279 return;
1280 }
1281
1246 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid 1282 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
1247 // in OpenGL). 1283 // in OpenGL).
1248 state.point.program_control = regs.vp_point_size.enable != 0; 1284 glPointSize(std::max(1.0f, gpu.regs.point_size));
1249 state.point.sprite = regs.point_sprite_enable != 0; 1285 glDisable(GL_PROGRAM_POINT_SIZE);
1250 state.point.size = std::max(1.0f, regs.point_size);
1251} 1286}
1252 1287
1253void RasterizerOpenGL::SyncPolygonOffset() { 1288void RasterizerOpenGL::SyncPolygonOffset() {
1254 auto& maxwell3d = system.GPU().Maxwell3D(); 1289 auto& gpu = system.GPU().Maxwell3D();
1255 if (!maxwell3d.dirty.polygon_offset) { 1290 auto& flags = gpu.dirty.flags;
1291 if (!flags[Dirty::PolygonOffset]) {
1256 return; 1292 return;
1257 } 1293 }
1258 const auto& regs = maxwell3d.regs; 1294 flags[Dirty::PolygonOffset] = false;
1259
1260 state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
1261 state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
1262 state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
1263 1295
1264 // Hardware divides polygon offset units by two 1296 const auto& regs = gpu.regs;
1265 state.polygon_offset.units = regs.polygon_offset_units / 2.0f; 1297 oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable);
1266 state.polygon_offset.factor = regs.polygon_offset_factor; 1298 oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable);
1267 state.polygon_offset.clamp = regs.polygon_offset_clamp; 1299 oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable);
1268 1300
1269 state.MarkDirtyPolygonOffset(); 1301 if (regs.polygon_offset_fill_enable || regs.polygon_offset_line_enable ||
1270 maxwell3d.dirty.polygon_offset = false; 1302 regs.polygon_offset_point_enable) {
1303 // Hardware divides polygon offset units by two
1304 glPolygonOffsetClamp(regs.polygon_offset_factor, regs.polygon_offset_units / 2.0f,
1305 regs.polygon_offset_clamp);
1306 }
1271} 1307}
1272 1308
1273void RasterizerOpenGL::SyncAlphaTest() { 1309void RasterizerOpenGL::SyncAlphaTest() {
1274 const auto& regs = system.GPU().Maxwell3D().regs; 1310 auto& gpu = system.GPU().Maxwell3D();
1275 UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1, 1311 auto& flags = gpu.dirty.flags;
1276 "Alpha Testing is enabled with more than one rendertarget"); 1312 if (!flags[Dirty::AlphaTest]) {
1313 return;
1314 }
1315 flags[Dirty::AlphaTest] = false;
1316
1317 const auto& regs = gpu.regs;
1318 if (regs.alpha_test_enabled && regs.rt_control.count > 1) {
1319 LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested");
1320 }
1277 1321
1278 state.alpha_test.enabled = regs.alpha_test_enabled; 1322 if (regs.alpha_test_enabled) {
1279 if (!state.alpha_test.enabled) { 1323 glEnable(GL_ALPHA_TEST);
1324 glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref);
1325 } else {
1326 glDisable(GL_ALPHA_TEST);
1327 }
1328}
1329
1330void RasterizerOpenGL::SyncFramebufferSRGB() {
1331 auto& gpu = system.GPU().Maxwell3D();
1332 auto& flags = gpu.dirty.flags;
1333 if (!flags[Dirty::FramebufferSRGB]) {
1280 return; 1334 return;
1281 } 1335 }
1282 state.alpha_test.func = MaxwellToGL::ComparisonOp(regs.alpha_test_func); 1336 flags[Dirty::FramebufferSRGB] = false;
1283 state.alpha_test.ref = regs.alpha_test_ref; 1337
1338 oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb);
1284} 1339}
1285 1340
1286} // namespace OpenGL 1341} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 68abe9a21..b24c6661b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -30,7 +30,7 @@
30#include "video_core/renderer_opengl/gl_shader_cache.h" 30#include "video_core/renderer_opengl/gl_shader_cache.h"
31#include "video_core/renderer_opengl/gl_shader_decompiler.h" 31#include "video_core/renderer_opengl/gl_shader_decompiler.h"
32#include "video_core/renderer_opengl/gl_shader_manager.h" 32#include "video_core/renderer_opengl/gl_shader_manager.h"
33#include "video_core/renderer_opengl/gl_state.h" 33#include "video_core/renderer_opengl/gl_state_tracker.h"
34#include "video_core/renderer_opengl/gl_texture_cache.h" 34#include "video_core/renderer_opengl/gl_texture_cache.h"
35#include "video_core/renderer_opengl/utils.h" 35#include "video_core/renderer_opengl/utils.h"
36#include "video_core/textures/texture.h" 36#include "video_core/textures/texture.h"
@@ -55,7 +55,8 @@ struct DrawParameters;
55class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { 55class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
56public: 56public:
57 explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 57 explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
58 ScreenInfo& info); 58 ScreenInfo& info, GLShader::ProgramManager& program_manager,
59 StateTracker& state_tracker);
59 ~RasterizerOpenGL() override; 60 ~RasterizerOpenGL() override;
60 61
61 void Draw(bool is_indexed, bool is_instanced) override; 62 void Draw(bool is_indexed, bool is_instanced) override;
@@ -76,6 +77,7 @@ public:
76 u32 pixel_stride) override; 77 u32 pixel_stride) override;
77 void LoadDiskResources(const std::atomic_bool& stop_loading, 78 void LoadDiskResources(const std::atomic_bool& stop_loading,
78 const VideoCore::DiskResourceLoadCallback& callback) override; 79 const VideoCore::DiskResourceLoadCallback& callback) override;
80 void SetupDirtyFlags() override;
79 81
80 /// Returns true when there are commands queued to the OpenGL server. 82 /// Returns true when there are commands queued to the OpenGL server.
81 bool AnyCommandQueued() const { 83 bool AnyCommandQueued() const {
@@ -86,8 +88,7 @@ private:
86 /// Configures the color and depth framebuffer states. 88 /// Configures the color and depth framebuffer states.
87 void ConfigureFramebuffers(); 89 void ConfigureFramebuffers();
88 90
89 void ConfigureClearFramebuffer(OpenGLState& current_state, bool using_color_fb, 91 void ConfigureClearFramebuffer(bool using_color_fb, bool using_depth_fb, bool using_stencil_fb);
90 bool using_depth_fb, bool using_stencil_fb);
91 92
92 /// Configures the current constbuffers to use for the draw command. 93 /// Configures the current constbuffers to use for the draw command.
93 void SetupDrawConstBuffers(std::size_t stage_index, const Shader& shader); 94 void SetupDrawConstBuffers(std::size_t stage_index, const Shader& shader);
@@ -130,11 +131,13 @@ private:
130 const GLShader::ImageEntry& entry); 131 const GLShader::ImageEntry& entry);
131 132
132 /// Syncs the viewport and depth range to match the guest state 133 /// Syncs the viewport and depth range to match the guest state
133 void SyncViewport(OpenGLState& current_state); 134 void SyncViewport();
135
136 /// Syncs the depth clamp state
137 void SyncDepthClamp();
134 138
135 /// Syncs the clip enabled status to match the guest state 139 /// Syncs the clip enabled status to match the guest state
136 void SyncClipEnabled( 140 void SyncClipEnabled(u32 clip_mask);
137 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
138 141
139 /// Syncs the clip coefficients to match the guest state 142 /// Syncs the clip coefficients to match the guest state
140 void SyncClipCoef(); 143 void SyncClipCoef();
@@ -164,7 +167,7 @@ private:
164 void SyncMultiSampleState(); 167 void SyncMultiSampleState();
165 168
166 /// Syncs the scissor test state to match the guest state 169 /// Syncs the scissor test state to match the guest state
167 void SyncScissorTest(OpenGLState& current_state); 170 void SyncScissorTest();
168 171
169 /// Syncs the transform feedback state to match the guest state 172 /// Syncs the transform feedback state to match the guest state
170 void SyncTransformFeedback(); 173 void SyncTransformFeedback();
@@ -173,7 +176,7 @@ private:
173 void SyncPointState(); 176 void SyncPointState();
174 177
175 /// Syncs the rasterizer enable state to match the guest state 178 /// Syncs the rasterizer enable state to match the guest state
176 void SyncRasterizeEnable(OpenGLState& current_state); 179 void SyncRasterizeEnable();
177 180
178 /// Syncs Color Mask 181 /// Syncs Color Mask
179 void SyncColorMask(); 182 void SyncColorMask();
@@ -184,6 +187,9 @@ private:
184 /// Syncs the alpha test state to match the guest state 187 /// Syncs the alpha test state to match the guest state
185 void SyncAlphaTest(); 188 void SyncAlphaTest();
186 189
190 /// Syncs the framebuffer sRGB state to match the guest state
191 void SyncFramebufferSRGB();
192
187 /// Check for extension that are not strictly required but are needed for correct emulation 193 /// Check for extension that are not strictly required but are needed for correct emulation
188 void CheckExtensions(); 194 void CheckExtensions();
189 195
@@ -191,18 +197,17 @@ private:
191 197
192 std::size_t CalculateIndexBufferSize() const; 198 std::size_t CalculateIndexBufferSize() const;
193 199
194 /// Updates and returns a vertex array object representing current vertex format 200 /// Updates the current vertex format
195 GLuint SetupVertexFormat(); 201 void SetupVertexFormat();
196 202
197 void SetupVertexBuffer(GLuint vao); 203 void SetupVertexBuffer();
198 void SetupVertexInstances(GLuint vao); 204 void SetupVertexInstances();
199 205
200 GLintptr SetupIndexBuffer(); 206 GLintptr SetupIndexBuffer();
201 207
202 void SetupShaders(GLenum primitive_mode); 208 void SetupShaders(GLenum primitive_mode);
203 209
204 const Device device; 210 const Device device;
205 OpenGLState state;
206 211
207 TextureCacheOpenGL texture_cache; 212 TextureCacheOpenGL texture_cache;
208 ShaderCacheOpenGL shader_cache; 213 ShaderCacheOpenGL shader_cache;
@@ -212,22 +217,20 @@ private:
212 217
213 Core::System& system; 218 Core::System& system;
214 ScreenInfo& screen_info; 219 ScreenInfo& screen_info;
215 220 GLShader::ProgramManager& program_manager;
216 std::unique_ptr<GLShader::ProgramManager> shader_program_manager; 221 StateTracker& state_tracker;
217 std::map<std::array<Tegra::Engines::Maxwell3D::Regs::VertexAttribute,
218 Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes>,
219 OGLVertexArray>
220 vertex_array_cache;
221 222
222 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 223 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
223 OGLBufferCache buffer_cache; 224 OGLBufferCache buffer_cache;
224 225
225 VertexArrayPushBuffer vertex_array_pushbuffer; 226 VertexArrayPushBuffer vertex_array_pushbuffer{state_tracker};
226 BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; 227 BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER};
227 BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; 228 BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER};
228 229
229 /// Number of commands queued to the OpenGL driver. Reseted on flush. 230 /// Number of commands queued to the OpenGL driver. Reseted on flush.
230 std::size_t num_queued_commands = 0; 231 std::size_t num_queued_commands = 0;
232
233 u32 last_clip_distance_mask = 0;
231}; 234};
232 235
233} // namespace OpenGL 236} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index c0aee770f..97803d480 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -8,7 +8,6 @@
8#include "common/microprofile.h" 8#include "common/microprofile.h"
9#include "video_core/renderer_opengl/gl_resource_manager.h" 9#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/renderer_opengl/gl_shader_util.h" 10#include "video_core/renderer_opengl/gl_shader_util.h"
11#include "video_core/renderer_opengl/gl_state.h"
12 11
13MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192)); 12MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192));
14MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192)); 13MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192));
@@ -20,7 +19,7 @@ void OGLRenderbuffer::Create() {
20 return; 19 return;
21 20
22 MICROPROFILE_SCOPE(OpenGL_ResourceCreation); 21 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
23 glGenRenderbuffers(1, &handle); 22 glCreateRenderbuffers(1, &handle);
24} 23}
25 24
26void OGLRenderbuffer::Release() { 25void OGLRenderbuffer::Release() {
@@ -29,7 +28,6 @@ void OGLRenderbuffer::Release() {
29 28
30 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 29 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
31 glDeleteRenderbuffers(1, &handle); 30 glDeleteRenderbuffers(1, &handle);
32 OpenGLState::GetCurState().ResetRenderbuffer(handle).Apply();
33 handle = 0; 31 handle = 0;
34} 32}
35 33
@@ -47,7 +45,6 @@ void OGLTexture::Release() {
47 45
48 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 46 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
49 glDeleteTextures(1, &handle); 47 glDeleteTextures(1, &handle);
50 OpenGLState::GetCurState().UnbindTexture(handle).Apply();
51 handle = 0; 48 handle = 0;
52} 49}
53 50
@@ -65,7 +62,6 @@ void OGLTextureView::Release() {
65 62
66 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 63 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
67 glDeleteTextures(1, &handle); 64 glDeleteTextures(1, &handle);
68 OpenGLState::GetCurState().UnbindTexture(handle).Apply();
69 handle = 0; 65 handle = 0;
70} 66}
71 67
@@ -83,7 +79,6 @@ void OGLSampler::Release() {
83 79
84 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 80 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
85 glDeleteSamplers(1, &handle); 81 glDeleteSamplers(1, &handle);
86 OpenGLState::GetCurState().ResetSampler(handle).Apply();
87 handle = 0; 82 handle = 0;
88} 83}
89 84
@@ -127,7 +122,6 @@ void OGLProgram::Release() {
127 122
128 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 123 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
129 glDeleteProgram(handle); 124 glDeleteProgram(handle);
130 OpenGLState::GetCurState().ResetProgram(handle).Apply();
131 handle = 0; 125 handle = 0;
132} 126}
133 127
@@ -145,7 +139,6 @@ void OGLPipeline::Release() {
145 139
146 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 140 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
147 glDeleteProgramPipelines(1, &handle); 141 glDeleteProgramPipelines(1, &handle);
148 OpenGLState::GetCurState().ResetPipeline(handle).Apply();
149 handle = 0; 142 handle = 0;
150} 143}
151 144
@@ -189,24 +182,6 @@ void OGLSync::Release() {
189 handle = 0; 182 handle = 0;
190} 183}
191 184
192void OGLVertexArray::Create() {
193 if (handle != 0)
194 return;
195
196 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
197 glCreateVertexArrays(1, &handle);
198}
199
200void OGLVertexArray::Release() {
201 if (handle == 0)
202 return;
203
204 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
205 glDeleteVertexArrays(1, &handle);
206 OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
207 handle = 0;
208}
209
210void OGLFramebuffer::Create() { 185void OGLFramebuffer::Create() {
211 if (handle != 0) 186 if (handle != 0)
212 return; 187 return;
@@ -221,7 +196,6 @@ void OGLFramebuffer::Release() {
221 196
222 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); 197 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
223 glDeleteFramebuffers(1, &handle); 198 glDeleteFramebuffers(1, &handle);
224 OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
225 handle = 0; 199 handle = 0;
226} 200}
227 201
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 995a4e45e..de93f4212 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -241,31 +241,6 @@ public:
241 GLsync handle = 0; 241 GLsync handle = 0;
242}; 242};
243 243
244class OGLVertexArray : private NonCopyable {
245public:
246 OGLVertexArray() = default;
247
248 OGLVertexArray(OGLVertexArray&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
249
250 ~OGLVertexArray() {
251 Release();
252 }
253
254 OGLVertexArray& operator=(OGLVertexArray&& o) noexcept {
255 Release();
256 handle = std::exchange(o.handle, 0);
257 return *this;
258 }
259
260 /// Creates a new internal OpenGL resource and stores the handle
261 void Create();
262
263 /// Deletes the internal OpenGL resource
264 void Release();
265
266 GLuint handle = 0;
267};
268
269class OGLFramebuffer : private NonCopyable { 244class OGLFramebuffer : private NonCopyable {
270public: 245public:
271 OGLFramebuffer() = default; 246 OGLFramebuffer() = default;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 489eb143c..4cb89db8c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -22,6 +22,7 @@
22#include "video_core/renderer_opengl/gl_shader_cache.h" 22#include "video_core/renderer_opengl/gl_shader_cache.h"
23#include "video_core/renderer_opengl/gl_shader_decompiler.h" 23#include "video_core/renderer_opengl/gl_shader_decompiler.h"
24#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 24#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
25#include "video_core/renderer_opengl/gl_state_tracker.h"
25#include "video_core/renderer_opengl/utils.h" 26#include "video_core/renderer_opengl/utils.h"
26#include "video_core/shader/shader_ir.h" 27#include "video_core/shader/shader_ir.h"
27 28
@@ -623,7 +624,7 @@ bool ShaderCacheOpenGL::GenerateUnspecializedShaders(
623} 624}
624 625
625Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { 626Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
626 if (!system.GPU().Maxwell3D().dirty.shaders) { 627 if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) {
627 return last_shaders[static_cast<std::size_t>(program)]; 628 return last_shaders[static_cast<std::size_t>(program)];
628 } 629 }
629 630
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 4735000b5..3a41ed30c 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -2547,7 +2547,10 @@ ShaderEntries GetEntries(const VideoCommon::Shader::ShaderIR& ir) {
2547 for (const auto& image : ir.GetImages()) { 2547 for (const auto& image : ir.GetImages()) {
2548 entries.images.emplace_back(image); 2548 entries.images.emplace_back(image);
2549 } 2549 }
2550 entries.clip_distances = ir.GetClipDistances(); 2550 const auto clip_distances = ir.GetClipDistances();
2551 for (std::size_t i = 0; i < std::size(clip_distances); ++i) {
2552 entries.clip_distances = (clip_distances[i] ? 1U : 0U) << i;
2553 }
2551 entries.shader_length = ir.GetLength(); 2554 entries.shader_length = ir.GetLength();
2552 return entries; 2555 return entries;
2553} 2556}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 7876f48d6..0f692c1db 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -74,7 +74,7 @@ struct ShaderEntries {
74 std::vector<GlobalMemoryEntry> global_memory_entries; 74 std::vector<GlobalMemoryEntry> global_memory_entries;
75 std::vector<SamplerEntry> samplers; 75 std::vector<SamplerEntry> samplers;
76 std::vector<ImageEntry> images; 76 std::vector<ImageEntry> images;
77 std::array<bool, Maxwell::NumClipDistances> clip_distances{}; 77 u32 clip_distances{};
78 std::size_t shader_length{}; 78 std::size_t shader_length{};
79}; 79};
80 80
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 75d3fac04..15f3cd066 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -10,27 +10,21 @@ namespace OpenGL::GLShader {
10 10
11using Tegra::Engines::Maxwell3D; 11using Tegra::Engines::Maxwell3D;
12 12
13ProgramManager::ProgramManager() {
14 pipeline.Create();
15}
16
17ProgramManager::~ProgramManager() = default; 13ProgramManager::~ProgramManager() = default;
18 14
19void ProgramManager::ApplyTo(OpenGLState& state) { 15void ProgramManager::Create() {
20 UpdatePipeline(); 16 pipeline.Create();
21 state.draw.shader_program = 0;
22 state.draw.program_pipeline = pipeline.handle;
23} 17}
24 18
25void ProgramManager::UpdatePipeline() { 19void ProgramManager::Update() {
26 // Avoid updating the pipeline when values have no changed 20 // Avoid updating the pipeline when values have no changed
27 if (old_state == current_state) { 21 if (old_state == current_state) {
28 return; 22 return;
29 } 23 }
30 24
31 // Workaround for AMD bug 25 // Workaround for AMD bug
32 constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | 26 static constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT |
33 GL_FRAGMENT_SHADER_BIT}; 27 GL_FRAGMENT_SHADER_BIT};
34 glUseProgramStages(pipeline.handle, all_used_stages, 0); 28 glUseProgramStages(pipeline.handle, all_used_stages, 0);
35 29
36 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader); 30 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader);
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 478c165ce..e94cd75aa 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -9,7 +9,6 @@
9#include <glad/glad.h> 9#include <glad/glad.h>
10 10
11#include "video_core/renderer_opengl/gl_resource_manager.h" 11#include "video_core/renderer_opengl/gl_resource_manager.h"
12#include "video_core/renderer_opengl/gl_state.h"
13#include "video_core/renderer_opengl/maxwell_to_gl.h" 12#include "video_core/renderer_opengl/maxwell_to_gl.h"
14 13
15namespace OpenGL::GLShader { 14namespace OpenGL::GLShader {
@@ -29,25 +28,26 @@ static_assert(sizeof(MaxwellUniformData) < 16384,
29 28
30class ProgramManager { 29class ProgramManager {
31public: 30public:
32 explicit ProgramManager();
33 ~ProgramManager(); 31 ~ProgramManager();
34 32
35 void ApplyTo(OpenGLState& state); 33 void Create();
36 34
37 void UseProgrammableVertexShader(GLuint program) { 35 void Update();
36
37 void UseVertexShader(GLuint program) {
38 current_state.vertex_shader = program; 38 current_state.vertex_shader = program;
39 } 39 }
40 40
41 void UseProgrammableGeometryShader(GLuint program) { 41 void UseGeometryShader(GLuint program) {
42 current_state.geometry_shader = program; 42 current_state.geometry_shader = program;
43 } 43 }
44 44
45 void UseProgrammableFragmentShader(GLuint program) { 45 void UseFragmentShader(GLuint program) {
46 current_state.fragment_shader = program; 46 current_state.fragment_shader = program;
47 } 47 }
48 48
49 void UseTrivialGeometryShader() { 49 GLuint GetHandle() const {
50 current_state.geometry_shader = 0; 50 return pipeline.handle;
51 } 51 }
52 52
53 void UseTrivialFragmentShader() { 53 void UseTrivialFragmentShader() {
@@ -70,8 +70,6 @@ private:
70 GLuint geometry_shader{}; 70 GLuint geometry_shader{};
71 }; 71 };
72 72
73 void UpdatePipeline();
74
75 OGLPipeline pipeline; 73 OGLPipeline pipeline;
76 PipelineState current_state; 74 PipelineState current_state;
77 PipelineState old_state; 75 PipelineState old_state;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
deleted file mode 100644
index 7d3bc1a1f..000000000
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <iterator>
7#include <glad/glad.h>
8#include "common/assert.h"
9#include "common/logging/log.h"
10#include "common/microprofile.h"
11#include "video_core/renderer_opengl/gl_state.h"
12
13MICROPROFILE_DEFINE(OpenGL_State, "OpenGL", "State Change", MP_RGB(192, 128, 128));
14
15namespace OpenGL {
16
17using Maxwell = Tegra::Engines::Maxwell3D::Regs;
18
19OpenGLState OpenGLState::cur_state;
20
21namespace {
22
23template <typename T>
24bool UpdateValue(T& current_value, const T new_value) {
25 const bool changed = current_value != new_value;
26 current_value = new_value;
27 return changed;
28}
29
30template <typename T1, typename T2>
31bool UpdateTie(T1 current_value, const T2 new_value) {
32 const bool changed = current_value != new_value;
33 current_value = new_value;
34 return changed;
35}
36
37template <typename T>
38std::optional<std::pair<GLuint, GLsizei>> UpdateArray(T& current_values, const T& new_values) {
39 std::optional<std::size_t> first;
40 std::size_t last;
41 for (std::size_t i = 0; i < std::size(current_values); ++i) {
42 if (!UpdateValue(current_values[i], new_values[i])) {
43 continue;
44 }
45 if (!first) {
46 first = i;
47 }
48 last = i;
49 }
50 if (!first) {
51 return std::nullopt;
52 }
53 return std::make_pair(static_cast<GLuint>(*first), static_cast<GLsizei>(last - *first + 1));
54}
55
56void Enable(GLenum cap, bool enable) {
57 if (enable) {
58 glEnable(cap);
59 } else {
60 glDisable(cap);
61 }
62}
63
64void Enable(GLenum cap, GLuint index, bool enable) {
65 if (enable) {
66 glEnablei(cap, index);
67 } else {
68 glDisablei(cap, index);
69 }
70}
71
72void Enable(GLenum cap, bool& current_value, bool new_value) {
73 if (UpdateValue(current_value, new_value)) {
74 Enable(cap, new_value);
75 }
76}
77
78void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) {
79 if (UpdateValue(current_value, new_value)) {
80 Enable(cap, index, new_value);
81 }
82}
83
84} // Anonymous namespace
85
86OpenGLState::OpenGLState() = default;
87
88void OpenGLState::SetDefaultViewports() {
89 viewports.fill(Viewport{});
90
91 depth_clamp.far_plane = false;
92 depth_clamp.near_plane = false;
93}
94
95void OpenGLState::ApplyFramebufferState() {
96 if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) {
97 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
98 }
99 if (UpdateValue(cur_state.draw.draw_framebuffer, draw.draw_framebuffer)) {
100 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
101 }
102}
103
104void OpenGLState::ApplyVertexArrayState() {
105 if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) {
106 glBindVertexArray(draw.vertex_array);
107 }
108}
109
110void OpenGLState::ApplyShaderProgram() {
111 if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) {
112 glUseProgram(draw.shader_program);
113 }
114}
115
116void OpenGLState::ApplyProgramPipeline() {
117 if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) {
118 glBindProgramPipeline(draw.program_pipeline);
119 }
120}
121
122void OpenGLState::ApplyClipDistances() {
123 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
124 Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i],
125 clip_distance[i]);
126 }
127}
128
129void OpenGLState::ApplyPointSize() {
130 Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control);
131 Enable(GL_POINT_SPRITE, cur_state.point.sprite, point.sprite);
132 if (UpdateValue(cur_state.point.size, point.size)) {
133 glPointSize(point.size);
134 }
135}
136
137void OpenGLState::ApplyFragmentColorClamp() {
138 if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) {
139 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
140 fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
141 }
142}
143
144void OpenGLState::ApplyMultisample() {
145 Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage,
146 multisample_control.alpha_to_coverage);
147 Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one,
148 multisample_control.alpha_to_one);
149}
150
151void OpenGLState::ApplyDepthClamp() {
152 if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
153 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
154 return;
155 }
156 cur_state.depth_clamp = depth_clamp;
157
158 UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
159 "Unimplemented Depth Clamp Separation!");
160
161 Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane);
162}
163
164void OpenGLState::ApplySRgb() {
165 if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled)
166 return;
167 cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled;
168 if (framebuffer_srgb.enabled) {
169 glEnable(GL_FRAMEBUFFER_SRGB);
170 } else {
171 glDisable(GL_FRAMEBUFFER_SRGB);
172 }
173}
174
175void OpenGLState::ApplyCulling() {
176 Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled);
177
178 if (UpdateValue(cur_state.cull.mode, cull.mode)) {
179 glCullFace(cull.mode);
180 }
181
182 if (UpdateValue(cur_state.cull.front_face, cull.front_face)) {
183 glFrontFace(cull.front_face);
184 }
185}
186
187void OpenGLState::ApplyRasterizerDiscard() {
188 Enable(GL_RASTERIZER_DISCARD, cur_state.rasterizer_discard, rasterizer_discard);
189}
190
191void OpenGLState::ApplyColorMask() {
192 if (!dirty.color_mask) {
193 return;
194 }
195 dirty.color_mask = false;
196
197 for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
198 const auto& updated = color_mask[i];
199 auto& current = cur_state.color_mask[i];
200 if (updated.red_enabled != current.red_enabled ||
201 updated.green_enabled != current.green_enabled ||
202 updated.blue_enabled != current.blue_enabled ||
203 updated.alpha_enabled != current.alpha_enabled) {
204 current = updated;
205 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
206 updated.blue_enabled, updated.alpha_enabled);
207 }
208 }
209}
210
211void OpenGLState::ApplyDepth() {
212 Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled);
213
214 if (cur_state.depth.test_func != depth.test_func) {
215 cur_state.depth.test_func = depth.test_func;
216 glDepthFunc(depth.test_func);
217 }
218
219 if (cur_state.depth.write_mask != depth.write_mask) {
220 cur_state.depth.write_mask = depth.write_mask;
221 glDepthMask(depth.write_mask);
222 }
223}
224
225void OpenGLState::ApplyPrimitiveRestart() {
226 Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled);
227
228 if (cur_state.primitive_restart.index != primitive_restart.index) {
229 cur_state.primitive_restart.index = primitive_restart.index;
230 glPrimitiveRestartIndex(primitive_restart.index);
231 }
232}
233
234void OpenGLState::ApplyStencilTest() {
235 if (!dirty.stencil_state) {
236 return;
237 }
238 dirty.stencil_state = false;
239
240 Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled);
241
242 const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) {
243 if (current.test_func != config.test_func || current.test_ref != config.test_ref ||
244 current.test_mask != config.test_mask) {
245 current.test_func = config.test_func;
246 current.test_ref = config.test_ref;
247 current.test_mask = config.test_mask;
248 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
249 }
250 if (current.action_depth_fail != config.action_depth_fail ||
251 current.action_depth_pass != config.action_depth_pass ||
252 current.action_stencil_fail != config.action_stencil_fail) {
253 current.action_depth_fail = config.action_depth_fail;
254 current.action_depth_pass = config.action_depth_pass;
255 current.action_stencil_fail = config.action_stencil_fail;
256 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
257 config.action_depth_pass);
258 }
259 if (current.write_mask != config.write_mask) {
260 current.write_mask = config.write_mask;
261 glStencilMaskSeparate(face, config.write_mask);
262 }
263 };
264 ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front);
265 ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back);
266}
267
268void OpenGLState::ApplyViewport() {
269 for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) {
270 const auto& updated = viewports[i];
271 auto& current = cur_state.viewports[i];
272
273 if (current.x != updated.x || current.y != updated.y || current.width != updated.width ||
274 current.height != updated.height) {
275 current.x = updated.x;
276 current.y = updated.y;
277 current.width = updated.width;
278 current.height = updated.height;
279 glViewportIndexedf(i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
280 static_cast<GLfloat>(updated.width),
281 static_cast<GLfloat>(updated.height));
282 }
283 if (current.depth_range_near != updated.depth_range_near ||
284 current.depth_range_far != updated.depth_range_far) {
285 current.depth_range_near = updated.depth_range_near;
286 current.depth_range_far = updated.depth_range_far;
287 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
288 }
289
290 Enable(GL_SCISSOR_TEST, i, current.scissor.enabled, updated.scissor.enabled);
291
292 if (current.scissor.x != updated.scissor.x || current.scissor.y != updated.scissor.y ||
293 current.scissor.width != updated.scissor.width ||
294 current.scissor.height != updated.scissor.height) {
295 current.scissor.x = updated.scissor.x;
296 current.scissor.y = updated.scissor.y;
297 current.scissor.width = updated.scissor.width;
298 current.scissor.height = updated.scissor.height;
299 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
300 updated.scissor.height);
301 }
302 }
303}
304
305void OpenGLState::ApplyGlobalBlending() {
306 const Blend& updated = blend[0];
307 Blend& current = cur_state.blend[0];
308
309 Enable(GL_BLEND, current.enabled, updated.enabled);
310
311 if (current.src_rgb_func != updated.src_rgb_func ||
312 current.dst_rgb_func != updated.dst_rgb_func || current.src_a_func != updated.src_a_func ||
313 current.dst_a_func != updated.dst_a_func) {
314 current.src_rgb_func = updated.src_rgb_func;
315 current.dst_rgb_func = updated.dst_rgb_func;
316 current.src_a_func = updated.src_a_func;
317 current.dst_a_func = updated.dst_a_func;
318 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
319 updated.dst_a_func);
320 }
321
322 if (current.rgb_equation != updated.rgb_equation || current.a_equation != updated.a_equation) {
323 current.rgb_equation = updated.rgb_equation;
324 current.a_equation = updated.a_equation;
325 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
326 }
327}
328
329void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) {
330 const Blend& updated = blend[target];
331 Blend& current = cur_state.blend[target];
332
333 if (current.enabled != updated.enabled || force) {
334 current.enabled = updated.enabled;
335 Enable(GL_BLEND, static_cast<GLuint>(target), updated.enabled);
336 }
337
338 if (UpdateTie(std::tie(current.src_rgb_func, current.dst_rgb_func, current.src_a_func,
339 current.dst_a_func),
340 std::tie(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
341 updated.dst_a_func))) {
342 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
343 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
344 }
345
346 if (UpdateTie(std::tie(current.rgb_equation, current.a_equation),
347 std::tie(updated.rgb_equation, updated.a_equation))) {
348 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
349 updated.a_equation);
350 }
351}
352
353void OpenGLState::ApplyBlending() {
354 if (!dirty.blend_state) {
355 return;
356 }
357 dirty.blend_state = false;
358
359 if (independant_blend.enabled) {
360 const bool force = independant_blend.enabled != cur_state.independant_blend.enabled;
361 for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) {
362 ApplyTargetBlending(target, force);
363 }
364 } else {
365 ApplyGlobalBlending();
366 }
367 cur_state.independant_blend.enabled = independant_blend.enabled;
368
369 if (UpdateTie(
370 std::tie(cur_state.blend_color.red, cur_state.blend_color.green,
371 cur_state.blend_color.blue, cur_state.blend_color.alpha),
372 std::tie(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha))) {
373 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
374 }
375}
376
377void OpenGLState::ApplyLogicOp() {
378 Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled);
379
380 if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) {
381 glLogicOp(logic_op.operation);
382 }
383}
384
385void OpenGLState::ApplyPolygonOffset() {
386 if (!dirty.polygon_offset) {
387 return;
388 }
389 dirty.polygon_offset = false;
390
391 Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable,
392 polygon_offset.fill_enable);
393 Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable,
394 polygon_offset.line_enable);
395 Enable(GL_POLYGON_OFFSET_POINT, cur_state.polygon_offset.point_enable,
396 polygon_offset.point_enable);
397
398 if (UpdateTie(std::tie(cur_state.polygon_offset.factor, cur_state.polygon_offset.units,
399 cur_state.polygon_offset.clamp),
400 std::tie(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp))) {
401 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
402 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
403 } else {
404 UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
405 "Unimplemented Depth polygon offset clamp.");
406 glPolygonOffset(polygon_offset.factor, polygon_offset.units);
407 }
408 }
409}
410
411void OpenGLState::ApplyAlphaTest() {
412 Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled);
413 if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref),
414 std::tie(alpha_test.func, alpha_test.ref))) {
415 glAlphaFunc(alpha_test.func, alpha_test.ref);
416 }
417}
418
419void OpenGLState::ApplyClipControl() {
420 if (UpdateTie(std::tie(cur_state.clip_control.origin, cur_state.clip_control.depth_mode),
421 std::tie(clip_control.origin, clip_control.depth_mode))) {
422 glClipControl(clip_control.origin, clip_control.depth_mode);
423 }
424}
425
426void OpenGLState::ApplyRenderBuffer() {
427 if (cur_state.renderbuffer != renderbuffer) {
428 cur_state.renderbuffer = renderbuffer;
429 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
430 }
431}
432
433void OpenGLState::ApplyTextures() {
434 const std::size_t size = std::size(textures);
435 for (std::size_t i = 0; i < size; ++i) {
436 if (UpdateValue(cur_state.textures[i], textures[i])) {
437 // BindTextureUnit doesn't support binding null textures, skip those binds.
438 // TODO(Rodrigo): Stop using null textures
439 if (textures[i] != 0) {
440 glBindTextureUnit(static_cast<GLuint>(i), textures[i]);
441 }
442 }
443 }
444}
445
446void OpenGLState::ApplySamplers() {
447 const std::size_t size = std::size(samplers);
448 for (std::size_t i = 0; i < size; ++i) {
449 if (UpdateValue(cur_state.samplers[i], samplers[i])) {
450 glBindSampler(static_cast<GLuint>(i), samplers[i]);
451 }
452 }
453}
454
455void OpenGLState::ApplyImages() {
456 if (const auto update = UpdateArray(cur_state.images, images)) {
457 glBindImageTextures(update->first, update->second, images.data() + update->first);
458 }
459}
460
461void OpenGLState::Apply() {
462 MICROPROFILE_SCOPE(OpenGL_State);
463 ApplyFramebufferState();
464 ApplyVertexArrayState();
465 ApplyShaderProgram();
466 ApplyProgramPipeline();
467 ApplyClipDistances();
468 ApplyPointSize();
469 ApplyFragmentColorClamp();
470 ApplyMultisample();
471 ApplyRasterizerDiscard();
472 ApplyColorMask();
473 ApplyDepthClamp();
474 ApplyViewport();
475 ApplyStencilTest();
476 ApplySRgb();
477 ApplyCulling();
478 ApplyDepth();
479 ApplyPrimitiveRestart();
480 ApplyBlending();
481 ApplyLogicOp();
482 ApplyTextures();
483 ApplySamplers();
484 ApplyImages();
485 ApplyPolygonOffset();
486 ApplyAlphaTest();
487 ApplyClipControl();
488 ApplyRenderBuffer();
489}
490
491void OpenGLState::EmulateViewportWithScissor() {
492 auto& current = viewports[0];
493 if (current.scissor.enabled) {
494 const GLint left = std::max(current.x, current.scissor.x);
495 const GLint right =
496 std::max(current.x + current.width, current.scissor.x + current.scissor.width);
497 const GLint bottom = std::max(current.y, current.scissor.y);
498 const GLint top =
499 std::max(current.y + current.height, current.scissor.y + current.scissor.height);
500 current.scissor.x = std::max(left, 0);
501 current.scissor.y = std::max(bottom, 0);
502 current.scissor.width = std::max(right - left, 0);
503 current.scissor.height = std::max(top - bottom, 0);
504 } else {
505 current.scissor.enabled = true;
506 current.scissor.x = current.x;
507 current.scissor.y = current.y;
508 current.scissor.width = current.width;
509 current.scissor.height = current.height;
510 }
511}
512
513OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
514 for (auto& texture : textures) {
515 if (texture == handle) {
516 texture = 0;
517 }
518 }
519 return *this;
520}
521
522OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
523 for (auto& sampler : samplers) {
524 if (sampler == handle) {
525 sampler = 0;
526 }
527 }
528 return *this;
529}
530
531OpenGLState& OpenGLState::ResetProgram(GLuint handle) {
532 if (draw.shader_program == handle) {
533 draw.shader_program = 0;
534 }
535 return *this;
536}
537
538OpenGLState& OpenGLState::ResetPipeline(GLuint handle) {
539 if (draw.program_pipeline == handle) {
540 draw.program_pipeline = 0;
541 }
542 return *this;
543}
544
545OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) {
546 if (draw.vertex_array == handle) {
547 draw.vertex_array = 0;
548 }
549 return *this;
550}
551
552OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) {
553 if (draw.read_framebuffer == handle) {
554 draw.read_framebuffer = 0;
555 }
556 if (draw.draw_framebuffer == handle) {
557 draw.draw_framebuffer = 0;
558 }
559 return *this;
560}
561
562OpenGLState& OpenGLState::ResetRenderbuffer(GLuint handle) {
563 if (renderbuffer == handle) {
564 renderbuffer = 0;
565 }
566 return *this;
567}
568
569} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
deleted file mode 100644
index bce662f2c..000000000
--- a/src/video_core/renderer_opengl/gl_state.h
+++ /dev/null
@@ -1,251 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <type_traits>
9#include <glad/glad.h>
10#include "video_core/engines/maxwell_3d.h"
11
12namespace OpenGL {
13
14class OpenGLState {
15public:
16 struct {
17 bool enabled = false; // GL_FRAMEBUFFER_SRGB
18 } framebuffer_srgb;
19
20 struct {
21 bool alpha_to_coverage = false; // GL_ALPHA_TO_COVERAGE
22 bool alpha_to_one = false; // GL_ALPHA_TO_ONE
23 } multisample_control;
24
25 struct {
26 bool enabled = false; // GL_CLAMP_FRAGMENT_COLOR_ARB
27 } fragment_color_clamp;
28
29 struct {
30 bool far_plane = false;
31 bool near_plane = false;
32 } depth_clamp; // GL_DEPTH_CLAMP
33
34 struct {
35 bool enabled = false; // GL_CULL_FACE
36 GLenum mode = GL_BACK; // GL_CULL_FACE_MODE
37 GLenum front_face = GL_CCW; // GL_FRONT_FACE
38 } cull;
39
40 struct {
41 bool test_enabled = false; // GL_DEPTH_TEST
42 GLboolean write_mask = GL_TRUE; // GL_DEPTH_WRITEMASK
43 GLenum test_func = GL_LESS; // GL_DEPTH_FUNC
44 } depth;
45
46 struct {
47 bool enabled = false;
48 GLuint index = 0;
49 } primitive_restart; // GL_PRIMITIVE_RESTART
50
51 bool rasterizer_discard = false; // GL_RASTERIZER_DISCARD
52
53 struct ColorMask {
54 GLboolean red_enabled = GL_TRUE;
55 GLboolean green_enabled = GL_TRUE;
56 GLboolean blue_enabled = GL_TRUE;
57 GLboolean alpha_enabled = GL_TRUE;
58 };
59 std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
60 color_mask; // GL_COLOR_WRITEMASK
61
62 struct {
63 bool test_enabled = false; // GL_STENCIL_TEST
64 struct {
65 GLenum test_func = GL_ALWAYS; // GL_STENCIL_FUNC
66 GLint test_ref = 0; // GL_STENCIL_REF
67 GLuint test_mask = 0xFFFFFFFF; // GL_STENCIL_VALUE_MASK
68 GLuint write_mask = 0xFFFFFFFF; // GL_STENCIL_WRITEMASK
69 GLenum action_stencil_fail = GL_KEEP; // GL_STENCIL_FAIL
70 GLenum action_depth_fail = GL_KEEP; // GL_STENCIL_PASS_DEPTH_FAIL
71 GLenum action_depth_pass = GL_KEEP; // GL_STENCIL_PASS_DEPTH_PASS
72 } front, back;
73 } stencil;
74
75 struct Blend {
76 bool enabled = false; // GL_BLEND
77 GLenum rgb_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_RGB
78 GLenum a_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_ALPHA
79 GLenum src_rgb_func = GL_ONE; // GL_BLEND_SRC_RGB
80 GLenum dst_rgb_func = GL_ZERO; // GL_BLEND_DST_RGB
81 GLenum src_a_func = GL_ONE; // GL_BLEND_SRC_ALPHA
82 GLenum dst_a_func = GL_ZERO; // GL_BLEND_DST_ALPHA
83 };
84 std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
85
86 struct {
87 bool enabled = false;
88 } independant_blend;
89
90 struct {
91 GLclampf red = 0.0f;
92 GLclampf green = 0.0f;
93 GLclampf blue = 0.0f;
94 GLclampf alpha = 0.0f;
95 } blend_color; // GL_BLEND_COLOR
96
97 struct {
98 bool enabled = false; // GL_LOGIC_OP_MODE
99 GLenum operation = GL_COPY;
100 } logic_op;
101
102 static constexpr std::size_t NumSamplers = 32 * 5;
103 static constexpr std::size_t NumImages = 8 * 5;
104 std::array<GLuint, NumSamplers> textures = {};
105 std::array<GLuint, NumSamplers> samplers = {};
106 std::array<GLuint, NumImages> images = {};
107
108 struct {
109 GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING
110 GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING
111 GLuint vertex_array = 0; // GL_VERTEX_ARRAY_BINDING
112 GLuint shader_program = 0; // GL_CURRENT_PROGRAM
113 GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING
114 } draw;
115
116 struct Viewport {
117 GLint x = 0;
118 GLint y = 0;
119 GLint width = 0;
120 GLint height = 0;
121 GLfloat depth_range_near = 0.0f; // GL_DEPTH_RANGE
122 GLfloat depth_range_far = 1.0f; // GL_DEPTH_RANGE
123 struct {
124 bool enabled = false; // GL_SCISSOR_TEST
125 GLint x = 0;
126 GLint y = 0;
127 GLsizei width = 0;
128 GLsizei height = 0;
129 } scissor;
130 };
131 std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
132
133 struct {
134 bool program_control = false; // GL_PROGRAM_POINT_SIZE
135 bool sprite = false; // GL_POINT_SPRITE
136 GLfloat size = 1.0f; // GL_POINT_SIZE
137 } point;
138
139 struct {
140 bool point_enable = false;
141 bool line_enable = false;
142 bool fill_enable = false;
143 GLfloat units = 0.0f;
144 GLfloat factor = 0.0f;
145 GLfloat clamp = 0.0f;
146 } polygon_offset;
147
148 struct {
149 bool enabled = false; // GL_ALPHA_TEST
150 GLenum func = GL_ALWAYS; // GL_ALPHA_TEST_FUNC
151 GLfloat ref = 0.0f; // GL_ALPHA_TEST_REF
152 } alpha_test;
153
154 std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE
155
156 struct {
157 GLenum origin = GL_LOWER_LEFT;
158 GLenum depth_mode = GL_NEGATIVE_ONE_TO_ONE;
159 } clip_control;
160
161 GLuint renderbuffer{}; // GL_RENDERBUFFER_BINDING
162
163 OpenGLState();
164
165 /// Get the currently active OpenGL state
166 static OpenGLState GetCurState() {
167 return cur_state;
168 }
169
170 void SetDefaultViewports();
171 /// Apply this state as the current OpenGL state
172 void Apply();
173
174 void ApplyFramebufferState();
175 void ApplyVertexArrayState();
176 void ApplyShaderProgram();
177 void ApplyProgramPipeline();
178 void ApplyClipDistances();
179 void ApplyPointSize();
180 void ApplyFragmentColorClamp();
181 void ApplyMultisample();
182 void ApplySRgb();
183 void ApplyCulling();
184 void ApplyRasterizerDiscard();
185 void ApplyColorMask();
186 void ApplyDepth();
187 void ApplyPrimitiveRestart();
188 void ApplyStencilTest();
189 void ApplyViewport();
190 void ApplyTargetBlending(std::size_t target, bool force);
191 void ApplyGlobalBlending();
192 void ApplyBlending();
193 void ApplyLogicOp();
194 void ApplyTextures();
195 void ApplySamplers();
196 void ApplyImages();
197 void ApplyDepthClamp();
198 void ApplyPolygonOffset();
199 void ApplyAlphaTest();
200 void ApplyClipControl();
201 void ApplyRenderBuffer();
202
203 /// Resets any references to the given resource
204 OpenGLState& UnbindTexture(GLuint handle);
205 OpenGLState& ResetSampler(GLuint handle);
206 OpenGLState& ResetProgram(GLuint handle);
207 OpenGLState& ResetPipeline(GLuint handle);
208 OpenGLState& ResetVertexArray(GLuint handle);
209 OpenGLState& ResetFramebuffer(GLuint handle);
210 OpenGLState& ResetRenderbuffer(GLuint handle);
211
212 /// Viewport does not affects glClearBuffer so emulate viewport using scissor test
213 void EmulateViewportWithScissor();
214
215 void MarkDirtyBlendState() {
216 dirty.blend_state = true;
217 }
218
219 void MarkDirtyStencilState() {
220 dirty.stencil_state = true;
221 }
222
223 void MarkDirtyPolygonOffset() {
224 dirty.polygon_offset = true;
225 }
226
227 void MarkDirtyColorMask() {
228 dirty.color_mask = true;
229 }
230
231 void AllDirty() {
232 dirty.blend_state = true;
233 dirty.stencil_state = true;
234 dirty.polygon_offset = true;
235 dirty.color_mask = true;
236 }
237
238private:
239 static OpenGLState cur_state;
240
241 struct {
242 bool blend_state;
243 bool stencil_state;
244 bool viewport_state;
245 bool polygon_offset;
246 bool color_mask;
247 } dirty{};
248};
249static_assert(std::is_trivially_copyable_v<OpenGLState>);
250
251} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
new file mode 100644
index 000000000..1e43c9ec0
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -0,0 +1,238 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include <cstddef>
8
9#include "common/common_types.h"
10#include "core/core.h"
11#include "video_core/engines/maxwell_3d.h"
12#include "video_core/gpu.h"
13#include "video_core/renderer_opengl/gl_state_tracker.h"
14
15#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
16#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32))
17
18namespace OpenGL {
19
20namespace {
21
22using namespace Dirty;
23using namespace VideoCommon::Dirty;
24using Tegra::Engines::Maxwell3D;
25using Regs = Maxwell3D::Regs;
26using Tables = Maxwell3D::DirtyState::Tables;
27using Table = Maxwell3D::DirtyState::Table;
28
29void SetupDirtyColorMasks(Tables& tables) {
30 tables[0][OFF(color_mask_common)] = ColorMaskCommon;
31 for (std::size_t rt = 0; rt < Regs::NumRenderTargets; ++rt) {
32 const std::size_t offset = OFF(color_mask) + rt * NUM(color_mask[0]);
33 FillBlock(tables[0], offset, NUM(color_mask[0]), ColorMask0 + rt);
34 }
35
36 FillBlock(tables[1], OFF(color_mask), NUM(color_mask), ColorMasks);
37}
38
39void SetupDirtyVertexArrays(Tables& tables) {
40 static constexpr std::size_t num_array = 3;
41 static constexpr std::size_t instance_base_offset = 3;
42 for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) {
43 const std::size_t array_offset = OFF(vertex_array) + i * NUM(vertex_array[0]);
44 const std::size_t limit_offset = OFF(vertex_array_limit) + i * NUM(vertex_array_limit[0]);
45
46 FillBlock(tables, array_offset, num_array, VertexBuffer0 + i, VertexBuffers);
47 FillBlock(tables, limit_offset, NUM(vertex_array_limit), VertexBuffer0 + i, VertexBuffers);
48
49 const std::size_t instance_array_offset = array_offset + instance_base_offset;
50 tables[0][instance_array_offset] = static_cast<u8>(VertexInstance0 + i);
51 tables[1][instance_array_offset] = VertexInstances;
52
53 const std::size_t instance_offset = OFF(instanced_arrays) + i;
54 tables[0][instance_offset] = static_cast<u8>(VertexInstance0 + i);
55 tables[1][instance_offset] = VertexInstances;
56 }
57}
58
59void SetupDirtyVertexFormat(Tables& tables) {
60 for (std::size_t i = 0; i < Regs::NumVertexAttributes; ++i) {
61 const std::size_t offset = OFF(vertex_attrib_format) + i * NUM(vertex_attrib_format[0]);
62 FillBlock(tables[0], offset, NUM(vertex_attrib_format[0]), VertexFormat0 + i);
63 }
64
65 FillBlock(tables[1], OFF(vertex_attrib_format), Regs::NumVertexAttributes, VertexFormats);
66}
67
68void SetupDirtyViewports(Tables& tables) {
69 for (std::size_t i = 0; i < Regs::NumViewports; ++i) {
70 const std::size_t transf_offset = OFF(viewport_transform) + i * NUM(viewport_transform[0]);
71 const std::size_t viewport_offset = OFF(viewports) + i * NUM(viewports[0]);
72
73 FillBlock(tables[0], transf_offset, NUM(viewport_transform[0]), Viewport0 + i);
74 FillBlock(tables[0], viewport_offset, NUM(viewports[0]), Viewport0 + i);
75 }
76
77 FillBlock(tables[1], OFF(viewport_transform), NUM(viewport_transform), Viewports);
78 FillBlock(tables[1], OFF(viewports), NUM(viewports), Viewports);
79
80 tables[0][OFF(viewport_transform_enabled)] = ViewportTransform;
81 tables[1][OFF(viewport_transform_enabled)] = Viewports;
82}
83
84void SetupDirtyScissors(Tables& tables) {
85 for (std::size_t i = 0; i < Regs::NumViewports; ++i) {
86 const std::size_t offset = OFF(scissor_test) + i * NUM(scissor_test[0]);
87 FillBlock(tables[0], offset, NUM(scissor_test[0]), Scissor0 + i);
88 }
89 FillBlock(tables[1], OFF(scissor_test), NUM(scissor_test), Scissors);
90}
91
92void SetupDirtyShaders(Tables& tables) {
93 FillBlock(tables[0], OFF(shader_config[0]), NUM(shader_config[0]) * Regs::MaxShaderProgram,
94 Shaders);
95}
96
97void SetupDirtyDepthTest(Tables& tables) {
98 auto& table = tables[0];
99 table[OFF(depth_test_enable)] = DepthTest;
100 table[OFF(depth_write_enabled)] = DepthMask;
101 table[OFF(depth_test_func)] = DepthTest;
102}
103
104void SetupDirtyStencilTest(Tables& tables) {
105 static constexpr std::array offsets = {
106 OFF(stencil_enable), OFF(stencil_front_func_func), OFF(stencil_front_func_ref),
107 OFF(stencil_front_func_mask), OFF(stencil_front_op_fail), OFF(stencil_front_op_zfail),
108 OFF(stencil_front_op_zpass), OFF(stencil_front_mask), OFF(stencil_two_side_enable),
109 OFF(stencil_back_func_func), OFF(stencil_back_func_ref), OFF(stencil_back_func_mask),
110 OFF(stencil_back_op_fail), OFF(stencil_back_op_zfail), OFF(stencil_back_op_zpass),
111 OFF(stencil_back_mask)};
112 for (const auto offset : offsets) {
113 tables[0][offset] = StencilTest;
114 }
115}
116
117void SetupDirtyAlphaTest(Tables& tables) {
118 auto& table = tables[0];
119 table[OFF(alpha_test_ref)] = AlphaTest;
120 table[OFF(alpha_test_func)] = AlphaTest;
121 table[OFF(alpha_test_enabled)] = AlphaTest;
122}
123
124void SetupDirtyBlend(Tables& tables) {
125 FillBlock(tables[0], OFF(blend_color), NUM(blend_color), BlendColor);
126
127 tables[0][OFF(independent_blend_enable)] = BlendIndependentEnabled;
128
129 for (std::size_t i = 0; i < Regs::NumRenderTargets; ++i) {
130 const std::size_t offset = OFF(independent_blend) + i * NUM(independent_blend[0]);
131 FillBlock(tables[0], offset, NUM(independent_blend[0]), BlendState0 + i);
132
133 tables[0][OFF(blend.enable) + i] = static_cast<u8>(BlendState0 + i);
134 }
135 FillBlock(tables[1], OFF(independent_blend), NUM(independent_blend), BlendStates);
136 FillBlock(tables[1], OFF(blend), NUM(blend), BlendStates);
137}
138
139void SetupDirtyPrimitiveRestart(Tables& tables) {
140 FillBlock(tables[0], OFF(primitive_restart), NUM(primitive_restart), PrimitiveRestart);
141}
142
143void SetupDirtyPolygonOffset(Tables& tables) {
144 auto& table = tables[0];
145 table[OFF(polygon_offset_fill_enable)] = PolygonOffset;
146 table[OFF(polygon_offset_line_enable)] = PolygonOffset;
147 table[OFF(polygon_offset_point_enable)] = PolygonOffset;
148 table[OFF(polygon_offset_factor)] = PolygonOffset;
149 table[OFF(polygon_offset_units)] = PolygonOffset;
150 table[OFF(polygon_offset_clamp)] = PolygonOffset;
151}
152
153void SetupDirtyMultisampleControl(Tables& tables) {
154 FillBlock(tables[0], OFF(multisample_control), NUM(multisample_control), MultisampleControl);
155}
156
157void SetupDirtyRasterizeEnable(Tables& tables) {
158 tables[0][OFF(rasterize_enable)] = RasterizeEnable;
159}
160
161void SetupDirtyFramebufferSRGB(Tables& tables) {
162 tables[0][OFF(framebuffer_srgb)] = FramebufferSRGB;
163}
164
165void SetupDirtyLogicOp(Tables& tables) {
166 FillBlock(tables[0], OFF(logic_op), NUM(logic_op), LogicOp);
167}
168
169void SetupDirtyFragmentClampColor(Tables& tables) {
170 tables[0][OFF(frag_color_clamp)] = FragmentClampColor;
171}
172
173void SetupDirtyPointSize(Tables& tables) {
174 tables[0][OFF(vp_point_size)] = PointSize;
175 tables[0][OFF(point_size)] = PointSize;
176 tables[0][OFF(point_sprite_enable)] = PointSize;
177}
178
179void SetupDirtyClipControl(Tables& tables) {
180 auto& table = tables[0];
181 table[OFF(screen_y_control)] = ClipControl;
182 table[OFF(depth_mode)] = ClipControl;
183}
184
185void SetupDirtyDepthClampEnabled(Tables& tables) {
186 tables[0][OFF(view_volume_clip_control)] = DepthClampEnabled;
187}
188
189void SetupDirtyMisc(Tables& tables) {
190 auto& table = tables[0];
191
192 table[OFF(clip_distance_enabled)] = ClipDistances;
193
194 table[OFF(front_face)] = FrontFace;
195
196 table[OFF(cull_test_enabled)] = CullTest;
197 table[OFF(cull_face)] = CullTest;
198}
199
200} // Anonymous namespace
201
202StateTracker::StateTracker(Core::System& system) : system{system} {}
203
204void StateTracker::Initialize() {
205 auto& dirty = system.GPU().Maxwell3D().dirty;
206 auto& tables = dirty.tables;
207 SetupDirtyRenderTargets(tables);
208 SetupDirtyColorMasks(tables);
209 SetupDirtyViewports(tables);
210 SetupDirtyScissors(tables);
211 SetupDirtyVertexArrays(tables);
212 SetupDirtyVertexFormat(tables);
213 SetupDirtyShaders(tables);
214 SetupDirtyDepthTest(tables);
215 SetupDirtyStencilTest(tables);
216 SetupDirtyAlphaTest(tables);
217 SetupDirtyBlend(tables);
218 SetupDirtyPrimitiveRestart(tables);
219 SetupDirtyPolygonOffset(tables);
220 SetupDirtyMultisampleControl(tables);
221 SetupDirtyRasterizeEnable(tables);
222 SetupDirtyFramebufferSRGB(tables);
223 SetupDirtyLogicOp(tables);
224 SetupDirtyFragmentClampColor(tables);
225 SetupDirtyPointSize(tables);
226 SetupDirtyClipControl(tables);
227 SetupDirtyDepthClampEnabled(tables);
228 SetupDirtyMisc(tables);
229
230 auto& store = dirty.on_write_stores;
231 SetupCommonOnWriteStores(store);
232 store[VertexBuffers] = true;
233 for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) {
234 store[VertexBuffer0 + i] = true;
235 }
236}
237
238} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h
new file mode 100644
index 000000000..e08482911
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_state_tracker.h
@@ -0,0 +1,204 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <limits>
8
9#include <glad/glad.h>
10
11#include "common/common_types.h"
12#include "core/core.h"
13#include "video_core/dirty_flags.h"
14#include "video_core/engines/maxwell_3d.h"
15
16namespace Core {
17class System;
18}
19
20namespace OpenGL {
21
22namespace Dirty {
23
24enum : u8 {
25 First = VideoCommon::Dirty::LastCommonEntry,
26
27 VertexFormats,
28 VertexFormat0,
29 VertexFormat31 = VertexFormat0 + 31,
30
31 VertexBuffers,
32 VertexBuffer0,
33 VertexBuffer31 = VertexBuffer0 + 31,
34
35 VertexInstances,
36 VertexInstance0,
37 VertexInstance31 = VertexInstance0 + 31,
38
39 ViewportTransform,
40 Viewports,
41 Viewport0,
42 Viewport15 = Viewport0 + 15,
43
44 Scissors,
45 Scissor0,
46 Scissor15 = Scissor0 + 15,
47
48 ColorMaskCommon,
49 ColorMasks,
50 ColorMask0,
51 ColorMask7 = ColorMask0 + 7,
52
53 BlendColor,
54 BlendIndependentEnabled,
55 BlendStates,
56 BlendState0,
57 BlendState7 = BlendState0 + 7,
58
59 Shaders,
60 ClipDistances,
61
62 ColorMask,
63 FrontFace,
64 CullTest,
65 DepthMask,
66 DepthTest,
67 StencilTest,
68 AlphaTest,
69 PrimitiveRestart,
70 PolygonOffset,
71 MultisampleControl,
72 RasterizeEnable,
73 FramebufferSRGB,
74 LogicOp,
75 FragmentClampColor,
76 PointSize,
77 ClipControl,
78 DepthClampEnabled,
79
80 Last
81};
82static_assert(Last <= std::numeric_limits<u8>::max());
83
84} // namespace Dirty
85
86class StateTracker {
87public:
88 explicit StateTracker(Core::System& system);
89
90 void Initialize();
91
92 void BindIndexBuffer(GLuint new_index_buffer) {
93 if (index_buffer == new_index_buffer) {
94 return;
95 }
96 index_buffer = new_index_buffer;
97 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, new_index_buffer);
98 }
99
100 void NotifyScreenDrawVertexArray() {
101 auto& flags = system.GPU().Maxwell3D().dirty.flags;
102 flags[OpenGL::Dirty::VertexFormats] = true;
103 flags[OpenGL::Dirty::VertexFormat0 + 0] = true;
104 flags[OpenGL::Dirty::VertexFormat0 + 1] = true;
105
106 flags[OpenGL::Dirty::VertexBuffers] = true;
107 flags[OpenGL::Dirty::VertexBuffer0] = true;
108
109 flags[OpenGL::Dirty::VertexInstances] = true;
110 flags[OpenGL::Dirty::VertexInstance0 + 0] = true;
111 flags[OpenGL::Dirty::VertexInstance0 + 1] = true;
112 }
113
114 void NotifyViewport0() {
115 auto& flags = system.GPU().Maxwell3D().dirty.flags;
116 flags[OpenGL::Dirty::Viewports] = true;
117 flags[OpenGL::Dirty::Viewport0] = true;
118 }
119
120 void NotifyScissor0() {
121 auto& flags = system.GPU().Maxwell3D().dirty.flags;
122 flags[OpenGL::Dirty::Scissors] = true;
123 flags[OpenGL::Dirty::Scissor0] = true;
124 }
125
126 void NotifyColorMask0() {
127 auto& flags = system.GPU().Maxwell3D().dirty.flags;
128 flags[OpenGL::Dirty::ColorMasks] = true;
129 flags[OpenGL::Dirty::ColorMask0] = true;
130 }
131
132 void NotifyBlend0() {
133 auto& flags = system.GPU().Maxwell3D().dirty.flags;
134 flags[OpenGL::Dirty::BlendStates] = true;
135 flags[OpenGL::Dirty::BlendState0] = true;
136 }
137
138 void NotifyFramebuffer() {
139 auto& flags = system.GPU().Maxwell3D().dirty.flags;
140 flags[VideoCommon::Dirty::RenderTargets] = true;
141 }
142
143 void NotifyFrontFace() {
144 auto& flags = system.GPU().Maxwell3D().dirty.flags;
145 flags[OpenGL::Dirty::FrontFace] = true;
146 }
147
148 void NotifyCullTest() {
149 auto& flags = system.GPU().Maxwell3D().dirty.flags;
150 flags[OpenGL::Dirty::CullTest] = true;
151 }
152
153 void NotifyDepthMask() {
154 auto& flags = system.GPU().Maxwell3D().dirty.flags;
155 flags[OpenGL::Dirty::DepthMask] = true;
156 }
157
158 void NotifyDepthTest() {
159 auto& flags = system.GPU().Maxwell3D().dirty.flags;
160 flags[OpenGL::Dirty::DepthTest] = true;
161 }
162
163 void NotifyStencilTest() {
164 auto& flags = system.GPU().Maxwell3D().dirty.flags;
165 flags[OpenGL::Dirty::StencilTest] = true;
166 }
167
168 void NotifyPolygonOffset() {
169 auto& flags = system.GPU().Maxwell3D().dirty.flags;
170 flags[OpenGL::Dirty::PolygonOffset] = true;
171 }
172
173 void NotifyRasterizeEnable() {
174 auto& flags = system.GPU().Maxwell3D().dirty.flags;
175 flags[OpenGL::Dirty::RasterizeEnable] = true;
176 }
177
178 void NotifyFramebufferSRGB() {
179 auto& flags = system.GPU().Maxwell3D().dirty.flags;
180 flags[OpenGL::Dirty::FramebufferSRGB] = true;
181 }
182
183 void NotifyLogicOp() {
184 auto& flags = system.GPU().Maxwell3D().dirty.flags;
185 flags[OpenGL::Dirty::LogicOp] = true;
186 }
187
188 void NotifyClipControl() {
189 auto& flags = system.GPU().Maxwell3D().dirty.flags;
190 flags[OpenGL::Dirty::ClipControl] = true;
191 }
192
193 void NotifyAlphaTest() {
194 auto& flags = system.GPU().Maxwell3D().dirty.flags;
195 flags[OpenGL::Dirty::AlphaTest] = true;
196 }
197
198private:
199 Core::System& system;
200
201 GLuint index_buffer = 0;
202};
203
204} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index 35ba334e4..6ec328c53 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -7,7 +7,6 @@
7#include "common/alignment.h" 7#include "common/alignment.h"
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/microprofile.h" 9#include "common/microprofile.h"
10#include "video_core/renderer_opengl/gl_state.h"
11#include "video_core/renderer_opengl/gl_stream_buffer.h" 10#include "video_core/renderer_opengl/gl_stream_buffer.h"
12 11
13MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning", 12MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index cf934b0d8..2d3838a7a 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -10,7 +10,7 @@
10#include "core/core.h" 10#include "core/core.h"
11#include "video_core/morton.h" 11#include "video_core/morton.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h" 12#include "video_core/renderer_opengl/gl_resource_manager.h"
13#include "video_core/renderer_opengl/gl_state.h" 13#include "video_core/renderer_opengl/gl_state_tracker.h"
14#include "video_core/renderer_opengl/gl_texture_cache.h" 14#include "video_core/renderer_opengl/gl_texture_cache.h"
15#include "video_core/renderer_opengl/utils.h" 15#include "video_core/renderer_opengl/utils.h"
16#include "video_core/texture_cache/surface_base.h" 16#include "video_core/texture_cache/surface_base.h"
@@ -397,6 +397,7 @@ CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& p
397 const bool is_proxy) 397 const bool is_proxy)
398 : VideoCommon::ViewBase(params), surface{surface}, is_proxy{is_proxy} { 398 : VideoCommon::ViewBase(params), surface{surface}, is_proxy{is_proxy} {
399 target = GetTextureTarget(params.target); 399 target = GetTextureTarget(params.target);
400 format = GetFormatTuple(surface.GetSurfaceParams().pixel_format).internal_format;
400 if (!is_proxy) { 401 if (!is_proxy) {
401 texture_view = CreateTextureView(); 402 texture_view = CreateTextureView();
402 } 403 }
@@ -467,25 +468,20 @@ void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_sou
467} 468}
468 469
469OGLTextureView CachedSurfaceView::CreateTextureView() const { 470OGLTextureView CachedSurfaceView::CreateTextureView() const {
470 const auto& owner_params = surface.GetSurfaceParams();
471 OGLTextureView texture_view; 471 OGLTextureView texture_view;
472 texture_view.Create(); 472 texture_view.Create();
473 473
474 const GLuint handle{texture_view.handle}; 474 glTextureView(texture_view.handle, target, surface.texture.handle, format, params.base_level,
475 const FormatTuple& tuple{GetFormatTuple(owner_params.pixel_format)};
476
477 glTextureView(handle, target, surface.texture.handle, tuple.internal_format, params.base_level,
478 params.num_levels, params.base_layer, params.num_layers); 475 params.num_levels, params.base_layer, params.num_layers);
479 476 ApplyTextureDefaults(surface.GetSurfaceParams(), texture_view.handle);
480 ApplyTextureDefaults(owner_params, handle);
481 477
482 return texture_view; 478 return texture_view;
483} 479}
484 480
485TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, 481TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
486 VideoCore::RasterizerInterface& rasterizer, 482 VideoCore::RasterizerInterface& rasterizer,
487 const Device& device) 483 const Device& device, StateTracker& state_tracker)
488 : TextureCacheBase{system, rasterizer} { 484 : TextureCacheBase{system, rasterizer}, state_tracker{state_tracker} {
489 src_framebuffer.Create(); 485 src_framebuffer.Create();
490 dst_framebuffer.Create(); 486 dst_framebuffer.Create();
491} 487}
@@ -519,25 +515,26 @@ void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view,
519 const Tegra::Engines::Fermi2D::Config& copy_config) { 515 const Tegra::Engines::Fermi2D::Config& copy_config) {
520 const auto& src_params{src_view->GetSurfaceParams()}; 516 const auto& src_params{src_view->GetSurfaceParams()};
521 const auto& dst_params{dst_view->GetSurfaceParams()}; 517 const auto& dst_params{dst_view->GetSurfaceParams()};
518 UNIMPLEMENTED_IF(src_params.target == SurfaceTarget::Texture3D);
519 UNIMPLEMENTED_IF(dst_params.target == SurfaceTarget::Texture3D);
522 520
523 OpenGLState prev_state{OpenGLState::GetCurState()}; 521 state_tracker.NotifyScissor0();
524 SCOPE_EXIT({ 522 state_tracker.NotifyFramebuffer();
525 prev_state.AllDirty(); 523 state_tracker.NotifyRasterizeEnable();
526 prev_state.Apply(); 524 state_tracker.NotifyFramebufferSRGB();
527 });
528
529 OpenGLState state;
530 state.draw.read_framebuffer = src_framebuffer.handle;
531 state.draw.draw_framebuffer = dst_framebuffer.handle;
532 state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
533 state.AllDirty();
534 state.Apply();
535 525
536 u32 buffers{}; 526 if (dst_params.srgb_conversion) {
527 glEnable(GL_FRAMEBUFFER_SRGB);
528 } else {
529 glDisable(GL_FRAMEBUFFER_SRGB);
530 }
531 glDisable(GL_RASTERIZER_DISCARD);
532 glDisablei(GL_SCISSOR_TEST, 0);
537 533
538 UNIMPLEMENTED_IF(src_params.target == SurfaceTarget::Texture3D); 534 glBindFramebuffer(GL_READ_FRAMEBUFFER, src_framebuffer.handle);
539 UNIMPLEMENTED_IF(dst_params.target == SurfaceTarget::Texture3D); 535 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_framebuffer.handle);
540 536
537 GLenum buffers = 0;
541 if (src_params.type == SurfaceType::ColorTexture) { 538 if (src_params.type == SurfaceType::ColorTexture) {
542 src_view->Attach(GL_COLOR_ATTACHMENT0, GL_READ_FRAMEBUFFER); 539 src_view->Attach(GL_COLOR_ATTACHMENT0, GL_READ_FRAMEBUFFER);
543 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 540 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 8e13ab38b..6658c6ffd 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -27,6 +27,7 @@ using VideoCommon::ViewParams;
27class CachedSurfaceView; 27class CachedSurfaceView;
28class CachedSurface; 28class CachedSurface;
29class TextureCacheOpenGL; 29class TextureCacheOpenGL;
30class StateTracker;
30 31
31using Surface = std::shared_ptr<CachedSurface>; 32using Surface = std::shared_ptr<CachedSurface>;
32using View = std::shared_ptr<CachedSurfaceView>; 33using View = std::shared_ptr<CachedSurfaceView>;
@@ -96,6 +97,10 @@ public:
96 return texture_view.handle; 97 return texture_view.handle;
97 } 98 }
98 99
100 GLenum GetFormat() const {
101 return format;
102 }
103
99 const SurfaceParams& GetSurfaceParams() const { 104 const SurfaceParams& GetSurfaceParams() const {
100 return surface.GetSurfaceParams(); 105 return surface.GetSurfaceParams();
101 } 106 }
@@ -113,6 +118,7 @@ private:
113 118
114 CachedSurface& surface; 119 CachedSurface& surface;
115 GLenum target{}; 120 GLenum target{};
121 GLenum format{};
116 122
117 OGLTextureView texture_view; 123 OGLTextureView texture_view;
118 u32 swizzle{}; 124 u32 swizzle{};
@@ -122,7 +128,7 @@ private:
122class TextureCacheOpenGL final : public TextureCacheBase { 128class TextureCacheOpenGL final : public TextureCacheBase {
123public: 129public:
124 explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 130 explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
125 const Device& device); 131 const Device& device, StateTracker& state_tracker);
126 ~TextureCacheOpenGL(); 132 ~TextureCacheOpenGL();
127 133
128protected: 134protected:
@@ -139,6 +145,8 @@ protected:
139private: 145private:
140 GLuint FetchPBO(std::size_t buffer_size); 146 GLuint FetchPBO(std::size_t buffer_size);
141 147
148 StateTracker& state_tracker;
149
142 OGLFramebuffer src_framebuffer; 150 OGLFramebuffer src_framebuffer;
143 OGLFramebuffer dst_framebuffer; 151 OGLFramebuffer dst_framebuffer;
144 std::unordered_map<u32, OGLBuffer> copy_pbo_cache; 152 std::unordered_map<u32, OGLBuffer> copy_pbo_cache;
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index d3dea3659..494e38e7a 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -425,24 +425,24 @@ inline GLenum StencilOp(Maxwell::StencilOp stencil) {
425 return GL_KEEP; 425 return GL_KEEP;
426} 426}
427 427
428inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { 428inline GLenum FrontFace(Maxwell::FrontFace front_face) {
429 switch (front_face) { 429 switch (front_face) {
430 case Maxwell::Cull::FrontFace::ClockWise: 430 case Maxwell::FrontFace::ClockWise:
431 return GL_CW; 431 return GL_CW;
432 case Maxwell::Cull::FrontFace::CounterClockWise: 432 case Maxwell::FrontFace::CounterClockWise:
433 return GL_CCW; 433 return GL_CCW;
434 } 434 }
435 LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); 435 LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face));
436 return GL_CCW; 436 return GL_CCW;
437} 437}
438 438
439inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { 439inline GLenum CullFace(Maxwell::CullFace cull_face) {
440 switch (cull_face) { 440 switch (cull_face) {
441 case Maxwell::Cull::CullFace::Front: 441 case Maxwell::CullFace::Front:
442 return GL_FRONT; 442 return GL_FRONT;
443 case Maxwell::Cull::CullFace::Back: 443 case Maxwell::CullFace::Back:
444 return GL_BACK; 444 return GL_BACK;
445 case Maxwell::Cull::CullFace::FrontAndBack: 445 case Maxwell::CullFace::FrontAndBack:
446 return GL_FRONT_AND_BACK; 446 return GL_FRONT_AND_BACK;
447 } 447 }
448 LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); 448 LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index a4340b502..a51410660 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -20,6 +20,7 @@
20#include "core/telemetry_session.h" 20#include "core/telemetry_session.h"
21#include "video_core/morton.h" 21#include "video_core/morton.h"
22#include "video_core/renderer_opengl/gl_rasterizer.h" 22#include "video_core/renderer_opengl/gl_rasterizer.h"
23#include "video_core/renderer_opengl/gl_shader_manager.h"
23#include "video_core/renderer_opengl/renderer_opengl.h" 24#include "video_core/renderer_opengl/renderer_opengl.h"
24 25
25namespace OpenGL { 26namespace OpenGL {
@@ -86,28 +87,22 @@ public:
86 } 87 }
87 88
88 void ReloadRenderFrame(Frame* frame, u32 width, u32 height) { 89 void ReloadRenderFrame(Frame* frame, u32 width, u32 height) {
89 OpenGLState prev_state = OpenGLState::GetCurState();
90 OpenGLState state = OpenGLState::GetCurState();
91
92 // Recreate the color texture attachment 90 // Recreate the color texture attachment
93 frame->color.Release(); 91 frame->color.Release();
94 frame->color.Create(); 92 frame->color.Create();
95 state.renderbuffer = frame->color.handle; 93 const GLenum internal_format = frame->is_srgb ? GL_SRGB8 : GL_RGB8;
96 state.Apply(); 94 glNamedRenderbufferStorage(frame->color.handle, internal_format, width, height);
97 glRenderbufferStorage(GL_RENDERBUFFER, frame->is_srgb ? GL_SRGB8 : GL_RGB8, width, height);
98 95
99 // Recreate the FBO for the render target 96 // Recreate the FBO for the render target
100 frame->render.Release(); 97 frame->render.Release();
101 frame->render.Create(); 98 frame->render.Create();
102 state.draw.read_framebuffer = frame->render.handle; 99 glBindFramebuffer(GL_FRAMEBUFFER, frame->render.handle);
103 state.draw.draw_framebuffer = frame->render.handle;
104 state.Apply();
105 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 100 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
106 frame->color.handle); 101 frame->color.handle);
107 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 102 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
108 LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); 103 LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!");
109 } 104 }
110 prev_state.Apply(); 105
111 frame->width = width; 106 frame->width = width;
112 frame->height = height; 107 frame->height = height;
113 frame->color_reloaded = true; 108 frame->color_reloaded = true;
@@ -164,9 +159,13 @@ public:
164 159
165namespace { 160namespace {
166 161
167constexpr char vertex_shader[] = R"( 162constexpr char VERTEX_SHADER[] = R"(
168#version 430 core 163#version 430 core
169 164
165out gl_PerVertex {
166 vec4 gl_Position;
167};
168
170layout (location = 0) in vec2 vert_position; 169layout (location = 0) in vec2 vert_position;
171layout (location = 1) in vec2 vert_tex_coord; 170layout (location = 1) in vec2 vert_tex_coord;
172layout (location = 0) out vec2 frag_tex_coord; 171layout (location = 0) out vec2 frag_tex_coord;
@@ -187,7 +186,7 @@ void main() {
187} 186}
188)"; 187)";
189 188
190constexpr char fragment_shader[] = R"( 189constexpr char FRAGMENT_SHADER[] = R"(
191#version 430 core 190#version 430 core
192 191
193layout (location = 0) in vec2 frag_tex_coord; 192layout (location = 0) in vec2 frag_tex_coord;
@@ -196,7 +195,7 @@ layout (location = 0) out vec4 color;
196layout (binding = 0) uniform sampler2D color_texture; 195layout (binding = 0) uniform sampler2D color_texture;
197 196
198void main() { 197void main() {
199 color = texture(color_texture, frag_tex_coord); 198 color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
200} 199}
201)"; 200)";
202 201
@@ -205,8 +204,8 @@ constexpr GLint TexCoordLocation = 1;
205constexpr GLint ModelViewMatrixLocation = 0; 204constexpr GLint ModelViewMatrixLocation = 0;
206 205
207struct ScreenRectVertex { 206struct ScreenRectVertex {
208 constexpr ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) 207 constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v)
209 : position{{x, y}}, tex_coord{{u, v}} {} 208 : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {}
210 209
211 std::array<GLfloat, 2> position; 210 std::array<GLfloat, 2> position;
212 std::array<GLfloat, 2> tex_coord; 211 std::array<GLfloat, 2> tex_coord;
@@ -311,11 +310,6 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
311 return; 310 return;
312 } 311 }
313 312
314 // Maintain the rasterizer's state as a priority
315 OpenGLState prev_state = OpenGLState::GetCurState();
316 state.AllDirty();
317 state.Apply();
318
319 PrepareRendertarget(framebuffer); 313 PrepareRendertarget(framebuffer);
320 RenderScreenshot(); 314 RenderScreenshot();
321 315
@@ -358,8 +352,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
358 frame->is_srgb = screen_info.display_srgb; 352 frame->is_srgb = screen_info.display_srgb;
359 frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height); 353 frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height);
360 } 354 }
361 state.draw.draw_framebuffer = frame->render.handle; 355 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame->render.handle);
362 state.Apply();
363 DrawScreen(layout); 356 DrawScreen(layout);
364 // Create a fence for the frontend to wait on and swap this frame to OffTex 357 // Create a fence for the frontend to wait on and swap this frame to OffTex
365 frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 358 frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
@@ -368,10 +361,6 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
368 m_current_frame++; 361 m_current_frame++;
369 rasterizer->TickFrame(); 362 rasterizer->TickFrame();
370 } 363 }
371
372 // Restore the rasterizer state
373 prev_state.AllDirty();
374 prev_state.Apply();
375} 364}
376 365
377void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { 366void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) {
@@ -442,31 +431,25 @@ void RendererOpenGL::InitOpenGLObjects() {
442 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 431 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
443 0.0f); 432 0.0f);
444 433
445 // Link shaders and get variable locations 434 // Create shader programs
446 shader.CreateFromSource(vertex_shader, nullptr, fragment_shader); 435 OGLShader vertex_shader;
447 state.draw.shader_program = shader.handle; 436 vertex_shader.Create(VERTEX_SHADER, GL_VERTEX_SHADER);
448 state.AllDirty(); 437
449 state.Apply(); 438 OGLShader fragment_shader;
439 fragment_shader.Create(FRAGMENT_SHADER, GL_FRAGMENT_SHADER);
440
441 vertex_program.Create(true, false, vertex_shader.handle);
442 fragment_program.Create(true, false, fragment_shader.handle);
443
444 // Create program pipeline
445 program_manager.Create();
446 glBindProgramPipeline(program_manager.GetHandle());
450 447
451 // Generate VBO handle for drawing 448 // Generate VBO handle for drawing
452 vertex_buffer.Create(); 449 vertex_buffer.Create();
453 450
454 // Generate VAO
455 vertex_array.Create();
456 state.draw.vertex_array = vertex_array.handle;
457
458 // Attach vertex data to VAO 451 // Attach vertex data to VAO
459 glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); 452 glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
460 glVertexArrayAttribFormat(vertex_array.handle, PositionLocation, 2, GL_FLOAT, GL_FALSE,
461 offsetof(ScreenRectVertex, position));
462 glVertexArrayAttribFormat(vertex_array.handle, TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
463 offsetof(ScreenRectVertex, tex_coord));
464 glVertexArrayAttribBinding(vertex_array.handle, PositionLocation, 0);
465 glVertexArrayAttribBinding(vertex_array.handle, TexCoordLocation, 0);
466 glEnableVertexArrayAttrib(vertex_array.handle, PositionLocation);
467 glEnableVertexArrayAttrib(vertex_array.handle, TexCoordLocation);
468 glVertexArrayVertexBuffer(vertex_array.handle, 0, vertex_buffer.handle, 0,
469 sizeof(ScreenRectVertex));
470 453
471 // Allocate textures for the screen 454 // Allocate textures for the screen
472 screen_info.texture.resource.Create(GL_TEXTURE_2D); 455 screen_info.texture.resource.Create(GL_TEXTURE_2D);
@@ -499,7 +482,8 @@ void RendererOpenGL::CreateRasterizer() {
499 if (rasterizer) { 482 if (rasterizer) {
500 return; 483 return;
501 } 484 }
502 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info); 485 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info,
486 program_manager, state_tracker);
503} 487}
504 488
505void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 489void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
@@ -538,8 +522,19 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
538 glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height); 522 glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
539} 523}
540 524
541void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, 525void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
542 float h) { 526 if (renderer_settings.set_background_color) {
527 // Update background color before drawing
528 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
529 0.0f);
530 }
531
532 // Set projection matrix
533 const std::array ortho_matrix =
534 MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
535 glProgramUniformMatrix3x2fv(vertex_program.handle, ModelViewMatrixLocation, 1, GL_FALSE,
536 std::data(ortho_matrix));
537
543 const auto& texcoords = screen_info.display_texcoords; 538 const auto& texcoords = screen_info.display_texcoords;
544 auto left = texcoords.left; 539 auto left = texcoords.left;
545 auto right = texcoords.right; 540 auto right = texcoords.right;
@@ -571,46 +566,77 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
571 static_cast<f32>(screen_info.texture.height); 566 static_cast<f32>(screen_info.texture.height);
572 } 567 }
573 568
569 const auto& screen = layout.screen;
574 const std::array vertices = { 570 const std::array vertices = {
575 ScreenRectVertex(x, y, texcoords.top * scale_u, left * scale_v), 571 ScreenRectVertex(screen.left, screen.top, texcoords.top * scale_u, left * scale_v),
576 ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left * scale_v), 572 ScreenRectVertex(screen.right, screen.top, texcoords.bottom * scale_u, left * scale_v),
577 ScreenRectVertex(x, y + h, texcoords.top * scale_u, right * scale_v), 573 ScreenRectVertex(screen.left, screen.bottom, texcoords.top * scale_u, right * scale_v),
578 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), 574 ScreenRectVertex(screen.right, screen.bottom, texcoords.bottom * scale_u, right * scale_v),
579 }; 575 };
580
581 state.textures[0] = screen_info.display_texture;
582 state.framebuffer_srgb.enabled = screen_info.display_srgb;
583 state.AllDirty();
584 state.Apply();
585 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); 576 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
586 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
587 // Restore default state
588 state.framebuffer_srgb.enabled = false;
589 state.textures[0] = 0;
590 state.AllDirty();
591 state.Apply();
592}
593 577
594void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { 578 // TODO: Signal state tracker about these changes
595 if (renderer_settings.set_background_color) { 579 state_tracker.NotifyScreenDrawVertexArray();
596 // Update background color before drawing 580 state_tracker.NotifyViewport0();
597 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 581 state_tracker.NotifyScissor0();
598 0.0f); 582 state_tracker.NotifyColorMask0();
583 state_tracker.NotifyBlend0();
584 state_tracker.NotifyFramebuffer();
585 state_tracker.NotifyFrontFace();
586 state_tracker.NotifyCullTest();
587 state_tracker.NotifyDepthTest();
588 state_tracker.NotifyStencilTest();
589 state_tracker.NotifyPolygonOffset();
590 state_tracker.NotifyRasterizeEnable();
591 state_tracker.NotifyFramebufferSRGB();
592 state_tracker.NotifyLogicOp();
593 state_tracker.NotifyClipControl();
594 state_tracker.NotifyAlphaTest();
595
596 program_manager.UseVertexShader(vertex_program.handle);
597 program_manager.UseGeometryShader(0);
598 program_manager.UseFragmentShader(fragment_program.handle);
599 program_manager.Update();
600
601 glEnable(GL_CULL_FACE);
602 if (screen_info.display_srgb) {
603 glEnable(GL_FRAMEBUFFER_SRGB);
604 } else {
605 glDisable(GL_FRAMEBUFFER_SRGB);
599 } 606 }
607 glDisable(GL_COLOR_LOGIC_OP);
608 glDisable(GL_DEPTH_TEST);
609 glDisable(GL_STENCIL_TEST);
610 glDisable(GL_POLYGON_OFFSET_FILL);
611 glDisable(GL_RASTERIZER_DISCARD);
612 glDisable(GL_ALPHA_TEST);
613 glDisablei(GL_BLEND, 0);
614 glDisablei(GL_SCISSOR_TEST, 0);
615 glCullFace(GL_BACK);
616 glFrontFace(GL_CW);
617 glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
618 glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
619 glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
620 static_cast<GLfloat>(layout.height));
621 glDepthRangeIndexed(0, 0.0, 0.0);
622
623 glEnableVertexAttribArray(PositionLocation);
624 glEnableVertexAttribArray(TexCoordLocation);
625 glVertexAttribDivisor(PositionLocation, 0);
626 glVertexAttribDivisor(TexCoordLocation, 0);
627 glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
628 offsetof(ScreenRectVertex, position));
629 glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
630 offsetof(ScreenRectVertex, tex_coord));
631 glVertexAttribBinding(PositionLocation, 0);
632 glVertexAttribBinding(TexCoordLocation, 0);
633 glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
634
635 glBindTextureUnit(0, screen_info.display_texture);
636 glBindSampler(0, 0);
600 637
601 const auto& screen = layout.screen;
602
603 glViewport(0, 0, layout.width, layout.height);
604 glClear(GL_COLOR_BUFFER_BIT); 638 glClear(GL_COLOR_BUFFER_BIT);
605 639 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
606 // Set projection matrix
607 const std::array ortho_matrix =
608 MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
609 glUniformMatrix3x2fv(ModelViewMatrixLocation, 1, GL_FALSE, ortho_matrix.data());
610
611 DrawScreenTriangles(screen_info, static_cast<float>(screen.left),
612 static_cast<float>(screen.top), static_cast<float>(screen.GetWidth()),
613 static_cast<float>(screen.GetHeight()));
614} 640}
615 641
616void RendererOpenGL::TryPresent(int timeout_ms) { 642void RendererOpenGL::TryPresent(int timeout_ms) {
@@ -653,13 +679,14 @@ void RendererOpenGL::RenderScreenshot() {
653 return; 679 return;
654 } 680 }
655 681
682 GLint old_read_fb;
683 GLint old_draw_fb;
684 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
685 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
686
656 // Draw the current frame to the screenshot framebuffer 687 // Draw the current frame to the screenshot framebuffer
657 screenshot_framebuffer.Create(); 688 screenshot_framebuffer.Create();
658 GLuint old_read_fb = state.draw.read_framebuffer; 689 glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle);
659 GLuint old_draw_fb = state.draw.draw_framebuffer;
660 state.draw.read_framebuffer = state.draw.draw_framebuffer = screenshot_framebuffer.handle;
661 state.AllDirty();
662 state.Apply();
663 690
664 Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; 691 Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
665 692
@@ -676,12 +703,11 @@ void RendererOpenGL::RenderScreenshot() {
676 renderer_settings.screenshot_bits); 703 renderer_settings.screenshot_bits);
677 704
678 screenshot_framebuffer.Release(); 705 screenshot_framebuffer.Release();
679 state.draw.read_framebuffer = old_read_fb;
680 state.draw.draw_framebuffer = old_draw_fb;
681 state.AllDirty();
682 state.Apply();
683 glDeleteRenderbuffers(1, &renderbuffer); 706 glDeleteRenderbuffers(1, &renderbuffer);
684 707
708 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
709 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
710
685 renderer_settings.screenshot_complete_callback(); 711 renderer_settings.screenshot_complete_callback();
686 renderer_settings.screenshot_requested = false; 712 renderer_settings.screenshot_requested = false;
687} 713}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index d45e69cbc..33073ce5b 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -10,7 +10,8 @@
10#include "common/math_util.h" 10#include "common/math_util.h"
11#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h" 12#include "video_core/renderer_opengl/gl_resource_manager.h"
13#include "video_core/renderer_opengl/gl_state.h" 13#include "video_core/renderer_opengl/gl_shader_manager.h"
14#include "video_core/renderer_opengl/gl_state_tracker.h"
14 15
15namespace Core { 16namespace Core {
16class System; 17class System;
@@ -76,8 +77,6 @@ private:
76 /// Draws the emulated screens to the emulator window. 77 /// Draws the emulated screens to the emulator window.
77 void DrawScreen(const Layout::FramebufferLayout& layout); 78 void DrawScreen(const Layout::FramebufferLayout& layout);
78 79
79 void DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, float h);
80
81 void RenderScreenshot(); 80 void RenderScreenshot();
82 81
83 /// Loads framebuffer from emulated memory into the active OpenGL texture. 82 /// Loads framebuffer from emulated memory into the active OpenGL texture.
@@ -93,17 +92,20 @@ private:
93 Core::Frontend::EmuWindow& emu_window; 92 Core::Frontend::EmuWindow& emu_window;
94 Core::System& system; 93 Core::System& system;
95 94
96 OpenGLState state; 95 StateTracker state_tracker{system};
97 96
98 // OpenGL object IDs 97 // OpenGL object IDs
99 OGLVertexArray vertex_array;
100 OGLBuffer vertex_buffer; 98 OGLBuffer vertex_buffer;
101 OGLProgram shader; 99 OGLProgram vertex_program;
100 OGLProgram fragment_program;
102 OGLFramebuffer screenshot_framebuffer; 101 OGLFramebuffer screenshot_framebuffer;
103 102
104 /// Display information for Switch screen 103 /// Display information for Switch screen
105 ScreenInfo screen_info; 104 ScreenInfo screen_info;
106 105
106 /// Global dummy shader pipeline
107 GLShader::ProgramManager program_manager;
108
107 /// OpenGL framebuffer data 109 /// OpenGL framebuffer data
108 std::vector<u8> gl_framebuffer_data; 110 std::vector<u8> gl_framebuffer_data;
109 111
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp
index ac99e6385..b751086fa 100644
--- a/src/video_core/renderer_opengl/utils.cpp
+++ b/src/video_core/renderer_opengl/utils.cpp
@@ -9,6 +9,7 @@
9#include <glad/glad.h> 9#include <glad/glad.h>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/renderer_opengl/gl_state_tracker.h"
12#include "video_core/renderer_opengl/utils.h" 13#include "video_core/renderer_opengl/utils.h"
13 14
14namespace OpenGL { 15namespace OpenGL {
@@ -20,12 +21,12 @@ struct VertexArrayPushBuffer::Entry {
20 GLsizei stride{}; 21 GLsizei stride{};
21}; 22};
22 23
23VertexArrayPushBuffer::VertexArrayPushBuffer() = default; 24VertexArrayPushBuffer::VertexArrayPushBuffer(StateTracker& state_tracker)
25 : state_tracker{state_tracker} {}
24 26
25VertexArrayPushBuffer::~VertexArrayPushBuffer() = default; 27VertexArrayPushBuffer::~VertexArrayPushBuffer() = default;
26 28
27void VertexArrayPushBuffer::Setup(GLuint vao_) { 29void VertexArrayPushBuffer::Setup() {
28 vao = vao_;
29 index_buffer = nullptr; 30 index_buffer = nullptr;
30 vertex_buffers.clear(); 31 vertex_buffers.clear();
31} 32}
@@ -41,13 +42,11 @@ void VertexArrayPushBuffer::SetVertexBuffer(GLuint binding_index, const GLuint*
41 42
42void VertexArrayPushBuffer::Bind() { 43void VertexArrayPushBuffer::Bind() {
43 if (index_buffer) { 44 if (index_buffer) {
44 glVertexArrayElementBuffer(vao, *index_buffer); 45 state_tracker.BindIndexBuffer(*index_buffer);
45 } 46 }
46 47
47 // TODO(Rodrigo): Find a way to ARB_multi_bind this
48 for (const auto& entry : vertex_buffers) { 48 for (const auto& entry : vertex_buffers) {
49 glVertexArrayVertexBuffer(vao, entry.binding_index, *entry.buffer, entry.offset, 49 glBindVertexBuffer(entry.binding_index, *entry.buffer, entry.offset, entry.stride);
50 entry.stride);
51 } 50 }
52} 51}
53 52
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h
index 3ad7c02d4..47ee3177b 100644
--- a/src/video_core/renderer_opengl/utils.h
+++ b/src/video_core/renderer_opengl/utils.h
@@ -11,12 +11,14 @@
11 11
12namespace OpenGL { 12namespace OpenGL {
13 13
14class StateTracker;
15
14class VertexArrayPushBuffer final { 16class VertexArrayPushBuffer final {
15public: 17public:
16 explicit VertexArrayPushBuffer(); 18 explicit VertexArrayPushBuffer(StateTracker& state_tracker);
17 ~VertexArrayPushBuffer(); 19 ~VertexArrayPushBuffer();
18 20
19 void Setup(GLuint vao_); 21 void Setup();
20 22
21 void SetIndexBuffer(const GLuint* buffer); 23 void SetIndexBuffer(const GLuint* buffer);
22 24
@@ -28,7 +30,8 @@ public:
28private: 30private:
29 struct Entry; 31 struct Entry;
30 32
31 GLuint vao{}; 33 StateTracker& state_tracker;
34
32 const GLuint* index_buffer{}; 35 const GLuint* index_buffer{};
33 std::vector<Entry> vertex_buffers; 36 std::vector<Entry> vertex_buffers;
34}; 37};
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 4e3ff231e..2bb376555 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -112,19 +112,18 @@ constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs)
112 const auto& clip = regs.view_volume_clip_control; 112 const auto& clip = regs.view_volume_clip_control;
113 const bool depth_clamp_enabled = clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1; 113 const bool depth_clamp_enabled = clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1;
114 114
115 Maxwell::Cull::FrontFace front_face = regs.cull.front_face; 115 Maxwell::FrontFace front_face = regs.front_face;
116 if (regs.screen_y_control.triangle_rast_flip != 0 && 116 if (regs.screen_y_control.triangle_rast_flip != 0 &&
117 regs.viewport_transform[0].scale_y > 0.0f) { 117 regs.viewport_transform[0].scale_y > 0.0f) {
118 if (front_face == Maxwell::Cull::FrontFace::CounterClockWise) 118 if (front_face == Maxwell::FrontFace::CounterClockWise)
119 front_face = Maxwell::Cull::FrontFace::ClockWise; 119 front_face = Maxwell::FrontFace::ClockWise;
120 else if (front_face == Maxwell::Cull::FrontFace::ClockWise) 120 else if (front_face == Maxwell::FrontFace::ClockWise)
121 front_face = Maxwell::Cull::FrontFace::CounterClockWise; 121 front_face = Maxwell::FrontFace::CounterClockWise;
122 } 122 }
123 123
124 const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; 124 const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
125 return FixedPipelineState::Rasterizer(regs.cull.enabled, depth_bias_enabled, 125 return FixedPipelineState::Rasterizer(regs.cull_test_enabled, depth_bias_enabled,
126 depth_clamp_enabled, gl_ndc, regs.cull.cull_face, 126 depth_clamp_enabled, gl_ndc, regs.cull_face, front_face);
127 front_face);
128} 127}
129 128
130} // Anonymous namespace 129} // Anonymous namespace
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index 87056ef37..4c8ba7f90 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -171,8 +171,8 @@ struct FixedPipelineState {
171 171
172 struct Rasterizer { 172 struct Rasterizer {
173 constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool depth_clamp_enable, 173 constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool depth_clamp_enable,
174 bool ndc_minus_one_to_one, Maxwell::Cull::CullFace cull_face, 174 bool ndc_minus_one_to_one, Maxwell::CullFace cull_face,
175 Maxwell::Cull::FrontFace front_face) 175 Maxwell::FrontFace front_face)
176 : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable}, 176 : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable},
177 depth_clamp_enable{depth_clamp_enable}, ndc_minus_one_to_one{ndc_minus_one_to_one}, 177 depth_clamp_enable{depth_clamp_enable}, ndc_minus_one_to_one{ndc_minus_one_to_one},
178 cull_face{cull_face}, front_face{front_face} {} 178 cull_face{cull_face}, front_face{front_face} {}
@@ -182,8 +182,8 @@ struct FixedPipelineState {
182 bool depth_bias_enable; 182 bool depth_bias_enable;
183 bool depth_clamp_enable; 183 bool depth_clamp_enable;
184 bool ndc_minus_one_to_one; 184 bool ndc_minus_one_to_one;
185 Maxwell::Cull::CullFace cull_face; 185 Maxwell::CullFace cull_face;
186 Maxwell::Cull::FrontFace front_face; 186 Maxwell::FrontFace front_face;
187 187
188 std::size_t Hash() const noexcept; 188 std::size_t Hash() const noexcept;
189 189
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 948d67d89..df3ac707c 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -586,24 +586,24 @@ vk::BlendFactor BlendFactor(Maxwell::Blend::Factor factor) {
586 return {}; 586 return {};
587} 587}
588 588
589vk::FrontFace FrontFace(Maxwell::Cull::FrontFace front_face) { 589vk::FrontFace FrontFace(Maxwell::FrontFace front_face) {
590 switch (front_face) { 590 switch (front_face) {
591 case Maxwell::Cull::FrontFace::ClockWise: 591 case Maxwell::FrontFace::ClockWise:
592 return vk::FrontFace::eClockwise; 592 return vk::FrontFace::eClockwise;
593 case Maxwell::Cull::FrontFace::CounterClockWise: 593 case Maxwell::FrontFace::CounterClockWise:
594 return vk::FrontFace::eCounterClockwise; 594 return vk::FrontFace::eCounterClockwise;
595 } 595 }
596 UNIMPLEMENTED_MSG("Unimplemented front face={}", static_cast<u32>(front_face)); 596 UNIMPLEMENTED_MSG("Unimplemented front face={}", static_cast<u32>(front_face));
597 return {}; 597 return {};
598} 598}
599 599
600vk::CullModeFlags CullFace(Maxwell::Cull::CullFace cull_face) { 600vk::CullModeFlags CullFace(Maxwell::CullFace cull_face) {
601 switch (cull_face) { 601 switch (cull_face) {
602 case Maxwell::Cull::CullFace::Front: 602 case Maxwell::CullFace::Front:
603 return vk::CullModeFlagBits::eFront; 603 return vk::CullModeFlagBits::eFront;
604 case Maxwell::Cull::CullFace::Back: 604 case Maxwell::CullFace::Back:
605 return vk::CullModeFlagBits::eBack; 605 return vk::CullModeFlagBits::eBack;
606 case Maxwell::Cull::CullFace::FrontAndBack: 606 case Maxwell::CullFace::FrontAndBack:
607 return vk::CullModeFlagBits::eFrontAndBack; 607 return vk::CullModeFlagBits::eFrontAndBack;
608 } 608 }
609 UNIMPLEMENTED_MSG("Unimplemented cull face={}", static_cast<u32>(cull_face)); 609 UNIMPLEMENTED_MSG("Unimplemented cull face={}", static_cast<u32>(cull_face));
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h
index 7e9678b7b..24f6ab544 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.h
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h
@@ -54,9 +54,9 @@ vk::BlendOp BlendEquation(Maxwell::Blend::Equation equation);
54 54
55vk::BlendFactor BlendFactor(Maxwell::Blend::Factor factor); 55vk::BlendFactor BlendFactor(Maxwell::Blend::Factor factor);
56 56
57vk::FrontFace FrontFace(Maxwell::Cull::FrontFace front_face); 57vk::FrontFace FrontFace(Maxwell::FrontFace front_face);
58 58
59vk::CullModeFlags CullFace(Maxwell::Cull::CullFace cull_face); 59vk::CullModeFlags CullFace(Maxwell::CullFace cull_face);
60 60
61vk::ComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); 61vk::ComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle);
62 62
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index ddc62bc97..42bb01418 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -27,6 +27,7 @@
27#include "video_core/renderer_vulkan/vk_rasterizer.h" 27#include "video_core/renderer_vulkan/vk_rasterizer.h"
28#include "video_core/renderer_vulkan/vk_resource_manager.h" 28#include "video_core/renderer_vulkan/vk_resource_manager.h"
29#include "video_core/renderer_vulkan/vk_scheduler.h" 29#include "video_core/renderer_vulkan/vk_scheduler.h"
30#include "video_core/renderer_vulkan/vk_state_tracker.h"
30#include "video_core/renderer_vulkan/vk_swapchain.h" 31#include "video_core/renderer_vulkan/vk_swapchain.h"
31 32
32namespace Vulkan { 33namespace Vulkan {
@@ -177,10 +178,13 @@ bool RendererVulkan::Init() {
177 swapchain = std::make_unique<VKSwapchain>(surface, *device); 178 swapchain = std::make_unique<VKSwapchain>(surface, *device);
178 swapchain->Create(framebuffer.width, framebuffer.height, false); 179 swapchain->Create(framebuffer.width, framebuffer.height, false);
179 180
180 scheduler = std::make_unique<VKScheduler>(*device, *resource_manager); 181 state_tracker = std::make_unique<StateTracker>(system);
182
183 scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker);
181 184
182 rasterizer = std::make_unique<RasterizerVulkan>(system, render_window, screen_info, *device, 185 rasterizer = std::make_unique<RasterizerVulkan>(system, render_window, screen_info, *device,
183 *resource_manager, *memory_manager, *scheduler); 186 *resource_manager, *memory_manager,
187 *state_tracker, *scheduler);
184 188
185 blit_screen = std::make_unique<VKBlitScreen>(system, render_window, *rasterizer, *device, 189 blit_screen = std::make_unique<VKBlitScreen>(system, render_window, *rasterizer, *device,
186 *resource_manager, *memory_manager, *swapchain, 190 *resource_manager, *memory_manager, *swapchain,
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index f513397f0..3da08d2e4 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -4,8 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <optional> 8#include <optional>
8#include <vector> 9#include <vector>
10
9#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
10#include "video_core/renderer_vulkan/declarations.h" 12#include "video_core/renderer_vulkan/declarations.h"
11 13
@@ -15,6 +17,7 @@ class System;
15 17
16namespace Vulkan { 18namespace Vulkan {
17 19
20class StateTracker;
18class VKBlitScreen; 21class VKBlitScreen;
19class VKDevice; 22class VKDevice;
20class VKFence; 23class VKFence;
@@ -61,6 +64,7 @@ private:
61 std::unique_ptr<VKSwapchain> swapchain; 64 std::unique_ptr<VKSwapchain> swapchain;
62 std::unique_ptr<VKMemoryManager> memory_manager; 65 std::unique_ptr<VKMemoryManager> memory_manager;
63 std::unique_ptr<VKResourceManager> resource_manager; 66 std::unique_ptr<VKResourceManager> resource_manager;
67 std::unique_ptr<StateTracker> state_tracker;
64 std::unique_ptr<VKScheduler> scheduler; 68 std::unique_ptr<VKScheduler> scheduler;
65 std::unique_ptr<VKBlitScreen> blit_screen; 69 std::unique_ptr<VKBlitScreen> blit_screen;
66}; 70};
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 696e4b291..144e1e007 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -188,11 +188,6 @@ VKPipelineCache::~VKPipelineCache() = default;
188 188
189std::array<Shader, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() { 189std::array<Shader, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
190 const auto& gpu = system.GPU().Maxwell3D(); 190 const auto& gpu = system.GPU().Maxwell3D();
191 auto& dirty = system.GPU().Maxwell3D().dirty.shaders;
192 if (!dirty) {
193 return last_shaders;
194 }
195 dirty = false;
196 191
197 std::array<Shader, Maxwell::MaxShaderProgram> shaders; 192 std::array<Shader, Maxwell::MaxShaderProgram> shaders;
198 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 193 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 3fe28c204..b402fb268 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -36,6 +36,7 @@
36#include "video_core/renderer_vulkan/vk_sampler_cache.h" 36#include "video_core/renderer_vulkan/vk_sampler_cache.h"
37#include "video_core/renderer_vulkan/vk_scheduler.h" 37#include "video_core/renderer_vulkan/vk_scheduler.h"
38#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 38#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
39#include "video_core/renderer_vulkan/vk_state_tracker.h"
39#include "video_core/renderer_vulkan/vk_texture_cache.h" 40#include "video_core/renderer_vulkan/vk_texture_cache.h"
40#include "video_core/renderer_vulkan/vk_update_descriptor.h" 41#include "video_core/renderer_vulkan/vk_update_descriptor.h"
41 42
@@ -280,10 +281,11 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf,
280RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer, 281RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer,
281 VKScreenInfo& screen_info, const VKDevice& device, 282 VKScreenInfo& screen_info, const VKDevice& device,
282 VKResourceManager& resource_manager, 283 VKResourceManager& resource_manager,
283 VKMemoryManager& memory_manager, VKScheduler& scheduler) 284 VKMemoryManager& memory_manager, StateTracker& state_tracker,
285 VKScheduler& scheduler)
284 : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer}, 286 : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer},
285 screen_info{screen_info}, device{device}, resource_manager{resource_manager}, 287 screen_info{screen_info}, device{device}, resource_manager{resource_manager},
286 memory_manager{memory_manager}, scheduler{scheduler}, 288 memory_manager{memory_manager}, state_tracker{state_tracker}, scheduler{scheduler},
287 staging_pool(device, memory_manager, scheduler), descriptor_pool(device), 289 staging_pool(device, memory_manager, scheduler), descriptor_pool(device),
288 update_descriptor_queue(device, scheduler), 290 update_descriptor_queue(device, scheduler),
289 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 291 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
@@ -548,6 +550,10 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
548 return true; 550 return true;
549} 551}
550 552
553void RasterizerVulkan::SetupDirtyFlags() {
554 state_tracker.Initialize();
555}
556
551void RasterizerVulkan::FlushWork() { 557void RasterizerVulkan::FlushWork() {
552 static constexpr u32 DRAWS_TO_DISPATCH = 4096; 558 static constexpr u32 DRAWS_TO_DISPATCH = 4096;
553 559
@@ -571,9 +577,9 @@ void RasterizerVulkan::FlushWork() {
571 577
572RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() { 578RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
573 MICROPROFILE_SCOPE(Vulkan_RenderTargets); 579 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
574 auto& dirty = system.GPU().Maxwell3D().dirty; 580 auto& dirty = system.GPU().Maxwell3D().dirty.flags;
575 const bool update_rendertargets = dirty.render_settings; 581 const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
576 dirty.render_settings = false; 582 dirty[VideoCommon::Dirty::RenderTargets] = false;
577 583
578 texture_cache.GuardRenderTargets(true); 584 texture_cache.GuardRenderTargets(true);
579 585
@@ -723,13 +729,13 @@ void RasterizerVulkan::SetupImageTransitions(
723} 729}
724 730
725void RasterizerVulkan::UpdateDynamicStates() { 731void RasterizerVulkan::UpdateDynamicStates() {
726 auto& gpu = system.GPU().Maxwell3D(); 732 auto& regs = system.GPU().Maxwell3D().regs;
727 UpdateViewportsState(gpu); 733 UpdateViewportsState(regs);
728 UpdateScissorsState(gpu); 734 UpdateScissorsState(regs);
729 UpdateDepthBias(gpu); 735 UpdateDepthBias(regs);
730 UpdateBlendConstants(gpu); 736 UpdateBlendConstants(regs);
731 UpdateDepthBounds(gpu); 737 UpdateDepthBounds(regs);
732 UpdateStencilFaces(gpu); 738 UpdateStencilFaces(regs);
733} 739}
734 740
735void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex_input, 741void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex_input,
@@ -979,12 +985,10 @@ void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const Ima
979 image_views.push_back(ImageView{std::move(view), image_layout}); 985 image_views.push_back(ImageView{std::move(view), image_layout});
980} 986}
981 987
982void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu) { 988void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) {
983 if (!gpu.dirty.viewport_transform && scheduler.TouchViewports()) { 989 if (!state_tracker.TouchViewports()) {
984 return; 990 return;
985 } 991 }
986 gpu.dirty.viewport_transform = false;
987 const auto& regs = gpu.regs;
988 const std::array viewports{ 992 const std::array viewports{
989 GetViewportState(device, regs, 0), GetViewportState(device, regs, 1), 993 GetViewportState(device, regs, 0), GetViewportState(device, regs, 1),
990 GetViewportState(device, regs, 2), GetViewportState(device, regs, 3), 994 GetViewportState(device, regs, 2), GetViewportState(device, regs, 3),
@@ -999,12 +1003,10 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu) {
999 }); 1003 });
1000} 1004}
1001 1005
1002void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D& gpu) { 1006void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
1003 if (!gpu.dirty.scissor_test && scheduler.TouchScissors()) { 1007 if (!state_tracker.TouchScissors()) {
1004 return; 1008 return;
1005 } 1009 }
1006 gpu.dirty.scissor_test = false;
1007 const auto& regs = gpu.regs;
1008 const std::array scissors = { 1010 const std::array scissors = {
1009 GetScissorState(regs, 0), GetScissorState(regs, 1), GetScissorState(regs, 2), 1011 GetScissorState(regs, 0), GetScissorState(regs, 1), GetScissorState(regs, 2),
1010 GetScissorState(regs, 3), GetScissorState(regs, 4), GetScissorState(regs, 5), 1012 GetScissorState(regs, 3), GetScissorState(regs, 4), GetScissorState(regs, 5),
@@ -1017,46 +1019,39 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D& gpu) {
1017 }); 1019 });
1018} 1020}
1019 1021
1020void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D& gpu) { 1022void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
1021 if (!gpu.dirty.polygon_offset && scheduler.TouchDepthBias()) { 1023 if (!state_tracker.TouchDepthBias()) {
1022 return; 1024 return;
1023 } 1025 }
1024 gpu.dirty.polygon_offset = false;
1025 const auto& regs = gpu.regs;
1026 scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp, 1026 scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp,
1027 factor = regs.polygon_offset_factor](auto cmdbuf, auto& dld) { 1027 factor = regs.polygon_offset_factor](auto cmdbuf, auto& dld) {
1028 cmdbuf.setDepthBias(constant, clamp, factor / 2.0f, dld); 1028 cmdbuf.setDepthBias(constant, clamp, factor / 2.0f, dld);
1029 }); 1029 });
1030} 1030}
1031 1031
1032void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D& gpu) { 1032void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs) {
1033 if (!gpu.dirty.blend_state && scheduler.TouchBlendConstants()) { 1033 if (!state_tracker.TouchBlendConstants()) {
1034 return; 1034 return;
1035 } 1035 }
1036 gpu.dirty.blend_state = false; 1036 const std::array blend_color = {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
1037 const std::array blend_color = {gpu.regs.blend_color.r, gpu.regs.blend_color.g, 1037 regs.blend_color.a};
1038 gpu.regs.blend_color.b, gpu.regs.blend_color.a};
1039 scheduler.Record([blend_color](auto cmdbuf, auto& dld) { 1038 scheduler.Record([blend_color](auto cmdbuf, auto& dld) {
1040 cmdbuf.setBlendConstants(blend_color.data(), dld); 1039 cmdbuf.setBlendConstants(blend_color.data(), dld);
1041 }); 1040 });
1042} 1041}
1043 1042
1044void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D& gpu) { 1043void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs) {
1045 if (!gpu.dirty.depth_bounds_values && scheduler.TouchDepthBounds()) { 1044 if (!state_tracker.TouchDepthBounds()) {
1046 return; 1045 return;
1047 } 1046 }
1048 gpu.dirty.depth_bounds_values = false;
1049 const auto& regs = gpu.regs;
1050 scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]]( 1047 scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
1051 auto cmdbuf, auto& dld) { cmdbuf.setDepthBounds(min, max, dld); }); 1048 auto cmdbuf, auto& dld) { cmdbuf.setDepthBounds(min, max, dld); });
1052} 1049}
1053 1050
1054void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D& gpu) { 1051void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs) {
1055 if (!gpu.dirty.stencil_test && scheduler.TouchStencilValues()) { 1052 if (!state_tracker.TouchStencilProperties()) {
1056 return; 1053 return;
1057 } 1054 }
1058 gpu.dirty.stencil_test = false;
1059 const auto& regs = gpu.regs;
1060 if (regs.stencil_two_side_enable) { 1055 if (regs.stencil_two_side_enable) {
1061 // Separate values per face 1056 // Separate values per face
1062 scheduler.Record( 1057 scheduler.Record(
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 4dc8af6e8..96ea05f0a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -96,6 +96,7 @@ struct hash<Vulkan::FramebufferCacheKey> {
96 96
97namespace Vulkan { 97namespace Vulkan {
98 98
99class StateTracker;
99class BufferBindings; 100class BufferBindings;
100 101
101struct ImageView { 102struct ImageView {
@@ -108,7 +109,7 @@ public:
108 explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window, 109 explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window,
109 VKScreenInfo& screen_info, const VKDevice& device, 110 VKScreenInfo& screen_info, const VKDevice& device,
110 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 111 VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
111 VKScheduler& scheduler); 112 StateTracker& state_tracker, VKScheduler& scheduler);
112 ~RasterizerVulkan() override; 113 ~RasterizerVulkan() override;
113 114
114 void Draw(bool is_indexed, bool is_instanced) override; 115 void Draw(bool is_indexed, bool is_instanced) override;
@@ -127,6 +128,7 @@ public:
127 const Tegra::Engines::Fermi2D::Config& copy_config) override; 128 const Tegra::Engines::Fermi2D::Config& copy_config) override;
128 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 129 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
129 u32 pixel_stride) override; 130 u32 pixel_stride) override;
131 void SetupDirtyFlags() override;
130 132
131 /// Maximum supported size that a constbuffer can have in bytes. 133 /// Maximum supported size that a constbuffer can have in bytes.
132 static constexpr std::size_t MaxConstbufferSize = 0x10000; 134 static constexpr std::size_t MaxConstbufferSize = 0x10000;
@@ -215,12 +217,12 @@ private:
215 217
216 void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry); 218 void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry);
217 219
218 void UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu); 220 void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs);
219 void UpdateScissorsState(Tegra::Engines::Maxwell3D& gpu); 221 void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs);
220 void UpdateDepthBias(Tegra::Engines::Maxwell3D& gpu); 222 void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs);
221 void UpdateBlendConstants(Tegra::Engines::Maxwell3D& gpu); 223 void UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs);
222 void UpdateDepthBounds(Tegra::Engines::Maxwell3D& gpu); 224 void UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs);
223 void UpdateStencilFaces(Tegra::Engines::Maxwell3D& gpu); 225 void UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs);
224 226
225 std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; 227 std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const;
226 228
@@ -241,6 +243,7 @@ private:
241 const VKDevice& device; 243 const VKDevice& device;
242 VKResourceManager& resource_manager; 244 VKResourceManager& resource_manager;
243 VKMemoryManager& memory_manager; 245 VKMemoryManager& memory_manager;
246 StateTracker& state_tracker;
244 VKScheduler& scheduler; 247 VKScheduler& scheduler;
245 248
246 VKStagingBufferPool staging_pool; 249 VKStagingBufferPool staging_pool;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 92bd6c344..b61d4fe63 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -2,6 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
6#include <mutex>
7#include <optional>
8#include <thread>
9#include <utility>
10
5#include "common/assert.h" 11#include "common/assert.h"
6#include "common/microprofile.h" 12#include "common/microprofile.h"
7#include "video_core/renderer_vulkan/declarations.h" 13#include "video_core/renderer_vulkan/declarations.h"
@@ -9,6 +15,7 @@
9#include "video_core/renderer_vulkan/vk_query_cache.h" 15#include "video_core/renderer_vulkan/vk_query_cache.h"
10#include "video_core/renderer_vulkan/vk_resource_manager.h" 16#include "video_core/renderer_vulkan/vk_resource_manager.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_state_tracker.h"
12 19
13namespace Vulkan { 20namespace Vulkan {
14 21
@@ -29,9 +36,10 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
29 last = nullptr; 36 last = nullptr;
30} 37}
31 38
32VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager) 39VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager,
33 : device{device}, resource_manager{resource_manager}, next_fence{ 40 StateTracker& state_tracker)
34 &resource_manager.CommitFence()} { 41 : device{device}, resource_manager{resource_manager}, state_tracker{state_tracker},
42 next_fence{&resource_manager.CommitFence()} {
35 AcquireNewChunk(); 43 AcquireNewChunk();
36 AllocateNewContext(); 44 AllocateNewContext();
37 worker_thread = std::thread(&VKScheduler::WorkerThread, this); 45 worker_thread = std::thread(&VKScheduler::WorkerThread, this);
@@ -157,12 +165,7 @@ void VKScheduler::AllocateNewContext() {
157 165
158void VKScheduler::InvalidateState() { 166void VKScheduler::InvalidateState() {
159 state.graphics_pipeline = nullptr; 167 state.graphics_pipeline = nullptr;
160 state.viewports = false; 168 state_tracker.InvalidateCommandBufferState();
161 state.scissors = false;
162 state.depth_bias = false;
163 state.blend_constants = false;
164 state.depth_bounds = false;
165 state.stencil_values = false;
166} 169}
167 170
168void VKScheduler::EndPendingOperations() { 171void VKScheduler::EndPendingOperations() {
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 62fd7858b..c7cc291c3 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -17,6 +17,7 @@
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
20class StateTracker;
20class VKDevice; 21class VKDevice;
21class VKFence; 22class VKFence;
22class VKQueryCache; 23class VKQueryCache;
@@ -43,7 +44,8 @@ private:
43/// OpenGL-like operations on Vulkan command buffers. 44/// OpenGL-like operations on Vulkan command buffers.
44class VKScheduler { 45class VKScheduler {
45public: 46public:
46 explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager); 47 explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager,
48 StateTracker& state_tracker);
47 ~VKScheduler(); 49 ~VKScheduler();
48 50
49 /// Sends the current execution context to the GPU. 51 /// Sends the current execution context to the GPU.
@@ -74,36 +76,6 @@ public:
74 query_cache = &query_cache_; 76 query_cache = &query_cache_;
75 } 77 }
76 78
77 /// Returns true when viewports have been set in the current command buffer.
78 bool TouchViewports() {
79 return std::exchange(state.viewports, true);
80 }
81
82 /// Returns true when scissors have been set in the current command buffer.
83 bool TouchScissors() {
84 return std::exchange(state.scissors, true);
85 }
86
87 /// Returns true when depth bias have been set in the current command buffer.
88 bool TouchDepthBias() {
89 return std::exchange(state.depth_bias, true);
90 }
91
92 /// Returns true when blend constants have been set in the current command buffer.
93 bool TouchBlendConstants() {
94 return std::exchange(state.blend_constants, true);
95 }
96
97 /// Returns true when depth bounds have been set in the current command buffer.
98 bool TouchDepthBounds() {
99 return std::exchange(state.depth_bounds, true);
100 }
101
102 /// Returns true when stencil values have been set in the current command buffer.
103 bool TouchStencilValues() {
104 return std::exchange(state.stencil_values, true);
105 }
106
107 /// Send work to a separate thread. 79 /// Send work to a separate thread.
108 template <typename T> 80 template <typename T>
109 void Record(T&& command) { 81 void Record(T&& command) {
@@ -217,6 +189,8 @@ private:
217 189
218 const VKDevice& device; 190 const VKDevice& device;
219 VKResourceManager& resource_manager; 191 VKResourceManager& resource_manager;
192 StateTracker& state_tracker;
193
220 VKQueryCache* query_cache = nullptr; 194 VKQueryCache* query_cache = nullptr;
221 195
222 vk::CommandBuffer current_cmdbuf; 196 vk::CommandBuffer current_cmdbuf;
@@ -226,12 +200,6 @@ private:
226 struct State { 200 struct State {
227 std::optional<vk::RenderPassBeginInfo> renderpass; 201 std::optional<vk::RenderPassBeginInfo> renderpass;
228 vk::Pipeline graphics_pipeline; 202 vk::Pipeline graphics_pipeline;
229 bool viewports = false;
230 bool scissors = false;
231 bool depth_bias = false;
232 bool blend_constants = false;
233 bool depth_bounds = false;
234 bool stencil_values = false;
235 } state; 203 } state;
236 204
237 std::unique_ptr<CommandChunk> chunk; 205 std::unique_ptr<CommandChunk> chunk;
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
new file mode 100644
index 000000000..d74e68b63
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -0,0 +1,101 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstddef>
7#include <iterator>
8
9#include "common/common_types.h"
10#include "core/core.h"
11#include "video_core/dirty_flags.h"
12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/gpu.h"
14#include "video_core/renderer_vulkan/vk_state_tracker.h"
15
16#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
17#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32))
18
19namespace Vulkan {
20
21namespace {
22
23using namespace Dirty;
24using namespace VideoCommon::Dirty;
25using Tegra::Engines::Maxwell3D;
26using Regs = Maxwell3D::Regs;
27using Tables = Maxwell3D::DirtyState::Tables;
28using Table = Maxwell3D::DirtyState::Table;
29using Flags = Maxwell3D::DirtyState::Flags;
30
31Flags MakeInvalidationFlags() {
32 Flags flags{};
33 flags[Viewports] = true;
34 flags[Scissors] = true;
35 flags[DepthBias] = true;
36 flags[BlendConstants] = true;
37 flags[DepthBounds] = true;
38 flags[StencilProperties] = true;
39 return flags;
40}
41
42void SetupDirtyViewports(Tables& tables) {
43 FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports);
44 FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports);
45 tables[0][OFF(viewport_transform_enabled)] = Viewports;
46}
47
48void SetupDirtyScissors(Tables& tables) {
49 FillBlock(tables[0], OFF(scissor_test), NUM(scissor_test), Scissors);
50}
51
52void SetupDirtyDepthBias(Tables& tables) {
53 auto& table = tables[0];
54 table[OFF(polygon_offset_units)] = DepthBias;
55 table[OFF(polygon_offset_clamp)] = DepthBias;
56 table[OFF(polygon_offset_factor)] = DepthBias;
57}
58
59void SetupDirtyBlendConstants(Tables& tables) {
60 FillBlock(tables[0], OFF(blend_color), NUM(blend_color), BlendConstants);
61}
62
63void SetupDirtyDepthBounds(Tables& tables) {
64 FillBlock(tables[0], OFF(depth_bounds), NUM(depth_bounds), DepthBounds);
65}
66
67void SetupDirtyStencilProperties(Tables& tables) {
68 auto& table = tables[0];
69 table[OFF(stencil_two_side_enable)] = StencilProperties;
70 table[OFF(stencil_front_func_ref)] = StencilProperties;
71 table[OFF(stencil_front_mask)] = StencilProperties;
72 table[OFF(stencil_front_func_mask)] = StencilProperties;
73 table[OFF(stencil_back_func_ref)] = StencilProperties;
74 table[OFF(stencil_back_mask)] = StencilProperties;
75 table[OFF(stencil_back_func_mask)] = StencilProperties;
76}
77
78} // Anonymous namespace
79
80StateTracker::StateTracker(Core::System& system)
81 : system{system}, invalidation_flags{MakeInvalidationFlags()} {}
82
83void StateTracker::Initialize() {
84 auto& dirty = system.GPU().Maxwell3D().dirty;
85 auto& tables = dirty.tables;
86 SetupDirtyRenderTargets(tables);
87 SetupDirtyViewports(tables);
88 SetupDirtyScissors(tables);
89 SetupDirtyDepthBias(tables);
90 SetupDirtyBlendConstants(tables);
91 SetupDirtyDepthBounds(tables);
92 SetupDirtyStencilProperties(tables);
93
94 SetupCommonOnWriteStores(dirty.on_write_stores);
95}
96
97void StateTracker::InvalidateCommandBufferState() {
98 system.GPU().Maxwell3D().dirty.flags |= invalidation_flags;
99}
100
101} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
new file mode 100644
index 000000000..03bc415b2
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -0,0 +1,79 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <limits>
9
10#include "common/common_types.h"
11#include "core/core.h"
12#include "video_core/dirty_flags.h"
13#include "video_core/engines/maxwell_3d.h"
14
15namespace Vulkan {
16
17namespace Dirty {
18
19enum : u8 {
20 First = VideoCommon::Dirty::LastCommonEntry,
21
22 Viewports,
23 Scissors,
24 DepthBias,
25 BlendConstants,
26 DepthBounds,
27 StencilProperties,
28
29 Last
30};
31static_assert(Last <= std::numeric_limits<u8>::max());
32
33} // namespace Dirty
34
35class StateTracker {
36public:
37 explicit StateTracker(Core::System& system);
38
39 void Initialize();
40
41 void InvalidateCommandBufferState();
42
43 bool TouchViewports() {
44 return Exchange(Dirty::Viewports, false);
45 }
46
47 bool TouchScissors() {
48 return Exchange(Dirty::Scissors, false);
49 }
50
51 bool TouchDepthBias() {
52 return Exchange(Dirty::DepthBias, false);
53 }
54
55 bool TouchBlendConstants() {
56 return Exchange(Dirty::BlendConstants, false);
57 }
58
59 bool TouchDepthBounds() {
60 return Exchange(Dirty::DepthBounds, false);
61 }
62
63 bool TouchStencilProperties() {
64 return Exchange(Dirty::StencilProperties, false);
65 }
66
67private:
68 bool Exchange(std::size_t id, bool new_value) const noexcept {
69 auto& flags = system.GPU().Maxwell3D().dirty.flags;
70 const bool is_dirty = flags[id];
71 flags[id] = new_value;
72 return is_dirty;
73 }
74
75 Core::System& system;
76 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
77};
78
79} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 51b0d38a6..73d92a5ae 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -22,6 +22,7 @@
22#include "video_core/renderer_vulkan/vk_device.h" 22#include "video_core/renderer_vulkan/vk_device.h"
23#include "video_core/renderer_vulkan/vk_memory_manager.h" 23#include "video_core/renderer_vulkan/vk_memory_manager.h"
24#include "video_core/renderer_vulkan/vk_rasterizer.h" 24#include "video_core/renderer_vulkan/vk_rasterizer.h"
25#include "video_core/renderer_vulkan/vk_scheduler.h"
25#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 26#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
26#include "video_core/renderer_vulkan/vk_texture_cache.h" 27#include "video_core/renderer_vulkan/vk_texture_cache.h"
27#include "video_core/surface.h" 28#include "video_core/surface.h"
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c70e4aec2..51373b687 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -22,6 +22,7 @@
22#include "core/core.h" 22#include "core/core.h"
23#include "core/memory.h" 23#include "core/memory.h"
24#include "core/settings.h" 24#include "core/settings.h"
25#include "video_core/dirty_flags.h"
25#include "video_core/engines/fermi_2d.h" 26#include "video_core/engines/fermi_2d.h"
26#include "video_core/engines/maxwell_3d.h" 27#include "video_core/engines/maxwell_3d.h"
27#include "video_core/gpu.h" 28#include "video_core/gpu.h"
@@ -142,11 +143,10 @@ public:
142 TView GetDepthBufferSurface(bool preserve_contents) { 143 TView GetDepthBufferSurface(bool preserve_contents) {
143 std::lock_guard lock{mutex}; 144 std::lock_guard lock{mutex};
144 auto& maxwell3d = system.GPU().Maxwell3D(); 145 auto& maxwell3d = system.GPU().Maxwell3D();
145 146 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
146 if (!maxwell3d.dirty.depth_buffer) {
147 return depth_buffer.view; 147 return depth_buffer.view;
148 } 148 }
149 maxwell3d.dirty.depth_buffer = false; 149 maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false;
150 150
151 const auto& regs{maxwell3d.regs}; 151 const auto& regs{maxwell3d.regs};
152 const auto gpu_addr{regs.zeta.Address()}; 152 const auto gpu_addr{regs.zeta.Address()};
@@ -175,10 +175,10 @@ public:
175 std::lock_guard lock{mutex}; 175 std::lock_guard lock{mutex};
176 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); 176 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
177 auto& maxwell3d = system.GPU().Maxwell3D(); 177 auto& maxwell3d = system.GPU().Maxwell3D();
178 if (!maxwell3d.dirty.render_target[index]) { 178 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index]) {
179 return render_targets[index].view; 179 return render_targets[index].view;
180 } 180 }
181 maxwell3d.dirty.render_target[index] = false; 181 maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index] = false;
182 182
183 const auto& regs{maxwell3d.regs}; 183 const auto& regs{maxwell3d.regs};
184 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 || 184 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
@@ -320,14 +320,14 @@ protected:
320 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0; 320 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0;
321 321
322 void ManageRenderTargetUnregister(TSurface& surface) { 322 void ManageRenderTargetUnregister(TSurface& surface) {
323 auto& maxwell3d = system.GPU().Maxwell3D(); 323 auto& dirty = system.GPU().Maxwell3D().dirty;
324 const u32 index = surface->GetRenderTarget(); 324 const u32 index = surface->GetRenderTarget();
325 if (index == DEPTH_RT) { 325 if (index == DEPTH_RT) {
326 maxwell3d.dirty.depth_buffer = true; 326 dirty.flags[VideoCommon::Dirty::ZetaBuffer] = true;
327 } else { 327 } else {
328 maxwell3d.dirty.render_target[index] = true; 328 dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index] = true;
329 } 329 }
330 maxwell3d.dirty.render_settings = true; 330 dirty.flags[VideoCommon::Dirty::RenderTargets] = true;
331 } 331 }
332 332
333 void Register(TSurface surface) { 333 void Register(TSurface surface) {