summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp9
-rw-r--r--src/video_core/engines/maxwell_3d.h267
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/rasterizer_interface.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp289
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp238
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h13
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp20
-rw-r--r--src/video_core/renderer_opengl/gl_state.h2
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h50
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp32
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h4
-rw-r--r--src/video_core/video_core.cpp2
17 files changed, 710 insertions, 241 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 3dab81769..841f27d7f 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -31,6 +31,7 @@ add_library(video_core STATIC
31 renderer_opengl/gl_state.h 31 renderer_opengl/gl_state.h
32 renderer_opengl/gl_stream_buffer.cpp 32 renderer_opengl/gl_stream_buffer.cpp
33 renderer_opengl/gl_stream_buffer.h 33 renderer_opengl/gl_stream_buffer.h
34 renderer_opengl/maxwell_to_gl.h
34 renderer_opengl/renderer_opengl.cpp 35 renderer_opengl/renderer_opengl.cpp
35 renderer_opengl/renderer_opengl.h 36 renderer_opengl/renderer_opengl.h
36 textures/decoders.cpp 37 textures/decoders.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 088d4357e..5359d21a2 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -7,8 +7,11 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "video_core/debug_utils/debug_utils.h" 8#include "video_core/debug_utils/debug_utils.h"
9#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
10#include "video_core/rasterizer_interface.h"
11#include "video_core/renderer_base.h"
10#include "video_core/textures/decoders.h" 12#include "video_core/textures/decoders.h"
11#include "video_core/textures/texture.h" 13#include "video_core/textures/texture.h"
14#include "video_core/video_core.h"
12 15
13namespace Tegra { 16namespace Tegra {
14namespace Engines { 17namespace Engines {
@@ -174,7 +177,9 @@ void Maxwell3D::ProcessQueryGet() {
174} 177}
175 178
176void Maxwell3D::DrawArrays() { 179void Maxwell3D::DrawArrays() {
177 LOG_WARNING(HW_GPU, "Game requested a DrawArrays, ignoring"); 180 LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(),
181 regs.vertex_buffer.count);
182
178 auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); 183 auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
179 184
180 if (debug_context) { 185 if (debug_context) {
@@ -184,6 +189,8 @@ void Maxwell3D::DrawArrays() {
184 if (debug_context) { 189 if (debug_context) {
185 debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); 190 debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
186 } 191 }
192
193 VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/);
187} 194}
188 195
189void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) { 196void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 8e2d888e7..3066bc606 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -11,6 +11,8 @@
11#include "common/bit_field.h" 11#include "common/bit_field.h"
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/math_util.h"
15#include "video_core/gpu.h"
14#include "video_core/memory_manager.h" 16#include "video_core/memory_manager.h"
15#include "video_core/textures/texture.h" 17#include "video_core/textures/texture.h"
16 18
@@ -59,88 +61,173 @@ public:
59 Fragment = 4, 61 Fragment = 4,
60 }; 62 };
61 63
62 enum class VertexSize : u32 { 64 struct VertexAttribute {
63 Size_32_32_32_32 = 0x01, 65 enum class Size : u32 {
64 Size_32_32_32 = 0x02, 66 Size_32_32_32_32 = 0x01,
65 Size_16_16_16_16 = 0x03, 67 Size_32_32_32 = 0x02,
66 Size_32_32 = 0x04, 68 Size_16_16_16_16 = 0x03,
67 Size_16_16_16 = 0x05, 69 Size_32_32 = 0x04,
68 Size_8_8_8_8 = 0x0a, 70 Size_16_16_16 = 0x05,
69 Size_16_16 = 0x0f, 71 Size_8_8_8_8 = 0x0a,
70 Size_32 = 0x12, 72 Size_16_16 = 0x0f,
71 Size_8_8_8 = 0x13, 73 Size_32 = 0x12,
72 Size_8_8 = 0x18, 74 Size_8_8_8 = 0x13,
73 Size_16 = 0x1b, 75 Size_8_8 = 0x18,
74 Size_8 = 0x1d, 76 Size_16 = 0x1b,
75 Size_10_10_10_2 = 0x30, 77 Size_8 = 0x1d,
76 Size_11_11_10 = 0x31, 78 Size_10_10_10_2 = 0x30,
77 }; 79 Size_11_11_10 = 0x31,
80 };
78 81
79 static std::string VertexSizeToString(VertexSize vertex_size) { 82 enum class Type : u32 {
80 switch (vertex_size) { 83 SignedNorm = 1,
81 case VertexSize::Size_32_32_32_32: 84 UnsignedNorm = 2,
82 return "32_32_32_32"; 85 SignedInt = 3,
83 case VertexSize::Size_32_32_32: 86 UnsignedInt = 4,
84 return "32_32_32"; 87 UnsignedScaled = 5,
85 case VertexSize::Size_16_16_16_16: 88 SignedScaled = 6,
86 return "16_16_16_16"; 89 Float = 7,
87 case VertexSize::Size_32_32: 90 };
88 return "32_32"; 91
89 case VertexSize::Size_16_16_16: 92 union {
90 return "16_16_16"; 93 BitField<0, 5, u32> buffer;
91 case VertexSize::Size_8_8_8_8: 94 BitField<6, 1, u32> constant;
92 return "8_8_8_8"; 95 BitField<7, 14, u32> offset;
93 case VertexSize::Size_16_16: 96 BitField<21, 6, Size> size;
94 return "16_16"; 97 BitField<27, 3, Type> type;
95 case VertexSize::Size_32: 98 BitField<31, 1, u32> bgra;
96 return "32"; 99 };
97 case VertexSize::Size_8_8_8: 100
98 return "8_8_8"; 101 u32 ComponentCount() const {
99 case VertexSize::Size_8_8: 102 switch (size) {
100 return "8_8"; 103 case Size::Size_32_32_32_32:
101 case VertexSize::Size_16: 104 return 4;
102 return "16"; 105 case Size::Size_32_32_32:
103 case VertexSize::Size_8: 106 return 3;
104 return "8"; 107 case Size::Size_16_16_16_16:
105 case VertexSize::Size_10_10_10_2: 108 return 4;
106 return "10_10_10_2"; 109 case Size::Size_32_32:
107 case VertexSize::Size_11_11_10: 110 return 2;
108 return "11_11_10"; 111 case Size::Size_16_16_16:
112 return 3;
113 case Size::Size_8_8_8_8:
114 return 4;
115 case Size::Size_16_16:
116 return 2;
117 case Size::Size_32:
118 return 1;
119 case Size::Size_8_8_8:
120 return 3;
121 case Size::Size_8_8:
122 return 2;
123 case Size::Size_16:
124 return 1;
125 case Size::Size_8:
126 return 1;
127 case Size::Size_10_10_10_2:
128 return 4;
129 case Size::Size_11_11_10:
130 return 3;
131 default:
132 UNREACHABLE();
133 }
134 }
135
136 u32 SizeInBytes() const {
137 switch (size) {
138 case Size::Size_32_32_32_32:
139 return 16;
140 case Size::Size_32_32_32:
141 return 12;
142 case Size::Size_16_16_16_16:
143 return 8;
144 case Size::Size_32_32:
145 return 8;
146 case Size::Size_16_16_16:
147 return 6;
148 case Size::Size_8_8_8_8:
149 return 4;
150 case Size::Size_16_16:
151 return 4;
152 case Size::Size_32:
153 return 4;
154 case Size::Size_8_8_8:
155 return 3;
156 case Size::Size_8_8:
157 return 2;
158 case Size::Size_16:
159 return 2;
160 case Size::Size_8:
161 return 1;
162 case Size::Size_10_10_10_2:
163 return 4;
164 case Size::Size_11_11_10:
165 return 4;
166 default:
167 UNREACHABLE();
168 }
109 } 169 }
110 UNIMPLEMENTED();
111 return {};
112 }
113
114 enum class VertexType : u32 {
115 SignedNorm = 1,
116 UnsignedNorm = 2,
117 SignedInt = 3,
118 UnsignedInt = 4,
119 UnsignedScaled = 5,
120 SignedScaled = 6,
121 Float = 7,
122 };
123 170
124 static std::string VertexTypeToString(VertexType vertex_type) { 171 std::string SizeString() const {
125 switch (vertex_type) { 172 switch (size) {
126 case VertexType::SignedNorm: 173 case Size::Size_32_32_32_32:
127 return "SignedNorm"; 174 return "32_32_32_32";
128 case VertexType::UnsignedNorm: 175 case Size::Size_32_32_32:
129 return "UnsignedNorm"; 176 return "32_32_32";
130 case VertexType::SignedInt: 177 case Size::Size_16_16_16_16:
131 return "SignedInt"; 178 return "16_16_16_16";
132 case VertexType::UnsignedInt: 179 case Size::Size_32_32:
133 return "UnsignedInt"; 180 return "32_32";
134 case VertexType::UnsignedScaled: 181 case Size::Size_16_16_16:
135 return "UnsignedScaled"; 182 return "16_16_16";
136 case VertexType::SignedScaled: 183 case Size::Size_8_8_8_8:
137 return "SignedScaled"; 184 return "8_8_8_8";
138 case VertexType::Float: 185 case Size::Size_16_16:
139 return "Float"; 186 return "16_16";
187 case Size::Size_32:
188 return "32";
189 case Size::Size_8_8_8:
190 return "8_8_8";
191 case Size::Size_8_8:
192 return "8_8";
193 case Size::Size_16:
194 return "16";
195 case Size::Size_8:
196 return "8";
197 case Size::Size_10_10_10_2:
198 return "10_10_10_2";
199 case Size::Size_11_11_10:
200 return "11_11_10";
201 }
202 UNREACHABLE();
203 return {};
140 } 204 }
141 UNIMPLEMENTED(); 205
142 return {}; 206 std::string TypeString() const {
143 } 207 switch (type) {
208 case Type::SignedNorm:
209 return "SNORM";
210 case Type::UnsignedNorm:
211 return "UNORM";
212 case Type::SignedInt:
213 return "SINT";
214 case Type::UnsignedInt:
215 return "UINT";
216 case Type::UnsignedScaled:
217 return "USCALED";
218 case Type::SignedScaled:
219 return "SSCALED";
220 case Type::Float:
221 return "FLOAT";
222 }
223 UNREACHABLE();
224 return {};
225 }
226
227 bool IsNormalized() const {
228 return (type == Type::SignedNorm) || (type == Type::UnsignedNorm);
229 }
230 };
144 231
145 enum class PrimitiveTopology : u32 { 232 enum class PrimitiveTopology : u32 {
146 Points = 0x0, 233 Points = 0x0,
@@ -167,9 +254,9 @@ public:
167 struct { 254 struct {
168 u32 address_high; 255 u32 address_high;
169 u32 address_low; 256 u32 address_low;
170 u32 horiz; 257 u32 width;
171 u32 vert; 258 u32 height;
172 u32 format; 259 Tegra::RenderTargetFormat format;
173 u32 block_dimensions; 260 u32 block_dimensions;
174 u32 array_mode; 261 u32 array_mode;
175 u32 layer_stride; 262 u32 layer_stride;
@@ -195,6 +282,15 @@ public:
195 }; 282 };
196 float depth_range_near; 283 float depth_range_near;
197 float depth_range_far; 284 float depth_range_far;
285
286 MathUtil::Rectangle<s32> GetRect() const {
287 return {
288 static_cast<s32>(x), // left
289 static_cast<s32>(y + height), // top
290 static_cast<s32>(x + width), // right
291 static_cast<s32>(y) // bottom
292 };
293 };
198 } viewport[NumViewports]; 294 } viewport[NumViewports];
199 295
200 INSERT_PADDING_WORDS(0x1D); 296 INSERT_PADDING_WORDS(0x1D);
@@ -221,14 +317,7 @@ public:
221 317
222 INSERT_PADDING_WORDS(0x5B); 318 INSERT_PADDING_WORDS(0x5B);
223 319
224 union { 320 VertexAttribute vertex_attrib_format[NumVertexAttributes];
225 BitField<0, 5, u32> buffer;
226 BitField<6, 1, u32> constant;
227 BitField<7, 14, u32> offset;
228 BitField<21, 6, VertexSize> size;
229 BitField<27, 3, VertexType> type;
230 BitField<31, 1, u32> bgra;
231 } vertex_attrib_format[NumVertexAttributes];
232 321
233 INSERT_PADDING_WORDS(0xF); 322 INSERT_PADDING_WORDS(0xF);
234 323
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 8183b12e9..71a8661b4 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -13,7 +13,8 @@
13 13
14namespace Tegra { 14namespace Tegra {
15 15
16enum class RenderTargetFormat { 16enum class RenderTargetFormat : u32 {
17 NONE = 0x0,
17 RGBA8_UNORM = 0xD5, 18 RGBA8_UNORM = 0xD5,
18}; 19};
19 20
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index a493e1d60..8239f9aad 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -15,8 +15,8 @@ class RasterizerInterface {
15public: 15public:
16 virtual ~RasterizerInterface() {} 16 virtual ~RasterizerInterface() {}
17 17
18 /// Draw the current batch of triangles 18 /// Draw the current batch of vertex arrays
19 virtual void DrawTriangles() = 0; 19 virtual void DrawArrays() = 0;
20 20
21 /// Notify rasterizer that the specified Maxwell register has been changed 21 /// Notify rasterizer that the specified Maxwell register has been changed
22 virtual void NotifyMaxwellRegisterChanged(u32 id) = 0; 22 virtual void NotifyMaxwellRegisterChanged(u32 id) = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 286491b73..911890f16 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -14,11 +14,16 @@
14#include "common/microprofile.h" 14#include "common/microprofile.h"
15#include "common/scope_exit.h" 15#include "common/scope_exit.h"
16#include "common/vector_math.h" 16#include "common/vector_math.h"
17#include "core/core.h"
18#include "core/hle/kernel/process.h"
17#include "core/settings.h" 19#include "core/settings.h"
20#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer.h" 21#include "video_core/renderer_opengl/gl_rasterizer.h"
19#include "video_core/renderer_opengl/gl_shader_gen.h" 22#include "video_core/renderer_opengl/gl_shader_gen.h"
23#include "video_core/renderer_opengl/maxwell_to_gl.h"
20#include "video_core/renderer_opengl/renderer_opengl.h" 24#include "video_core/renderer_opengl/renderer_opengl.h"
21 25
26using Maxwell = Tegra::Engines::Maxwell3D::Regs;
22using PixelFormat = SurfaceParams::PixelFormat; 27using PixelFormat = SurfaceParams::PixelFormat;
23using SurfaceType = SurfaceParams::SurfaceType; 28using SurfaceType = SurfaceParams::SurfaceType;
24 29
@@ -120,14 +125,14 @@ RasterizerOpenGL::RasterizerOpenGL() {
120 glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY); 125 glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
121 glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle); 126 glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
122 } else { 127 } else {
123 ASSERT_MSG(false, "Unimplemented"); 128 UNREACHABLE();
124 } 129 }
125 130
126 accelerate_draw = AccelDraw::Disabled; 131 accelerate_draw = AccelDraw::Disabled;
127 132
128 glEnable(GL_BLEND); 133 glEnable(GL_BLEND);
129 134
130 LOG_WARNING(HW_GPU, "Sync fixed function OpenGL state here when ready"); 135 LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
131} 136}
132 137
133RasterizerOpenGL::~RasterizerOpenGL() { 138RasterizerOpenGL::~RasterizerOpenGL() {
@@ -138,47 +143,235 @@ RasterizerOpenGL::~RasterizerOpenGL() {
138 } 143 }
139} 144}
140 145
141static constexpr std::array<GLenum, 4> vs_attrib_types{
142 GL_BYTE, // VertexAttributeFormat::BYTE
143 GL_UNSIGNED_BYTE, // VertexAttributeFormat::UBYTE
144 GL_SHORT, // VertexAttributeFormat::SHORT
145 GL_FLOAT // VertexAttributeFormat::FLOAT
146};
147
148void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { 146void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) {
149 UNIMPLEMENTED(); 147 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
148
149 if (is_indexed) {
150 UNREACHABLE();
151 }
152
153 // TODO(bunnei): Add support for 1+ vertex arrays
154 vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride;
150} 155}
151 156
152void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { 157void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
153 MICROPROFILE_SCOPE(OpenGL_VAO); 158 MICROPROFILE_SCOPE(OpenGL_VAO);
154 UNIMPLEMENTED(); 159 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
160 const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
161
162 state.draw.vertex_array = hw_vao.handle;
163 state.draw.vertex_buffer = stream_buffer->GetHandle();
164 state.Apply();
165
166 // TODO(bunnei): Add support for 1+ vertex arrays
167 const auto& vertex_array{regs.vertex_array[0]};
168 ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?");
169 ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!");
170 for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) {
171 ASSERT_MSG(!regs.vertex_array[index].enable, "vertex array %d is unimplemented!", index);
172 }
173
174 // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
175 // Enables the first 16 vertex attributes always, as we don't know which ones are actually used
176 // until shader time. Note, Tegra technically supports 32, but we're cappinig this to 16 for now
177 // to avoid OpenGL errors.
178 for (unsigned index = 0; index < 16; ++index) {
179 auto& attrib = regs.vertex_attrib_format[index];
180 glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
181 attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride,
182 reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset));
183 glEnableVertexAttribArray(index);
184 hw_vao_enabled_attributes[index] = true;
185 }
186
187 // Copy vertex array data
188 const u32 data_size{vertex_array.stride * regs.vertex_buffer.count};
189 const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())};
190 res_cache.FlushRegion(data_addr, data_size, nullptr);
191 Memory::ReadBlock(data_addr, array_ptr, data_size);
192
193 array_ptr += data_size;
194 buffer_offset += data_size;
155} 195}
156 196
157void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) { 197void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) {
158 MICROPROFILE_SCOPE(OpenGL_VS); 198 MICROPROFILE_SCOPE(OpenGL_VS);
159 UNIMPLEMENTED(); 199 LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader.");
200 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_shader->shader.handle);
160} 201}
161 202
162void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { 203void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
163 MICROPROFILE_SCOPE(OpenGL_FS); 204 MICROPROFILE_SCOPE(OpenGL_FS);
164 ASSERT_MSG(false, "Unimplemented"); 205 UNREACHABLE();
165} 206}
166 207
167bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { 208bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
168 if (!has_ARB_separate_shader_objects) { 209 if (!has_ARB_separate_shader_objects) {
169 ASSERT_MSG(false, "Unimplemented"); 210 UNREACHABLE();
170 return false; 211 return false;
171 } 212 }
172 213
173 accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; 214 accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
174 DrawTriangles(); 215 DrawArrays();
175 216
176 return true; 217 return true;
177} 218}
178 219
179void RasterizerOpenGL::DrawTriangles() { 220void RasterizerOpenGL::DrawArrays() {
221 if (accelerate_draw == AccelDraw::Disabled)
222 return;
223
180 MICROPROFILE_SCOPE(OpenGL_Drawing); 224 MICROPROFILE_SCOPE(OpenGL_Drawing);
181 UNIMPLEMENTED(); 225 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
226
227 // TODO(bunnei): Implement these
228 const bool has_stencil = false;
229 const bool using_color_fb = true;
230 const bool using_depth_fb = false;
231 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()};
232
233 const bool write_color_fb =
234 state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
235 state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
236
237 const bool write_depth_fb =
238 (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
239 (has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0);
240
241 Surface color_surface;
242 Surface depth_surface;
243 MathUtil::Rectangle<u32> surfaces_rect;
244 std::tie(color_surface, depth_surface, surfaces_rect) =
245 res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
246
247 const u16 res_scale = color_surface != nullptr
248 ? color_surface->res_scale
249 : (depth_surface == nullptr ? 1u : depth_surface->res_scale);
250
251 MathUtil::Rectangle<u32> draw_rect{
252 static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) +
253 viewport_rect.left * res_scale,
254 surfaces_rect.left, surfaces_rect.right)), // Left
255 static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
256 viewport_rect.top * res_scale,
257 surfaces_rect.bottom, surfaces_rect.top)), // Top
258 static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) +
259 viewport_rect.right * res_scale,
260 surfaces_rect.left, surfaces_rect.right)), // Right
261 static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
262 viewport_rect.bottom * res_scale,
263 surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
264
265 // Bind the framebuffer surfaces
266 BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
267
268 // Sync the viewport
269 SyncViewport(surfaces_rect, res_scale);
270
271 // TODO(bunnei): Sync framebuffer_scale uniform here
272 // TODO(bunnei): Sync scissorbox uniform(s) here
273 // TODO(bunnei): Sync and bind the texture surfaces
274
275 // Sync and bind the shader
276 if (shader_dirty) {
277 SetShader();
278 shader_dirty = false;
279 }
280
281 // Sync the uniform data
282 if (uniform_block_data.dirty) {
283 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformData), &uniform_block_data.data);
284 uniform_block_data.dirty = false;
285 }
286
287 // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
288 // scissor test to prevent drawing outside of the framebuffer region
289 state.scissor.enabled = true;
290 state.scissor.x = draw_rect.left;
291 state.scissor.y = draw_rect.bottom;
292 state.scissor.width = draw_rect.GetWidth();
293 state.scissor.height = draw_rect.GetHeight();
294 state.Apply();
295
296 // Draw the vertex batch
297 const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
298 AnalyzeVertexArray(is_indexed);
299 state.draw.vertex_buffer = stream_buffer->GetHandle();
300 state.Apply();
301
302 size_t buffer_size = static_cast<size_t>(vs_input_size);
303 if (is_indexed) {
304 UNREACHABLE();
305 }
306 buffer_size += sizeof(VSUniformData);
307
308 size_t ptr_pos = 0;
309 u8* buffer_ptr;
310 GLintptr buffer_offset;
311 std::tie(buffer_ptr, buffer_offset) =
312 stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4);
313
314 SetupVertexArray(buffer_ptr, buffer_offset);
315 ptr_pos += vs_input_size;
316
317 GLintptr index_buffer_offset = 0;
318 if (is_indexed) {
319 UNREACHABLE();
320 }
321
322 SetupVertexShader(reinterpret_cast<VSUniformData*>(&buffer_ptr[ptr_pos]),
323 buffer_offset + static_cast<GLintptr>(ptr_pos));
324 const GLintptr vs_ubo_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
325 ptr_pos += sizeof(VSUniformData);
326
327 stream_buffer->Unmap();
328
329 const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
330 if (has_ARB_direct_state_access) {
331 glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size);
332 } else {
333 glBindBuffer(GL_COPY_WRITE_BUFFER, handle);
334 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size);
335 }
336 };
337
338 copy_buffer(vs_uniform_buffer.handle, vs_ubo_offset, sizeof(VSUniformData));
339
340 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current_shader->shader.handle);
341
342 if (is_indexed) {
343 UNREACHABLE();
344 } else {
345 glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0,
346 regs.vertex_buffer.count);
347 }
348
349 // Disable scissor test
350 state.scissor.enabled = false;
351
352 accelerate_draw = AccelDraw::Disabled;
353
354 // Unbind textures for potential future use as framebuffer attachments
355 for (auto& texture_unit : state.texture_units) {
356 texture_unit.texture_2d = 0;
357 }
358 state.Apply();
359
360 // Mark framebuffer surfaces as dirty
361 MathUtil::Rectangle<u32> draw_rect_unscaled{
362 draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale,
363 draw_rect.bottom / res_scale};
364
365 if (color_surface != nullptr && write_color_fb) {
366 auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
367 res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
368 color_surface);
369 }
370 if (depth_surface != nullptr && write_depth_fb) {
371 auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled);
372 res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
373 depth_surface);
374 }
182} 375}
183 376
184void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} 377void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
@@ -206,17 +399,17 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
206 399
207bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { 400bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
208 MICROPROFILE_SCOPE(OpenGL_Blits); 401 MICROPROFILE_SCOPE(OpenGL_Blits);
209 ASSERT_MSG(false, "Unimplemented"); 402 UNREACHABLE();
210 return true; 403 return true;
211} 404}
212 405
213bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { 406bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
214 ASSERT_MSG(false, "Unimplemented"); 407 UNREACHABLE();
215 return true; 408 return true;
216} 409}
217 410
218bool RasterizerOpenGL::AccelerateFill(const void* config) { 411bool RasterizerOpenGL::AccelerateFill(const void* config) {
219 ASSERT_MSG(false, "Unimplemented"); 412 UNREACHABLE();
220 return true; 413 return true;
221} 414}
222 415
@@ -297,14 +490,14 @@ void main() {
297 return; 490 return;
298 } 491 }
299 492
300 LOG_ERROR(HW_GPU, "Emulated shaders are not supported! Using a passthrough shader."); 493 LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader.");
301 494
302 current_shader = &test_shader; 495 current_shader = &test_shader;
303 if (has_ARB_separate_shader_objects) { 496 if (has_ARB_separate_shader_objects) {
304 test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true); 497 test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true);
305 glActiveShaderProgram(pipeline.handle, test_shader.shader.handle); 498 glActiveShaderProgram(pipeline.handle, test_shader.shader.handle);
306 } else { 499 } else {
307 ASSERT_MSG(false, "Unimplemented"); 500 UNREACHABLE();
308 } 501 }
309 502
310 state.draw.shader_program = test_shader.shader.handle; 503 state.draw.shader_program = test_shader.shader.handle;
@@ -316,34 +509,70 @@ void main() {
316 } 509 }
317} 510}
318 511
512void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
513 const Surface& depth_surface, bool has_stencil) {
514 state.draw.draw_framebuffer = framebuffer.handle;
515 state.Apply();
516
517 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
518 color_surface != nullptr ? color_surface->texture.handle : 0, 0);
519 if (depth_surface != nullptr) {
520 if (has_stencil) {
521 // attach both depth and stencil
522 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
523 depth_surface->texture.handle, 0);
524 } else {
525 // attach depth
526 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
527 depth_surface->texture.handle, 0);
528 // clear stencil attachment
529 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
530 }
531 } else {
532 // clear both depth and stencil attachment
533 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
534 0);
535 }
536}
537
538void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) {
539 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
540 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()};
541
542 state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale;
543 state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale;
544 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth() * res_scale);
545 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight() * res_scale);
546}
547
319void RasterizerOpenGL::SyncClipEnabled() { 548void RasterizerOpenGL::SyncClipEnabled() {
320 ASSERT_MSG(false, "Unimplemented"); 549 UNREACHABLE();
321} 550}
322 551
323void RasterizerOpenGL::SyncClipCoef() { 552void RasterizerOpenGL::SyncClipCoef() {
324 ASSERT_MSG(false, "Unimplemented"); 553 UNREACHABLE();
325} 554}
326 555
327void RasterizerOpenGL::SyncCullMode() { 556void RasterizerOpenGL::SyncCullMode() {
328 ASSERT_MSG(false, "Unimplemented"); 557 UNREACHABLE();
329} 558}
330 559
331void RasterizerOpenGL::SyncDepthScale() { 560void RasterizerOpenGL::SyncDepthScale() {
332 ASSERT_MSG(false, "Unimplemented"); 561 UNREACHABLE();
333} 562}
334 563
335void RasterizerOpenGL::SyncDepthOffset() { 564void RasterizerOpenGL::SyncDepthOffset() {
336 ASSERT_MSG(false, "Unimplemented"); 565 UNREACHABLE();
337} 566}
338 567
339void RasterizerOpenGL::SyncBlendEnabled() { 568void RasterizerOpenGL::SyncBlendEnabled() {
340 ASSERT_MSG(false, "Unimplemented"); 569 UNREACHABLE();
341} 570}
342 571
343void RasterizerOpenGL::SyncBlendFuncs() { 572void RasterizerOpenGL::SyncBlendFuncs() {
344 ASSERT_MSG(false, "Unimplemented"); 573 UNREACHABLE();
345} 574}
346 575
347void RasterizerOpenGL::SyncBlendColor() { 576void RasterizerOpenGL::SyncBlendColor() {
348 ASSERT_MSG(false, "Unimplemented"); 577 UNREACHABLE();
349} 578}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index b387f383b..fd53e94cd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -29,7 +29,7 @@ public:
29 RasterizerOpenGL(); 29 RasterizerOpenGL();
30 ~RasterizerOpenGL() override; 30 ~RasterizerOpenGL() override;
31 31
32 void DrawTriangles() override; 32 void DrawArrays() override;
33 void NotifyMaxwellRegisterChanged(u32 id) override; 33 void NotifyMaxwellRegisterChanged(u32 id) override;
34 void FlushAll() override; 34 void FlushAll() override;
35 void FlushRegion(VAddr addr, u64 size) override; 35 void FlushRegion(VAddr addr, u64 size) override;
@@ -87,6 +87,13 @@ public:
87private: 87private:
88 struct SamplerInfo {}; 88 struct SamplerInfo {};
89 89
90 /// Binds the framebuffer color and depth surface
91 void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
92 bool has_stencil);
93
94 /// Syncs the viewport to match the guest state
95 void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale);
96
90 /// Syncs the clip enabled status to match the guest state 97 /// Syncs the clip enabled status to match the guest state
91 void SyncClipEnabled(); 98 void SyncClipEnabled();
92 99
@@ -139,7 +146,7 @@ private:
139 OGLVertexArray hw_vao; 146 OGLVertexArray hw_vao;
140 std::array<bool, 16> hw_vao_enabled_attributes; 147 std::array<bool, 16> hw_vao_enabled_attributes;
141 148
142 std::array<SamplerInfo, 3> texture_samplers; 149 std::array<SamplerInfo, 32> texture_samplers;
143 static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024; 150 static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024;
144 std::unique_ptr<OGLStreamBuffer> vertex_buffer; 151 std::unique_ptr<OGLStreamBuffer> vertex_buffer;
145 OGLBuffer uniform_buffer; 152 OGLBuffer uniform_buffer;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 78fa7c051..2ffbd3bab 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -21,10 +21,13 @@
21#include "common/microprofile.h" 21#include "common/microprofile.h"
22#include "common/scope_exit.h" 22#include "common/scope_exit.h"
23#include "common/vector_math.h" 23#include "common/vector_math.h"
24#include "core/core.h"
24#include "core/frontend/emu_window.h" 25#include "core/frontend/emu_window.h"
26#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/vm_manager.h" 27#include "core/hle/kernel/vm_manager.h"
26#include "core/memory.h" 28#include "core/memory.h"
27#include "core/settings.h" 29#include "core/settings.h"
30#include "video_core/engines/maxwell_3d.h"
28#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 31#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
29#include "video_core/renderer_opengl/gl_state.h" 32#include "video_core/renderer_opengl/gl_state.h"
30#include "video_core/utils.h" 33#include "video_core/utils.h"
@@ -110,65 +113,26 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
110template <bool morton_to_gl, PixelFormat format> 113template <bool morton_to_gl, PixelFormat format>
111static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { 114static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
112 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; 115 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
113 constexpr u32 tile_size = bytes_per_pixel * 64;
114
115 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); 116 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
116 static_assert(gl_bytes_per_pixel >= bytes_per_pixel, "");
117 gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
118
119 const VAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
120 const VAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
121 const VAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
122
123 ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
124
125 const u64 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel;
126 u32 x = static_cast<u32>((begin_pixel_index % (stride * 8)) / 8);
127 u32 y = static_cast<u32>((begin_pixel_index / (stride * 8)) * 8);
128
129 gl_buffer += ((height - 8 - y) * stride + x) * gl_bytes_per_pixel;
130
131 auto glbuf_next_tile = [&] {
132 x = (x + 8) % stride;
133 gl_buffer += 8 * gl_bytes_per_pixel;
134 if (!x) {
135 y += 8;
136 gl_buffer -= stride * 9 * gl_bytes_per_pixel;
137 }
138 };
139
140 u8* tile_buffer = Memory::GetPointer(start);
141
142 if (start < aligned_start && !morton_to_gl) {
143 std::array<u8, tile_size> tmp_buf;
144 MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer);
145 std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start],
146 std::min(aligned_start, end) - start);
147
148 tile_buffer += aligned_start - start;
149 glbuf_next_tile();
150 }
151
152 const u8* const buffer_end = tile_buffer + aligned_end - aligned_start;
153 while (tile_buffer < buffer_end) {
154 MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer);
155 tile_buffer += tile_size;
156 glbuf_next_tile();
157 }
158 117
159 if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) { 118 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
160 std::array<u8, tile_size> tmp_buf; 119 // configuration for this and perform more generic un/swizzle
161 MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); 120 LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
162 std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end); 121 VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
163 } 122 Memory::GetPointer(base), gl_buffer, morton_to_gl);
164} 123}
165 124
166static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { 125static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = {
167 MortonCopy<true, PixelFormat::RGBA8>, // 0 126 MortonCopy<true, PixelFormat::RGBA8>,
168 MortonCopy<true, PixelFormat::RGB8>, // 1 127 nullptr,
169 MortonCopy<true, PixelFormat::RGB5A1>, // 2 128 nullptr,
170 MortonCopy<true, PixelFormat::RGB565>, // 3 129 nullptr,
171 MortonCopy<true, PixelFormat::RGBA4>, // 4 130 nullptr,
131 nullptr,
132 nullptr,
133 nullptr,
134 nullptr,
135 nullptr,
172 nullptr, 136 nullptr,
173 nullptr, 137 nullptr,
174 nullptr, 138 nullptr,
@@ -177,19 +141,19 @@ static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> mo
177 nullptr, 141 nullptr,
178 nullptr, 142 nullptr,
179 nullptr, 143 nullptr,
180 nullptr, // 5 - 13
181 MortonCopy<true, PixelFormat::D16>, // 14
182 nullptr, // 15
183 MortonCopy<true, PixelFormat::D24>, // 16
184 MortonCopy<true, PixelFormat::D24S8> // 17
185}; 144};
186 145
187static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { 146static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = {
188 MortonCopy<false, PixelFormat::RGBA8>, // 0 147 MortonCopy<false, PixelFormat::RGBA8>,
189 MortonCopy<false, PixelFormat::RGB8>, // 1 148 nullptr,
190 MortonCopy<false, PixelFormat::RGB5A1>, // 2 149 nullptr,
191 MortonCopy<false, PixelFormat::RGB565>, // 3 150 nullptr,
192 MortonCopy<false, PixelFormat::RGBA4>, // 4 151 nullptr,
152 nullptr,
153 nullptr,
154 nullptr,
155 nullptr,
156 nullptr,
193 nullptr, 157 nullptr,
194 nullptr, 158 nullptr,
195 nullptr, 159 nullptr,
@@ -198,11 +162,6 @@ static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl
198 nullptr, 162 nullptr,
199 nullptr, 163 nullptr,
200 nullptr, 164 nullptr,
201 nullptr, // 5 - 13
202 MortonCopy<false, PixelFormat::D16>, // 14
203 nullptr, // 15
204 MortonCopy<false, PixelFormat::D24>, // 16
205 MortonCopy<false, PixelFormat::D24S8> // 17
206}; 165};
207 166
208// Allocate an uninitialized texture of appropriate size and format for the surface 167// Allocate an uninitialized texture of appropriate size and format for the surface
@@ -291,8 +250,8 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
291 250
292static bool FillSurface(const Surface& surface, const u8* fill_data, 251static bool FillSurface(const Surface& surface, const u8* fill_data,
293 const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) { 252 const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
294 ASSERT_MSG(false, "Unimplemented"); 253 UNREACHABLE();
295 return true; 254 return {};
296} 255}
297 256
298SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { 257SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
@@ -531,7 +490,7 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64
531void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { 490void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
532 ASSERT(type != SurfaceType::Fill); 491 ASSERT(type != SurfaceType::Fill);
533 492
534 u8* texture_src_data = Memory::GetPointer(addr); 493 u8* const texture_src_data = Memory::GetPointer(addr);
535 if (texture_src_data == nullptr) 494 if (texture_src_data == nullptr)
536 return; 495 return;
537 496
@@ -548,11 +507,16 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
548 if (!is_tiled) { 507 if (!is_tiled) {
549 ASSERT(type == SurfaceType::Color); 508 ASSERT(type == SurfaceType::Color);
550 const u32 bytes_per_pixel{GetFormatBpp() >> 3}; 509 const u32 bytes_per_pixel{GetFormatBpp() >> 3};
510
511 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
512 // the configuration for this and perform more generic un/swizzle
513 LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
551 VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4, 514 VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
552 texture_src_data + start_offset, &gl_buffer[start_offset], 515 texture_src_data + start_offset, &gl_buffer[start_offset],
553 true); 516 true);
554 } else { 517 } else {
555 ASSERT_MSG(false, "Unimplemented"); 518 morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
519 load_start, load_end);
556 } 520 }
557} 521}
558 522
@@ -1093,18 +1057,106 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
1093} 1057}
1094 1058
1095Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { 1059Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
1096 ASSERT_MSG(false, "Unimplemented"); 1060 UNREACHABLE();
1097 return {}; 1061 return {};
1098} 1062}
1099 1063
1100SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( 1064SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
1101 bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) { 1065 bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) {
1102 UNIMPLEMENTED(); 1066 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
1103 return {}; 1067 const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
1068 const auto& config = regs.rt[0];
1069
1070 // TODO(bunnei): This is hard corded to use just the first render buffer
1071 LOG_WARNING(Render_OpenGL, "hard-coded for render target 0!");
1072
1073 // update resolution_scale_factor and reset cache if changed
1074 // TODO (bunnei): This code was ported as-is from Citra, and is technically not thread-safe. We
1075 // need to fix this before making the renderer multi-threaded.
1076 static u16 resolution_scale_factor = GetResolutionScaleFactor();
1077 if (resolution_scale_factor != GetResolutionScaleFactor()) {
1078 resolution_scale_factor = GetResolutionScaleFactor();
1079 FlushAll();
1080 while (!surface_cache.empty())
1081 UnregisterSurface(*surface_cache.begin()->second.begin());
1082 }
1083
1084 MathUtil::Rectangle<u32> viewport_clamped{
1085 static_cast<u32>(MathUtil::Clamp(viewport.left, 0, static_cast<s32>(config.width))),
1086 static_cast<u32>(MathUtil::Clamp(viewport.top, 0, static_cast<s32>(config.height))),
1087 static_cast<u32>(MathUtil::Clamp(viewport.right, 0, static_cast<s32>(config.width))),
1088 static_cast<u32>(MathUtil::Clamp(viewport.bottom, 0, static_cast<s32>(config.height)))};
1089
1090 // get color and depth surfaces
1091 SurfaceParams color_params;
1092 color_params.is_tiled = true;
1093 color_params.res_scale = resolution_scale_factor;
1094 color_params.width = config.width;
1095 color_params.height = config.height;
1096 SurfaceParams depth_params = color_params;
1097
1098 color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address());
1099 color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format);
1100 color_params.UpdateParams();
1101
1102 ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented");
1103 // depth_params.addr = config.GetDepthBufferPhysicalAddress();
1104 // depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(config.depth_format);
1105 // depth_params.UpdateParams();
1106
1107 auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped);
1108 auto depth_vp_interval = depth_params.GetSubRectInterval(viewport_clamped);
1109
1110 // Make sure that framebuffers don't overlap if both color and depth are being used
1111 if (using_color_fb && using_depth_fb &&
1112 boost::icl::length(color_vp_interval & depth_vp_interval)) {
1113 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
1114 "overlapping framebuffers not supported!");
1115 using_depth_fb = false;
1116 }
1117
1118 MathUtil::Rectangle<u32> color_rect{};
1119 Surface color_surface = nullptr;
1120 if (using_color_fb)
1121 std::tie(color_surface, color_rect) =
1122 GetSurfaceSubRect(color_params, ScaleMatch::Exact, false);
1123
1124 MathUtil::Rectangle<u32> depth_rect{};
1125 Surface depth_surface = nullptr;
1126 if (using_depth_fb)
1127 std::tie(depth_surface, depth_rect) =
1128 GetSurfaceSubRect(depth_params, ScaleMatch::Exact, false);
1129
1130 MathUtil::Rectangle<u32> fb_rect{};
1131 if (color_surface != nullptr && depth_surface != nullptr) {
1132 fb_rect = color_rect;
1133 // Color and Depth surfaces must have the same dimensions and offsets
1134 if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top ||
1135 color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) {
1136 color_surface = GetSurface(color_params, ScaleMatch::Exact, false);
1137 depth_surface = GetSurface(depth_params, ScaleMatch::Exact, false);
1138 fb_rect = color_surface->GetScaledRect();
1139 }
1140 } else if (color_surface != nullptr) {
1141 fb_rect = color_rect;
1142 } else if (depth_surface != nullptr) {
1143 fb_rect = depth_rect;
1144 }
1145
1146 if (color_surface != nullptr) {
1147 ValidateSurface(color_surface, boost::icl::first(color_vp_interval),
1148 boost::icl::length(color_vp_interval));
1149 }
1150 if (depth_surface != nullptr) {
1151 ValidateSurface(depth_surface, boost::icl::first(depth_vp_interval),
1152 boost::icl::length(depth_vp_interval));
1153 }
1154
1155 return std::make_tuple(color_surface, depth_surface, fb_rect);
1104} 1156}
1105 1157
1106Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { 1158Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) {
1107 ASSERT_MSG(false, "Unimplemented"); 1159 UNREACHABLE();
1108 return {}; 1160 return {};
1109} 1161}
1110 1162
@@ -1348,5 +1400,33 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
1348} 1400}
1349 1401
1350void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 1402void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
1351 // ASSERT_MSG(false, "Unimplemented"); 1403 const u64 num_pages =
1404 ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1;
1405 const u64 page_start = addr >> Memory::PAGE_BITS;
1406 const u64 page_end = page_start + num_pages;
1407
1408 // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
1409 // subtract after iterating
1410 const auto pages_interval = PageMap::interval_type::right_open(page_start, page_end);
1411 if (delta > 0)
1412 cached_pages.add({pages_interval, delta});
1413
1414 for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
1415 const auto interval = pair.first & pages_interval;
1416 const int count = pair.second;
1417
1418 const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS;
1419 const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS;
1420 const u64 interval_size = interval_end_addr - interval_start_addr;
1421
1422 if (delta > 0 && count == delta)
1423 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
1424 else if (delta < 0 && count == -delta)
1425 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
1426 else
1427 ASSERT(count >= 0);
1428 }
1429
1430 if (delta < 0)
1431 cached_pages.add({pages_interval, delta});
1352} 1432}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 14f3cdc38..1f660d30c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -41,7 +41,7 @@ static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval
41using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; 41using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>;
42using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; 42using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
43 43
44using PageMap = boost::icl::interval_map<u32, int>; 44using PageMap = boost::icl::interval_map<u64, int>;
45 45
46enum class ScaleMatch { 46enum class ScaleMatch {
47 Exact, // only accept same res scale 47 Exact, // only accept same res scale
@@ -116,6 +116,15 @@ struct SurfaceParams {
116 return GetFormatBpp(pixel_format); 116 return GetFormatBpp(pixel_format);
117 } 117 }
118 118
119 static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
120 switch (format) {
121 case Tegra::RenderTargetFormat::RGBA8_UNORM:
122 return PixelFormat::RGBA8;
123 default:
124 UNREACHABLE();
125 }
126 }
127
119 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 128 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
120 switch (format) { 129 switch (format) {
121 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 130 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
@@ -308,7 +317,7 @@ public:
308 317
309 /// Get the color and depth surfaces based on the framebuffer configuration 318 /// Get the color and depth surfaces based on the framebuffer configuration
310 SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, 319 SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
311 const MathUtil::Rectangle<s32>& viewport_rect); 320 const MathUtil::Rectangle<s32>& viewport);
312 321
313 /// Get a surface that matches the fill config 322 /// Get a surface that matches the fill config
314 Surface GetFillSurface(const void* config); 323 Surface GetFillSurface(const void* config);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 0e0ef18cc..564ea8f9e 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -26,7 +26,7 @@ public:
26 sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {} 26 sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {}
27 27
28 std::string Decompile() { 28 std::string Decompile() {
29 UNIMPLEMENTED(); 29 UNREACHABLE();
30 return {}; 30 return {};
31 } 31 }
32 32
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index f242bce1d..8f3c98800 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -8,12 +8,12 @@
8namespace GLShader { 8namespace GLShader {
9 9
10std::string GenerateVertexShader(const MaxwellVSConfig& config) { 10std::string GenerateVertexShader(const MaxwellVSConfig& config) {
11 UNIMPLEMENTED(); 11 UNREACHABLE();
12 return {}; 12 return {};
13} 13}
14 14
15std::string GenerateFragmentShader(const MaxwellFSConfig& config) { 15std::string GenerateFragmentShader(const MaxwellFSConfig& config) {
16 UNIMPLEMENTED(); 16 UNREACHABLE();
17 return {}; 17 return {};
18} 18}
19 19
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index a3ba16761..a6c6204d5 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -38,8 +38,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
38 if (result == GL_TRUE) { 38 if (result == GL_TRUE) {
39 LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]); 39 LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
40 } else { 40 } else {
41 LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", 41 LOG_CRITICAL(Render_OpenGL, "Error compiling vertex shader:\n%s",
42 &vertex_shader_error[0]); 42 &vertex_shader_error[0]);
43 } 43 }
44 } 44 }
45 } 45 }
@@ -62,8 +62,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
62 if (result == GL_TRUE) { 62 if (result == GL_TRUE) {
63 LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]); 63 LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]);
64 } else { 64 } else {
65 LOG_ERROR(Render_OpenGL, "Error compiling geometry shader:\n%s", 65 LOG_CRITICAL(Render_OpenGL, "Error compiling geometry shader:\n%s",
66 &geometry_shader_error[0]); 66 &geometry_shader_error[0]);
67 } 67 }
68 } 68 }
69 } 69 }
@@ -86,8 +86,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
86 if (result == GL_TRUE) { 86 if (result == GL_TRUE) {
87 LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); 87 LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
88 } else { 88 } else {
89 LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", 89 LOG_CRITICAL(Render_OpenGL, "Error compiling fragment shader:\n%s",
90 &fragment_shader_error[0]); 90 &fragment_shader_error[0]);
91 } 91 }
92 } 92 }
93 } 93 }
@@ -128,20 +128,20 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
128 if (result == GL_TRUE) { 128 if (result == GL_TRUE) {
129 LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]); 129 LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]);
130 } else { 130 } else {
131 LOG_ERROR(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]); 131 LOG_CRITICAL(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]);
132 } 132 }
133 } 133 }
134 134
135 // If the program linking failed at least one of the shaders was probably bad 135 // If the program linking failed at least one of the shaders was probably bad
136 if (result == GL_FALSE) { 136 if (result == GL_FALSE) {
137 if (vertex_shader) { 137 if (vertex_shader) {
138 LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader); 138 LOG_CRITICAL(Render_OpenGL, "Vertex shader:\n%s", vertex_shader);
139 } 139 }
140 if (geometry_shader) { 140 if (geometry_shader) {
141 LOG_ERROR(Render_OpenGL, "Geometry shader:\n%s", geometry_shader); 141 LOG_CRITICAL(Render_OpenGL, "Geometry shader:\n%s", geometry_shader);
142 } 142 }
143 if (fragment_shader) { 143 if (fragment_shader) {
144 LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader); 144 LOG_CRITICAL(Render_OpenGL, "Fragment shader:\n%s", fragment_shader);
145 } 145 }
146 } 146 }
147 ASSERT_MSG(result == GL_TRUE, "Shader not linked"); 147 ASSERT_MSG(result == GL_TRUE, "Shader not linked");
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 940575dfa..c1f4efc8c 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -85,7 +85,7 @@ public:
85 struct { 85 struct {
86 GLuint texture_2d; // GL_TEXTURE_BINDING_2D 86 GLuint texture_2d; // GL_TEXTURE_BINDING_2D
87 GLuint sampler; // GL_SAMPLER_BINDING 87 GLuint sampler; // GL_SAMPLER_BINDING
88 } texture_units[3]; 88 } texture_units[32];
89 89
90 struct { 90 struct {
91 GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER 91 GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
new file mode 100644
index 000000000..d847317ac
--- /dev/null
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -0,0 +1,50 @@
1// Copyright 2018 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 <array>
8#include <glad/glad.h>
9#include "common/common_types.h"
10#include "common/logging/log.h"
11#include "video_core/engines/maxwell_3d.h"
12
13namespace MaxwellToGL {
14
15using Maxwell = Tegra::Engines::Maxwell3D::Regs;
16
17inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
18 switch (attrib.type) {
19 case Maxwell::VertexAttribute::Type::UnsignedNorm: {
20
21 switch (attrib.size) {
22 case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
23 return GL_UNSIGNED_BYTE;
24 }
25
26 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str());
27 UNREACHABLE();
28 return {};
29 }
30
31 case Maxwell::VertexAttribute::Type::Float:
32 return GL_FLOAT;
33 }
34
35 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str());
36 UNREACHABLE();
37 return {};
38}
39
40inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
41 switch (topology) {
42 case Maxwell::PrimitiveTopology::TriangleStrip:
43 return GL_TRIANGLE_STRIP;
44 }
45 LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology);
46 UNREACHABLE();
47 return {};
48}
49
50} // namespace MaxwellToGL
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 1a24855d7..78b50b227 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -100,6 +100,8 @@ RendererOpenGL::~RendererOpenGL() = default;
100 100
101/// Swap buffers (render frame) 101/// Swap buffers (render frame)
102void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { 102void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
103 Core::System::GetInstance().perf_stats.EndSystemFrame();
104
103 // Maintain the rasterizer's state as a priority 105 // Maintain the rasterizer's state as a priority
104 OpenGLState prev_state = OpenGLState::GetCurState(); 106 OpenGLState prev_state = OpenGLState::GetCurState();
105 state.Apply(); 107 state.Apply();
@@ -114,20 +116,19 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
114 // performance problem. 116 // performance problem.
115 ConfigureFramebufferTexture(screen_info.texture, *framebuffer); 117 ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
116 } 118 }
119
120 // Load the framebuffer from memory, draw it to the screen, and swap buffers
117 LoadFBToScreenInfo(*framebuffer, screen_info); 121 LoadFBToScreenInfo(*framebuffer, screen_info);
122 DrawScreen();
123 render_window->SwapBuffers();
118 } 124 }
119 125
120 DrawScreens();
121
122 Core::System::GetInstance().perf_stats.EndSystemFrame();
123
124 // Swap buffers
125 render_window->PollEvents(); 126 render_window->PollEvents();
126 render_window->SwapBuffers();
127 127
128 Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); 128 Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs());
129 Core::System::GetInstance().perf_stats.BeginSystemFrame(); 129 Core::System::GetInstance().perf_stats.BeginSystemFrame();
130 130
131 // Restore the rasterizer state
131 prev_state.Apply(); 132 prev_state.Apply();
132 RefreshRasterizerSetting(); 133 RefreshRasterizerSetting();
133} 134}
@@ -141,11 +142,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
141 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; 142 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
142 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; 143 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
143 144
144 // TODO(bunnei): The framebuffer region should only be invalidated if it is written to, not
145 // every frame. When we find the right place for this, the below line can be removed.
146 Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes,
147 Memory::FlushMode::Invalidate);
148
149 // Framebuffer orientation handling 145 // Framebuffer orientation handling
150 framebuffer_transform_flags = framebuffer.transform_flags; 146 framebuffer_transform_flags = framebuffer.transform_flags;
151 147
@@ -283,7 +279,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
283 gl_framebuffer_data.resize(texture.width * texture.height * 4); 279 gl_framebuffer_data.resize(texture.width * texture.height * 4);
284 break; 280 break;
285 default: 281 default:
286 UNIMPLEMENTED(); 282 UNREACHABLE();
287 } 283 }
288 284
289 state.texture_units[0].texture_2d = texture.resource.handle; 285 state.texture_units[0].texture_2d = texture.resource.handle;
@@ -297,8 +293,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
297 state.Apply(); 293 state.Apply();
298} 294}
299 295
300void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, 296void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w,
301 float h) { 297 float h) {
302 const auto& texcoords = screen_info.display_texcoords; 298 const auto& texcoords = screen_info.display_texcoords;
303 auto left = texcoords.left; 299 auto left = texcoords.left;
304 auto right = texcoords.right; 300 auto right = texcoords.right;
@@ -309,7 +305,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
309 right = texcoords.left; 305 right = texcoords.left;
310 } else { 306 } else {
311 // Other transformations are unsupported 307 // Other transformations are unsupported
312 LOG_CRITICAL(HW_GPU, "unsupported framebuffer_transform_flags=%d", 308 LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags=%d",
313 framebuffer_transform_flags); 309 framebuffer_transform_flags);
314 UNIMPLEMENTED(); 310 UNIMPLEMENTED();
315 } 311 }
@@ -334,7 +330,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
334/** 330/**
335 * Draws the emulated screens to the emulator window. 331 * Draws the emulated screens to the emulator window.
336 */ 332 */
337void RendererOpenGL::DrawScreens() { 333void RendererOpenGL::DrawScreen() {
338 const auto& layout = render_window->GetFramebufferLayout(); 334 const auto& layout = render_window->GetFramebufferLayout();
339 const auto& screen = layout.screen; 335 const auto& screen = layout.screen;
340 336
@@ -350,8 +346,8 @@ void RendererOpenGL::DrawScreens() {
350 glActiveTexture(GL_TEXTURE0); 346 glActiveTexture(GL_TEXTURE0);
351 glUniform1i(uniform_color_texture, 0); 347 glUniform1i(uniform_color_texture, 0);
352 348
353 DrawSingleScreen(screen_info, (float)screen.left, (float)screen.top, (float)screen.GetWidth(), 349 DrawScreenTriangles(screen_info, (float)screen.left, (float)screen.top,
354 (float)screen.GetHeight()); 350 (float)screen.GetWidth(), (float)screen.GetHeight());
355 351
356 m_current_frame++; 352 m_current_frame++;
357} 353}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 29516baf4..fffd0f9f4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -55,8 +55,8 @@ private:
55 void InitOpenGLObjects(); 55 void InitOpenGLObjects();
56 void ConfigureFramebufferTexture(TextureInfo& texture, 56 void ConfigureFramebufferTexture(TextureInfo& texture,
57 const Tegra::FramebufferConfig& framebuffer); 57 const Tegra::FramebufferConfig& framebuffer);
58 void DrawScreens(); 58 void DrawScreen();
59 void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); 59 void DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, float h);
60 void UpdateFramerate(); 60 void UpdateFramerate();
61 61
62 // Loads framebuffer from emulated memory into the display information structure 62 // Loads framebuffer from emulated memory into the display information structure
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 864691baa..289140f31 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -26,7 +26,7 @@ bool Init(EmuWindow* emu_window) {
26 if (g_renderer->Init()) { 26 if (g_renderer->Init()) {
27 LOG_DEBUG(Render, "initialized OK"); 27 LOG_DEBUG(Render, "initialized OK");
28 } else { 28 } else {
29 LOG_ERROR(Render, "initialization failed !"); 29 LOG_CRITICAL(Render, "initialization failed !");
30 return false; 30 return false;
31 } 31 }
32 return true; 32 return true;