summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
authorGravatar Emmanuel Gil Peyrot2016-09-18 09:38:01 +0900
committerGravatar Emmanuel Gil Peyrot2016-09-18 09:38:01 +0900
commitdc8479928c5aee4c6ad6fe4f59006fb604cee701 (patch)
tree569a7f13128450bbab973236615587ff00bced5f /src/video_core/renderer_opengl
parentTravis: Import Dolphin’s clang-format hook. (diff)
downloadyuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.gz
yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.xz
yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.zip
Sources: Run clang-format on everything.
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp234
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h50
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp285
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h78
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h114
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp213
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp49
-rw-r--r--src/video_core/renderer_opengl/gl_state.h40
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h72
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp122
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h15
12 files changed, 789 insertions, 486 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f8393c618..5021f48bc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -32,8 +32,7 @@ static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
32 stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && 32 stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
33 stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && 33 stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
34 stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && 34 stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
35 stage.GetColorMultiplier() == 1 && 35 stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
36 stage.GetAlphaMultiplier() == 1);
37} 36}
38 37
39RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { 38RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
@@ -65,26 +64,34 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
65 uniform_block_data.fog_lut_dirty = true; 64 uniform_block_data.fog_lut_dirty = true;
66 65
67 // Set vertex attributes 66 // Set vertex attributes
68 glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); 67 glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE,
68 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
69 glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); 69 glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
70 70
71 glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); 71 glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex),
72 (GLvoid*)offsetof(HardwareVertex, color));
72 glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); 73 glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR);
73 74
74 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); 75 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE,
75 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); 76 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
76 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); 77 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE,
78 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
79 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE,
80 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
77 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); 81 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0);
78 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); 82 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
79 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); 83 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
80 84
81 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w)); 85 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE,
86 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w));
82 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W); 87 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W);
83 88
84 glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat)); 89 glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE,
90 sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat));
85 glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT); 91 glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT);
86 92
87 glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, view)); 93 glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex),
94 (GLvoid*)offsetof(HardwareVertex, view));
88 glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW); 95 glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW);
89 96
90 // Create render framebuffer 97 // Create render framebuffer
@@ -130,7 +137,6 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
130} 137}
131 138
132RasterizerOpenGL::~RasterizerOpenGL() { 139RasterizerOpenGL::~RasterizerOpenGL() {
133
134} 140}
135 141
136/** 142/**
@@ -149,8 +155,8 @@ RasterizerOpenGL::~RasterizerOpenGL() {
149 * manually using two Lerps, and doing this correction before each Lerp. 155 * manually using two Lerps, and doing this correction before each Lerp.
150 */ 156 */
151static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) { 157static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
152 Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() }; 158 Math::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()};
153 Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() }; 159 Math::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()};
154 160
155 return (Math::Dot(a, b) < 0.f); 161 return (Math::Dot(a, b) < 0.f);
156} 162}
@@ -173,15 +179,20 @@ void RasterizerOpenGL::DrawTriangles() {
173 CachedSurface* color_surface; 179 CachedSurface* color_surface;
174 CachedSurface* depth_surface; 180 CachedSurface* depth_surface;
175 MathUtil::Rectangle<int> rect; 181 MathUtil::Rectangle<int> rect;
176 std::tie(color_surface, depth_surface, rect) = res_cache.GetFramebufferSurfaces(regs.framebuffer); 182 std::tie(color_surface, depth_surface, rect) =
183 res_cache.GetFramebufferSurfaces(regs.framebuffer);
177 184
178 state.draw.draw_framebuffer = framebuffer.handle; 185 state.draw.draw_framebuffer = framebuffer.handle;
179 state.Apply(); 186 state.Apply();
180 187
181 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_surface != nullptr ? color_surface->texture.handle : 0, 0); 188 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
182 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); 189 color_surface != nullptr ? color_surface->texture.handle : 0, 0);
190 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
191 depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
183 bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 192 bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
184 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); 193 glFramebufferTexture2D(
194 GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
195 (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
185 196
186 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 197 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
187 return; 198 return;
@@ -194,7 +205,8 @@ void RasterizerOpenGL::DrawTriangles() {
194 205
195 glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), 206 glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width),
196 (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), 207 (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height),
197 (GLsizei)(viewport_width * color_surface->res_scale_width), (GLsizei)(viewport_height * color_surface->res_scale_height)); 208 (GLsizei)(viewport_width * color_surface->res_scale_width),
209 (GLsizei)(viewport_height * color_surface->res_scale_height));
198 210
199 if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || 211 if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width ||
200 uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { 212 uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) {
@@ -245,14 +257,16 @@ void RasterizerOpenGL::DrawTriangles() {
245 257
246 // Sync the uniform data 258 // Sync the uniform data
247 if (uniform_block_data.dirty) { 259 if (uniform_block_data.dirty) {
248 glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); 260 glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data,
261 GL_STATIC_DRAW);
249 uniform_block_data.dirty = false; 262 uniform_block_data.dirty = false;
250 } 263 }
251 264
252 state.Apply(); 265 state.Apply();
253 266
254 // Draw the vertex batch 267 // Draw the vertex batch
255 glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); 268 glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(),
269 GL_STREAM_DRAW);
256 glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); 270 glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
257 271
258 // Mark framebuffer surfaces as dirty 272 // Mark framebuffer surfaces as dirty
@@ -278,7 +292,7 @@ void RasterizerOpenGL::DrawTriangles() {
278void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { 292void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
279 const auto& regs = Pica::g_state.regs; 293 const auto& regs = Pica::g_state.regs;
280 294
281 switch(id) { 295 switch (id) {
282 // Culling 296 // Culling
283 case PICA_REG_INDEX(cull_mode): 297 case PICA_REG_INDEX(cull_mode):
284 SyncCullMode(); 298 SyncCullMode();
@@ -548,7 +562,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
548 SyncLightAmbient(7); 562 SyncLightAmbient(7);
549 break; 563 break;
550 564
551 // Fragment lighting position 565 // Fragment lighting position
552 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10): 566 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10):
553 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10): 567 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10):
554 SyncLightPosition(0); 568 SyncLightPosition(0);
@@ -659,13 +673,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
659 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc): 673 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc):
660 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd): 674 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd):
661 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): 675 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce):
662 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): 676 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): {
663 {
664 auto& lut_config = regs.lighting.lut_config; 677 auto& lut_config = regs.lighting.lut_config;
665 uniform_block_data.lut_dirty[lut_config.type / 4] = true; 678 uniform_block_data.lut_dirty[lut_config.type / 4] = true;
666 break; 679 break;
667 } 680 }
668
669 } 681 }
670} 682}
671 683
@@ -699,8 +711,10 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
699 711
700 CachedSurface dst_params; 712 CachedSurface dst_params;
701 dst_params.addr = config.GetPhysicalOutputAddress(); 713 dst_params.addr = config.GetPhysicalOutputAddress();
702 dst_params.width = config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value(); 714 dst_params.width =
703 dst_params.height = config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value(); 715 config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value();
716 dst_params.height =
717 config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value();
704 dst_params.is_tiled = config.input_linear != config.dont_swizzle; 718 dst_params.is_tiled = config.input_linear != config.dont_swizzle;
705 dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format); 719 dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format);
706 720
@@ -735,7 +749,8 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
735 return false; 749 return false;
736 } 750 }
737 751
738 u32 dst_size = dst_params.width * dst_params.height * CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8; 752 u32 dst_size = dst_params.width * dst_params.height *
753 CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8;
739 dst_surface->dirty = true; 754 dst_surface->dirty = true;
740 res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true); 755 res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true);
741 return true; 756 return true;
@@ -757,12 +772,15 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
757 772
758 GLuint old_fb = cur_state.draw.draw_framebuffer; 773 GLuint old_fb = cur_state.draw.draw_framebuffer;
759 cur_state.draw.draw_framebuffer = framebuffer.handle; 774 cur_state.draw.draw_framebuffer = framebuffer.handle;
760 // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so Clear call isn't affected 775 // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so
776 // Clear call isn't affected
761 cur_state.Apply(); 777 cur_state.Apply();
762 778
763 if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) { 779 if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) {
764 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_surface->texture.handle, 0); 780 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
765 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 781 dst_surface->texture.handle, 0);
782 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
783 0);
766 784
767 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 785 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
768 return false; 786 return false;
@@ -770,8 +788,10 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
770 788
771 GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f}; 789 GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
772 790
773 // TODO: Handle additional pixel format and fill value size combinations to accelerate more cases 791 // TODO: Handle additional pixel format and fill value size combinations to accelerate more
774 // For instance, checking if fill value's bytes/bits repeat to allow filling I8/A8/I4/A4/... 792 // cases
793 // For instance, checking if fill value's bytes/bits repeat to allow filling
794 // I8/A8/I4/A4/...
775 // Currently only handles formats that are multiples of the fill value size 795 // Currently only handles formats that are multiples of the fill value size
776 796
777 if (config.fill_24bit) { 797 if (config.fill_24bit) {
@@ -846,7 +866,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
846 glClearBufferfv(GL_COLOR, 0, color_values); 866 glClearBufferfv(GL_COLOR, 0, color_values);
847 } else if (dst_type == SurfaceType::Depth) { 867 } else if (dst_type == SurfaceType::Depth) {
848 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 868 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
849 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); 869 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
870 dst_surface->texture.handle, 0);
850 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 871 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
851 872
852 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 873 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
@@ -865,7 +886,8 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
865 glClearBufferfv(GL_DEPTH, 0, &value_float); 886 glClearBufferfv(GL_DEPTH, 0, &value_float);
866 } else if (dst_type == SurfaceType::DepthStencil) { 887 } else if (dst_type == SurfaceType::DepthStencil) {
867 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 888 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
868 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); 889 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
890 dst_surface->texture.handle, 0);
869 891
870 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 892 if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
871 return false; 893 return false;
@@ -889,7 +911,9 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
889 return true; 911 return true;
890} 912}
891 913
892bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { 914bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config,
915 PAddr framebuffer_addr, u32 pixel_stride,
916 ScreenInfo& screen_info) {
893 if (framebuffer_addr == 0) { 917 if (framebuffer_addr == 0) {
894 return false; 918 return false;
895 } 919 }
@@ -912,10 +936,9 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
912 u32 scaled_width = src_surface->GetScaledWidth(); 936 u32 scaled_width = src_surface->GetScaledWidth();
913 u32 scaled_height = src_surface->GetScaledHeight(); 937 u32 scaled_height = src_surface->GetScaledHeight();
914 938
915 screen_info.display_texcoords = MathUtil::Rectangle<float>((float)src_rect.top / (float)scaled_height, 939 screen_info.display_texcoords = MathUtil::Rectangle<float>(
916 (float)src_rect.left / (float)scaled_width, 940 (float)src_rect.top / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
917 (float)src_rect.bottom / (float)scaled_height, 941 (float)src_rect.bottom / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
918 (float)src_rect.right / (float)scaled_width);
919 942
920 screen_info.display_texture = src_surface->texture.handle; 943 screen_info.display_texture = src_surface->texture.handle;
921 944
@@ -928,7 +951,8 @@ void RasterizerOpenGL::SamplerInfo::Create() {
928 wrap_s = wrap_t = TextureConfig::Repeat; 951 wrap_s = wrap_t = TextureConfig::Repeat;
929 border_color = 0; 952 border_color = 0;
930 953
931 glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR 954 glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER,
955 GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR
932 // Other attributes have correct defaults 956 // Other attributes have correct defaults
933} 957}
934 958
@@ -976,41 +1000,64 @@ void RasterizerOpenGL::SetShader() {
976 } else { 1000 } else {
977 LOG_DEBUG(Render_OpenGL, "Creating new shader"); 1001 LOG_DEBUG(Render_OpenGL, "Creating new shader");
978 1002
979 shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); 1003 shader->shader.Create(GLShader::GenerateVertexShader().c_str(),
1004 GLShader::GenerateFragmentShader(config).c_str());
980 1005
981 state.draw.shader_program = shader->shader.handle; 1006 state.draw.shader_program = shader->shader.handle;
982 state.Apply(); 1007 state.Apply();
983 1008
984 // Set the texture samplers to correspond to different texture units 1009 // Set the texture samplers to correspond to different texture units
985 GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); 1010 GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]");
986 if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); } 1011 if (uniform_tex != -1) {
1012 glUniform1i(uniform_tex, 0);
1013 }
987 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); 1014 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]");
988 if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); } 1015 if (uniform_tex != -1) {
1016 glUniform1i(uniform_tex, 1);
1017 }
989 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); 1018 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
990 if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } 1019 if (uniform_tex != -1) {
1020 glUniform1i(uniform_tex, 2);
1021 }
991 1022
992 // Set the texture samplers to correspond to different lookup table texture units 1023 // Set the texture samplers to correspond to different lookup table texture units
993 GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); 1024 GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]");
994 if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); } 1025 if (uniform_lut != -1) {
1026 glUniform1i(uniform_lut, 3);
1027 }
995 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); 1028 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]");
996 if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); } 1029 if (uniform_lut != -1) {
1030 glUniform1i(uniform_lut, 4);
1031 }
997 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); 1032 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]");
998 if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); } 1033 if (uniform_lut != -1) {
1034 glUniform1i(uniform_lut, 5);
1035 }
999 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); 1036 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]");
1000 if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); } 1037 if (uniform_lut != -1) {
1038 glUniform1i(uniform_lut, 6);
1039 }
1001 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); 1040 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]");
1002 if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); } 1041 if (uniform_lut != -1) {
1042 glUniform1i(uniform_lut, 7);
1043 }
1003 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); 1044 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]");
1004 if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); } 1045 if (uniform_lut != -1) {
1046 glUniform1i(uniform_lut, 8);
1047 }
1005 1048
1006 GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); 1049 GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut");
1007 if (uniform_fog_lut != -1) { glUniform1i(uniform_fog_lut, 9); } 1050 if (uniform_fog_lut != -1) {
1051 glUniform1i(uniform_fog_lut, 9);
1052 }
1008 1053
1009 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); 1054 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
1010 1055
1011 unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); 1056 unsigned int block_index =
1057 glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
1012 GLint block_size; 1058 GLint block_size;
1013 glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); 1059 glGetActiveUniformBlockiv(current_shader->shader.handle, block_index,
1060 GL_UNIFORM_BLOCK_DATA_SIZE, &block_size);
1014 ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!"); 1061 ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!");
1015 glUniformBlockBinding(current_shader->shader.handle, block_index, 0); 1062 glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
1016 1063
@@ -1073,7 +1120,8 @@ void RasterizerOpenGL::SyncDepthScale() {
1073} 1120}
1074 1121
1075void RasterizerOpenGL::SyncDepthOffset() { 1122void RasterizerOpenGL::SyncDepthOffset() {
1076 float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); 1123 float depth_offset =
1124 Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32();
1077 if (depth_offset != uniform_block_data.data.depth_offset) { 1125 if (depth_offset != uniform_block_data.data.depth_offset) {
1078 uniform_block_data.data.depth_offset = depth_offset; 1126 uniform_block_data.data.depth_offset = depth_offset;
1079 uniform_block_data.dirty = true; 1127 uniform_block_data.dirty = true;
@@ -1086,10 +1134,14 @@ void RasterizerOpenGL::SyncBlendEnabled() {
1086 1134
1087void RasterizerOpenGL::SyncBlendFuncs() { 1135void RasterizerOpenGL::SyncBlendFuncs() {
1088 const auto& regs = Pica::g_state.regs; 1136 const auto& regs = Pica::g_state.regs;
1089 state.blend.rgb_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); 1137 state.blend.rgb_equation =
1090 state.blend.a_equation = PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); 1138 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb);
1091 state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); 1139 state.blend.a_equation =
1092 state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); 1140 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a);
1141 state.blend.src_rgb_func =
1142 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
1143 state.blend.dst_rgb_func =
1144 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
1093 state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); 1145 state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
1094 state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); 1146 state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
1095} 1147}
@@ -1104,25 +1156,23 @@ void RasterizerOpenGL::SyncBlendColor() {
1104 1156
1105void RasterizerOpenGL::SyncFogColor() { 1157void RasterizerOpenGL::SyncFogColor() {
1106 const auto& regs = Pica::g_state.regs; 1158 const auto& regs = Pica::g_state.regs;
1107 uniform_block_data.data.fog_color = { 1159 uniform_block_data.data.fog_color = {regs.fog_color.r.Value() / 255.0f,
1108 regs.fog_color.r.Value() / 255.0f, 1160 regs.fog_color.g.Value() / 255.0f,
1109 regs.fog_color.g.Value() / 255.0f, 1161 regs.fog_color.b.Value() / 255.0f};
1110 regs.fog_color.b.Value() / 255.0f
1111 };
1112 uniform_block_data.dirty = true; 1162 uniform_block_data.dirty = true;
1113} 1163}
1114 1164
1115void RasterizerOpenGL::SyncFogLUT() { 1165void RasterizerOpenGL::SyncFogLUT() {
1116 std::array<GLuint, 128> new_data; 1166 std::array<GLuint, 128> new_data;
1117 1167
1118 std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), [](const auto& entry) { 1168 std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(),
1119 return entry.raw; 1169 [](const auto& entry) { return entry.raw; });
1120 });
1121 1170
1122 if (new_data != fog_lut_data) { 1171 if (new_data != fog_lut_data) {
1123 fog_lut_data = new_data; 1172 fog_lut_data = new_data;
1124 glActiveTexture(GL_TEXTURE9); 1173 glActiveTexture(GL_TEXTURE9);
1125 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, fog_lut_data.data()); 1174 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT,
1175 fog_lut_data.data());
1126 } 1176 }
1127} 1177}
1128 1178
@@ -1154,34 +1204,40 @@ void RasterizerOpenGL::SyncColorWriteMask() {
1154void RasterizerOpenGL::SyncStencilWriteMask() { 1204void RasterizerOpenGL::SyncStencilWriteMask() {
1155 const auto& regs = Pica::g_state.regs; 1205 const auto& regs = Pica::g_state.regs;
1156 state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) 1206 state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0)
1157 ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) 1207 ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
1158 : 0; 1208 : 0;
1159} 1209}
1160 1210
1161void RasterizerOpenGL::SyncDepthWriteMask() { 1211void RasterizerOpenGL::SyncDepthWriteMask() {
1162 const auto& regs = Pica::g_state.regs; 1212 const auto& regs = Pica::g_state.regs;
1163 state.depth.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) 1213 state.depth.write_mask =
1164 ? GL_TRUE 1214 (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
1165 : GL_FALSE; 1215 ? GL_TRUE
1216 : GL_FALSE;
1166} 1217}
1167 1218
1168void RasterizerOpenGL::SyncStencilTest() { 1219void RasterizerOpenGL::SyncStencilTest() {
1169 const auto& regs = Pica::g_state.regs; 1220 const auto& regs = Pica::g_state.regs;
1170 state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 1221 state.stencil.test_enabled = regs.output_merger.stencil_test.enable &&
1222 regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
1171 state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); 1223 state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
1172 state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; 1224 state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
1173 state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; 1225 state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
1174 state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); 1226 state.stencil.action_stencil_fail =
1175 state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); 1227 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail);
1176 state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); 1228 state.stencil.action_depth_fail =
1229 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail);
1230 state.stencil.action_depth_pass =
1231 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass);
1177} 1232}
1178 1233
1179void RasterizerOpenGL::SyncDepthTest() { 1234void RasterizerOpenGL::SyncDepthTest() {
1180 const auto& regs = Pica::g_state.regs; 1235 const auto& regs = Pica::g_state.regs;
1181 state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 || 1236 state.depth.test_enabled =
1182 regs.output_merger.depth_write_enable == 1; 1237 regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1;
1183 state.depth.test_func = regs.output_merger.depth_test_enable == 1 ? 1238 state.depth.test_func = regs.output_merger.depth_test_enable == 1
1184 PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; 1239 ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func)
1240 : GL_ALWAYS;
1185} 1241}
1186 1242
1187void RasterizerOpenGL::SyncScissorTest() { 1243void RasterizerOpenGL::SyncScissorTest() {
@@ -1208,7 +1264,8 @@ void RasterizerOpenGL::SyncCombinerColor() {
1208 } 1264 }
1209} 1265}
1210 1266
1211void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { 1267void RasterizerOpenGL::SyncTevConstColor(int stage_index,
1268 const Pica::Regs::TevStageConfig& tev_stage) {
1212 auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); 1269 auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
1213 if (const_color != uniform_block_data.data.const_color[stage_index]) { 1270 if (const_color != uniform_block_data.data.const_color[stage_index]) {
1214 uniform_block_data.data.const_color[stage_index] = const_color; 1271 uniform_block_data.data.const_color[stage_index] = const_color;
@@ -1237,7 +1294,8 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
1237 if (new_data != lighting_lut_data[lut_index]) { 1294 if (new_data != lighting_lut_data[lut_index]) {
1238 lighting_lut_data[lut_index] = new_data; 1295 lighting_lut_data[lut_index] = new_data;
1239 glActiveTexture(GL_TEXTURE3 + lut_index); 1296 glActiveTexture(GL_TEXTURE3 + lut_index);
1240 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data()); 1297 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT,
1298 lighting_lut_data[lut_index].data());
1241 } 1299 }
1242} 1300}
1243 1301
@@ -1277,7 +1335,7 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) {
1277 GLvec3 position = { 1335 GLvec3 position = {
1278 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), 1336 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(),
1279 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), 1337 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(),
1280 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() }; 1338 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()};
1281 1339
1282 if (position != uniform_block_data.data.light_src[light_index].position) { 1340 if (position != uniform_block_data.data.light_src[light_index].position) {
1283 uniform_block_data.data.light_src[light_index].position = position; 1341 uniform_block_data.data.light_src[light_index].position = position;
@@ -1286,7 +1344,9 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) {
1286} 1344}
1287 1345
1288void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { 1346void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) {
1289 GLfloat dist_atten_bias = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias).ToFloat32(); 1347 GLfloat dist_atten_bias =
1348 Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias)
1349 .ToFloat32();
1290 1350
1291 if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) { 1351 if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) {
1292 uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias; 1352 uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias;
@@ -1295,7 +1355,9 @@ void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) {
1295} 1355}
1296 1356
1297void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) { 1357void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) {
1298 GLfloat dist_atten_scale = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale).ToFloat32(); 1358 GLfloat dist_atten_scale =
1359 Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale)
1360 .ToFloat32();
1299 1361
1300 if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) { 1362 if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) {
1301 uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale; 1363 uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index c5029432b..70e9e64ef 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -8,8 +8,8 @@
8#include <cstddef> 8#include <cstddef>
9#include <cstring> 9#include <cstring>
10#include <memory> 10#include <memory>
11#include <vector>
12#include <unordered_map> 11#include <unordered_map>
12#include <vector>
13 13
14#include <glad/glad.h> 14#include <glad/glad.h>
15 15
@@ -40,10 +40,13 @@ struct ScreenInfo;
40 * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) 40 * Pica state is not being captured in the shader cache key, thereby resulting in (what should be)
41 * two separate shaders sharing the same key. 41 * two separate shaders sharing the same key.
42 * 42 *
43 * We use a union because "implicitly-defined copy/move constructor for a union X copies the object representation of X." 43 * We use a union because "implicitly-defined copy/move constructor for a union X copies the object
44 * and "implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X." 44 * representation of X."
45 * and "implicitly-defined copy assignment operator for a union X copies the object representation
46 * (3.9) of X."
45 * = Bytewise copy instead of memberwise copy. 47 * = Bytewise copy instead of memberwise copy.
46 * This is important because the padding bytes are included in the hash and comparison between objects. 48 * This is important because the padding bytes are included in the hash and comparison between
49 * objects.
47 */ 50 */
48union PicaShaderConfig { 51union PicaShaderConfig {
49 52
@@ -60,8 +63,9 @@ union PicaShaderConfig {
60 63
61 state.depthmap_enable = regs.depthmap_enable; 64 state.depthmap_enable = regs.depthmap_enable;
62 65
63 state.alpha_test_func = regs.output_merger.alpha_test.enable ? 66 state.alpha_test_func = regs.output_merger.alpha_test.enable
64 regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; 67 ? regs.output_merger.alpha_test.func.Value()
68 : Pica::Regs::CompareFunc::Always;
65 69
66 state.texture0_type = regs.texture0.type; 70 state.texture0_type = regs.texture0.type;
67 71
@@ -81,9 +85,8 @@ union PicaShaderConfig {
81 state.fog_mode = regs.fog_mode; 85 state.fog_mode = regs.fog_mode;
82 state.fog_flip = regs.fog_flip; 86 state.fog_flip = regs.fog_flip;
83 87
84 state.combiner_buffer_input = 88 state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
85 regs.tev_combiner_buffer_input.update_mask_rgb.Value() | 89 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
86 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
87 90
88 // Fragment lighting 91 // Fragment lighting
89 92
@@ -95,8 +98,10 @@ union PicaShaderConfig {
95 const auto& light = regs.lighting.light[num]; 98 const auto& light = regs.lighting.light[num];
96 state.lighting.light[light_index].num = num; 99 state.lighting.light[light_index].num = num;
97 state.lighting.light[light_index].directional = light.config.directional != 0; 100 state.lighting.light[light_index].directional = light.config.directional != 0;
98 state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; 101 state.lighting.light[light_index].two_sided_diffuse =
99 state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); 102 light.config.two_sided_diffuse != 0;
103 state.lighting.light[light_index].dist_atten_enable =
104 !regs.lighting.IsDistAttenDisabled(num);
100 } 105 }
101 106
102 state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; 107 state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0;
@@ -147,7 +152,7 @@ union PicaShaderConfig {
147 return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index)); 152 return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index));
148 } 153 }
149 154
150 bool operator ==(const PicaShaderConfig& o) const { 155 bool operator==(const PicaShaderConfig& o) const {
151 return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0; 156 return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0;
152 }; 157 };
153 158
@@ -212,7 +217,8 @@ union PicaShaderConfig {
212 } state; 217 } state;
213}; 218};
214#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) 219#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
215static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, "PicaShaderConfig::State must be trivially copyable"); 220static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value,
221 "PicaShaderConfig::State must be trivially copyable");
216#endif 222#endif
217 223
218namespace std { 224namespace std {
@@ -228,12 +234,10 @@ struct hash<PicaShaderConfig> {
228 234
229class RasterizerOpenGL : public VideoCore::RasterizerInterface { 235class RasterizerOpenGL : public VideoCore::RasterizerInterface {
230public: 236public:
231
232 RasterizerOpenGL(); 237 RasterizerOpenGL();
233 ~RasterizerOpenGL() override; 238 ~RasterizerOpenGL() override;
234 239
235 void AddTriangle(const Pica::Shader::OutputVertex& v0, 240 void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
236 const Pica::Shader::OutputVertex& v1,
237 const Pica::Shader::OutputVertex& v2) override; 241 const Pica::Shader::OutputVertex& v2) override;
238 void DrawTriangles() override; 242 void DrawTriangles() override;
239 void NotifyPicaRegisterChanged(u32 id) override; 243 void NotifyPicaRegisterChanged(u32 id) override;
@@ -242,7 +246,8 @@ public:
242 void FlushAndInvalidateRegion(PAddr addr, u32 size) override; 246 void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
243 bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; 247 bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
244 bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; 248 bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
245 bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) override; 249 bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr,
250 u32 pixel_stride, ScreenInfo& screen_info) override;
246 251
247 /// OpenGL shader generated for a given Pica register state 252 /// OpenGL shader generated for a given Pica register state
248 struct PicaShader { 253 struct PicaShader {
@@ -251,13 +256,13 @@ public:
251 }; 256 };
252 257
253private: 258private:
254
255 struct SamplerInfo { 259 struct SamplerInfo {
256 using TextureConfig = Pica::Regs::TextureConfig; 260 using TextureConfig = Pica::Regs::TextureConfig;
257 261
258 OGLSampler sampler; 262 OGLSampler sampler;
259 263
260 /// Creates the sampler object, initializing its state so that it's in sync with the SamplerInfo struct. 264 /// Creates the sampler object, initializing its state so that it's in sync with the
265 /// SamplerInfo struct.
261 void Create(); 266 void Create();
262 /// Syncs the sampler object with the config, updating any necessary state. 267 /// Syncs the sampler object with the config, updating any necessary state.
263 void SyncWithConfig(const TextureConfig& config); 268 void SyncWithConfig(const TextureConfig& config);
@@ -343,8 +348,11 @@ private:
343 alignas(16) GLvec4 tev_combiner_buffer_color; 348 alignas(16) GLvec4 tev_combiner_buffer_color;
344 }; 349 };
345 350
346 static_assert(sizeof(UniformData) == 0x3C0, "The size of the UniformData structure has changed, update the structure in the shader"); 351 static_assert(
347 static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); 352 sizeof(UniformData) == 0x3C0,
353 "The size of the UniformData structure has changed, update the structure in the shader");
354 static_assert(sizeof(UniformData) < 16384,
355 "UniformData structure must be less than 16kb as per the OpenGL spec");
348 356
349 /// Sets the OpenGL shader in accordance with the current PICA register state 357 /// Sets the OpenGL shader in accordance with the current PICA register state
350 void SetShader(); 358 void SetShader();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 7efd0038a..8f1477bcd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -35,18 +35,18 @@ struct FormatTuple {
35}; 35};
36 36
37static const std::array<FormatTuple, 5> fb_format_tuples = {{ 37static const std::array<FormatTuple, 5> fb_format_tuples = {{
38 { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 }, // RGBA8 38 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8
39 { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, // RGB8 39 {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8
40 { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGB5A1 40 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1
41 { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB565 41 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
42 { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, // RGBA4 42 {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4
43}}; 43}};
44 44
45static const std::array<FormatTuple, 4> depth_format_tuples = {{ 45static const std::array<FormatTuple, 4> depth_format_tuples = {{
46 { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // D16 46 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
47 {}, 47 {},
48 { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }, // D24 48 {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
49 { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }, // D24S8 49 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
50}}; 50}};
51 51
52RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 52RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
@@ -58,7 +58,9 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
58 FlushAll(); 58 FlushAll();
59} 59}
60 60
61static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, u32 height, u32 bytes_per_pixel, u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data, bool morton_to_gl) { 61static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, u32 height,
62 u32 bytes_per_pixel, u32 gl_bytes_per_pixel, u8* morton_data,
63 u8* gl_data, bool morton_to_gl) {
62 using PixelFormat = CachedSurface::PixelFormat; 64 using PixelFormat = CachedSurface::PixelFormat;
63 65
64 u8* data_ptrs[2]; 66 u8* data_ptrs[2];
@@ -72,7 +74,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
72 for (unsigned y = 0; y < height; ++y) { 74 for (unsigned y = 0; y < height; ++y) {
73 for (unsigned x = 0; x < width; ++x) { 75 for (unsigned x = 0; x < width; ++x) {
74 const u32 coarse_y = y & ~7; 76 const u32 coarse_y = y & ~7;
75 u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; 77 u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
78 coarse_y * width * bytes_per_pixel;
76 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; 79 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
77 80
78 data_ptrs[morton_to_gl] = morton_data + morton_offset; 81 data_ptrs[morton_to_gl] = morton_data + morton_offset;
@@ -81,7 +84,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
81 // Swap depth and stencil value ordering since 3DS does not match OpenGL 84 // Swap depth and stencil value ordering since 3DS does not match OpenGL
82 u32 depth_stencil; 85 u32 depth_stencil;
83 memcpy(&depth_stencil, data_ptrs[1], sizeof(u32)); 86 memcpy(&depth_stencil, data_ptrs[1], sizeof(u32));
84 depth_stencil = (depth_stencil << depth_stencil_shifts[0]) | (depth_stencil >> depth_stencil_shifts[1]); 87 depth_stencil = (depth_stencil << depth_stencil_shifts[0]) |
88 (depth_stencil >> depth_stencil_shifts[1]);
85 89
86 memcpy(data_ptrs[0], &depth_stencil, sizeof(u32)); 90 memcpy(data_ptrs[0], &depth_stencil, sizeof(u32));
87 } 91 }
@@ -90,7 +94,8 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
90 for (unsigned y = 0; y < height; ++y) { 94 for (unsigned y = 0; y < height; ++y) {
91 for (unsigned x = 0; x < width; ++x) { 95 for (unsigned x = 0; x < width; ++x) {
92 const u32 coarse_y = y & ~7; 96 const u32 coarse_y = y & ~7;
93 u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; 97 u32 morton_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
98 coarse_y * width * bytes_per_pixel;
94 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel; 99 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
95 100
96 data_ptrs[morton_to_gl] = morton_data + morton_offset; 101 data_ptrs[morton_to_gl] = morton_data + morton_offset;
@@ -102,17 +107,21 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
102 } 107 }
103} 108}
104 109
105bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { 110bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
111 CachedSurface::SurfaceType type,
112 const MathUtil::Rectangle<int>& src_rect,
113 const MathUtil::Rectangle<int>& dst_rect) {
106 using SurfaceType = CachedSurface::SurfaceType; 114 using SurfaceType = CachedSurface::SurfaceType;
107 115
108 OpenGLState cur_state = OpenGLState::GetCurState(); 116 OpenGLState cur_state = OpenGLState::GetCurState();
109 117
110 // Make sure textures aren't bound to texture units, since going to bind them to framebuffer components 118 // Make sure textures aren't bound to texture units, since going to bind them to framebuffer
119 // components
111 OpenGLState::ResetTexture(src_tex); 120 OpenGLState::ResetTexture(src_tex);
112 OpenGLState::ResetTexture(dst_tex); 121 OpenGLState::ResetTexture(dst_tex);
113 122
114 // Keep track of previous framebuffer bindings 123 // Keep track of previous framebuffer bindings
115 GLuint old_fbs[2] = { cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer }; 124 GLuint old_fbs[2] = {cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer};
116 cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle; 125 cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle;
117 cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle; 126 cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle;
118 cur_state.Apply(); 127 cur_state.Apply();
@@ -120,11 +129,15 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
120 u32 buffers = 0; 129 u32 buffers = 0;
121 130
122 if (type == SurfaceType::Color || type == SurfaceType::Texture) { 131 if (type == SurfaceType::Color || type == SurfaceType::Texture) {
123 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, 0); 132 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
124 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 133 0);
134 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
135 0);
125 136
126 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); 137 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex,
127 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 138 0);
139 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
140 0);
128 141
129 buffers = GL_COLOR_BUFFER_BIT; 142 buffers = GL_COLOR_BUFFER_BIT;
130 } else if (type == SurfaceType::Depth) { 143 } else if (type == SurfaceType::Depth) {
@@ -139,10 +152,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
139 buffers = GL_DEPTH_BUFFER_BIT; 152 buffers = GL_DEPTH_BUFFER_BIT;
140 } else if (type == SurfaceType::DepthStencil) { 153 } else if (type == SurfaceType::DepthStencil) {
141 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 154 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
142 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0); 155 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
156 src_tex, 0);
143 157
144 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 158 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
145 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0); 159 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
160 dst_tex, 0);
146 161
147 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; 162 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
148 } 163 }
@@ -155,9 +170,9 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
155 return false; 170 return false;
156 } 171 }
157 172
158 glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, 173 glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
159 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, 174 dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
160 buffers, buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); 175 buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
161 176
162 // Restore previous framebuffer bindings 177 // Restore previous framebuffer bindings
163 cur_state.draw.read_framebuffer = old_fbs[0]; 178 cur_state.draw.read_framebuffer = old_fbs[0];
@@ -167,17 +182,24 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS
167 return true; 182 return true;
168} 183}
169 184
170bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect) { 185bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,
186 const MathUtil::Rectangle<int>& src_rect,
187 CachedSurface* dst_surface,
188 const MathUtil::Rectangle<int>& dst_rect) {
171 using SurfaceType = CachedSurface::SurfaceType; 189 using SurfaceType = CachedSurface::SurfaceType;
172 190
173 if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { 191 if (!CachedSurface::CheckFormatsBlittable(src_surface->pixel_format,
192 dst_surface->pixel_format)) {
174 return false; 193 return false;
175 } 194 }
176 195
177 return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect); 196 return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle,
197 CachedSurface::GetFormatType(src_surface->pixel_format), src_rect,
198 dst_rect);
178} 199}
179 200
180static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) { 201static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format,
202 u32 width, u32 height) {
181 // Allocate an uninitialized texture of appropriate size and format for the surface 203 // Allocate an uninitialized texture of appropriate size and format for the surface
182 using SurfaceType = CachedSurface::SurfaceType; 204 using SurfaceType = CachedSurface::SurfaceType;
183 205
@@ -200,11 +222,11 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi
200 ASSERT(tuple_idx < depth_format_tuples.size()); 222 ASSERT(tuple_idx < depth_format_tuples.size());
201 tuple = depth_format_tuples[tuple_idx]; 223 tuple = depth_format_tuples[tuple_idx];
202 } else { 224 } else {
203 tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; 225 tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
204 } 226 }
205 227
206 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, 228 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, width, height, 0, tuple.format,
207 tuple.format, tuple.type, nullptr); 229 tuple.type, nullptr);
208 230
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -217,7 +239,8 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi
217} 239}
218 240
219MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); 241MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192));
220CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create) { 242CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bool match_res_scale,
243 bool load_if_create) {
221 using PixelFormat = CachedSurface::PixelFormat; 244 using PixelFormat = CachedSurface::PixelFormat;
222 using SurfaceType = CachedSurface::SurfaceType; 245 using SurfaceType = CachedSurface::SurfaceType;
223 246
@@ -225,29 +248,31 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
225 return nullptr; 248 return nullptr;
226 } 249 }
227 250
228 u32 params_size = params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8; 251 u32 params_size =
252 params.width * params.height * CachedSurface::GetFormatBpp(params.pixel_format) / 8;
229 253
230 // Check for an exact match in existing surfaces 254 // Check for an exact match in existing surfaces
231 CachedSurface* best_exact_surface = nullptr; 255 CachedSurface* best_exact_surface = nullptr;
232 float exact_surface_goodness = -1.f; 256 float exact_surface_goodness = -1.f;
233 257
234 auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); 258 auto surface_interval =
259 boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size);
235 auto range = surface_cache.equal_range(surface_interval); 260 auto range = surface_cache.equal_range(surface_interval);
236 for (auto it = range.first; it != range.second; ++it) { 261 for (auto it = range.first; it != range.second; ++it) {
237 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { 262 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
238 CachedSurface* surface = it2->get(); 263 CachedSurface* surface = it2->get();
239 264
240 // Check if the request matches the surface exactly 265 // Check if the request matches the surface exactly
241 if (params.addr == surface->addr && 266 if (params.addr == surface->addr && params.width == surface->width &&
242 params.width == surface->width && params.height == surface->height && 267 params.height == surface->height && params.pixel_format == surface->pixel_format) {
243 params.pixel_format == surface->pixel_format)
244 {
245 // Make sure optional param-matching criteria are fulfilled 268 // Make sure optional param-matching criteria are fulfilled
246 bool tiling_match = (params.is_tiled == surface->is_tiled); 269 bool tiling_match = (params.is_tiled == surface->is_tiled);
247 bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); 270 bool res_scale_match = (params.res_scale_width == surface->res_scale_width &&
271 params.res_scale_height == surface->res_scale_height);
248 if (!match_res_scale || res_scale_match) { 272 if (!match_res_scale || res_scale_match) {
249 // Prioritize same-tiling and highest resolution surfaces 273 // Prioritize same-tiling and highest resolution surfaces
250 float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; 274 float match_goodness =
275 (float)tiling_match + surface->res_scale_width * surface->res_scale_height;
251 if (match_goodness > exact_surface_goodness || surface->dirty) { 276 if (match_goodness > exact_surface_goodness || surface->dirty) {
252 exact_surface_goodness = match_goodness; 277 exact_surface_goodness = match_goodness;
253 best_exact_surface = surface; 278 best_exact_surface = surface;
@@ -288,9 +313,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
288 313
289 if (!load_if_create) { 314 if (!load_if_create) {
290 // Don't load any data; just allocate the surface's texture 315 // Don't load any data; just allocate the surface's texture
291 AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); 316 AllocateSurfaceTexture(new_surface->texture.handle, new_surface->pixel_format,
317 new_surface->GetScaledWidth(), new_surface->GetScaledHeight());
292 } else { 318 } else {
293 // TODO: Consider attempting subrect match in existing surfaces and direct blit here instead of memory upload below if that's a common scenario in some game 319 // TODO: Consider attempting subrect match in existing surfaces and direct blit here instead
320 // of memory upload below if that's a common scenario in some game
294 321
295 Memory::RasterizerFlushRegion(params.addr, params_size); 322 Memory::RasterizerFlushRegion(params.addr, params_size);
296 323
@@ -318,7 +345,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
318 tuple = fb_format_tuples[(unsigned int)params.pixel_format]; 345 tuple = fb_format_tuples[(unsigned int)params.pixel_format];
319 } else { 346 } else {
320 // Texture 347 // Texture
321 tuple = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; 348 tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
322 } 349 }
323 350
324 std::vector<Math::Vec4<u8>> tex_buffer(params.width * params.height); 351 std::vector<Math::Vec4<u8>> tex_buffer(params.width * params.height);
@@ -326,19 +353,23 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
326 Pica::DebugUtils::TextureInfo tex_info; 353 Pica::DebugUtils::TextureInfo tex_info;
327 tex_info.width = params.width; 354 tex_info.width = params.width;
328 tex_info.height = params.height; 355 tex_info.height = params.height;
329 tex_info.stride = params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; 356 tex_info.stride =
357 params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8;
330 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; 358 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format;
331 tex_info.physical_address = params.addr; 359 tex_info.physical_address = params.addr;
332 360
333 for (unsigned y = 0; y < params.height; ++y) { 361 for (unsigned y = 0; y < params.height; ++y) {
334 for (unsigned x = 0; x < params.width; ++x) { 362 for (unsigned x = 0; x < params.width; ++x) {
335 tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, params.height - 1 - y, tex_info); 363 tex_buffer[x + params.width * y] = Pica::DebugUtils::LookupTexture(
364 texture_src_data, x, params.height - 1 - y, tex_info);
336 } 365 }
337 } 366 }
338 367
339 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data()); 368 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height,
369 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer.data());
340 } else { 370 } else {
341 // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format 371 // Depth/Stencil formats need special treatment since they aren't sampleable using
372 // LookupTexture and can't use RGBA format
342 size_t tuple_idx = (size_t)params.pixel_format - 14; 373 size_t tuple_idx = (size_t)params.pixel_format - 14;
343 ASSERT(tuple_idx < depth_format_tuples.size()); 374 ASSERT(tuple_idx < depth_format_tuples.size());
344 const FormatTuple& tuple = depth_format_tuples[tuple_idx]; 375 const FormatTuple& tuple = depth_format_tuples[tuple_idx];
@@ -350,14 +381,18 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
350 381
351 u32 gl_bytes_per_pixel = use_4bpp ? 4 : bytes_per_pixel; 382 u32 gl_bytes_per_pixel = use_4bpp ? 4 : bytes_per_pixel;
352 383
353 std::vector<u8> temp_fb_depth_buffer(params.width * params.height * gl_bytes_per_pixel); 384 std::vector<u8> temp_fb_depth_buffer(params.width * params.height *
385 gl_bytes_per_pixel);
354 386
355 u8* temp_fb_depth_buffer_ptr = use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data(); 387 u8* temp_fb_depth_buffer_ptr =
388 use_4bpp ? temp_fb_depth_buffer.data() + 1 : temp_fb_depth_buffer.data();
356 389
357 MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel, gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr, true); 390 MortonCopyPixels(params.pixel_format, params.width, params.height, bytes_per_pixel,
391 gl_bytes_per_pixel, texture_src_data, temp_fb_depth_buffer_ptr,
392 true);
358 393
359 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, 394 glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height,
360 tuple.format, tuple.type, temp_fb_depth_buffer.data()); 395 0, tuple.format, tuple.type, temp_fb_depth_buffer.data());
361 } 396 }
362 } 397 }
363 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 398 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@@ -367,10 +402,13 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
367 OGLTexture scaled_texture; 402 OGLTexture scaled_texture;
368 scaled_texture.Create(); 403 scaled_texture.Create();
369 404
370 AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format, new_surface->GetScaledWidth(), new_surface->GetScaledHeight()); 405 AllocateSurfaceTexture(scaled_texture.handle, new_surface->pixel_format,
371 BlitTextures(new_surface->texture.handle, scaled_texture.handle, CachedSurface::GetFormatType(new_surface->pixel_format), 406 new_surface->GetScaledWidth(), new_surface->GetScaledHeight());
372 MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height), 407 BlitTextures(new_surface->texture.handle, scaled_texture.handle,
373 MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(), new_surface->GetScaledHeight())); 408 CachedSurface::GetFormatType(new_surface->pixel_format),
409 MathUtil::Rectangle<int>(0, 0, new_surface->width, new_surface->height),
410 MathUtil::Rectangle<int>(0, 0, new_surface->GetScaledWidth(),
411 new_surface->GetScaledHeight()));
374 412
375 new_surface->texture.Release(); 413 new_surface->texture.Release();
376 new_surface->texture.handle = scaled_texture.handle; 414 new_surface->texture.handle = scaled_texture.handle;
@@ -389,11 +427,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
389 } 427 }
390 428
391 Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); 429 Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1);
392 surface_cache.add(std::make_pair(boost::icl::interval<PAddr>::right_open(new_surface->addr, new_surface->addr + new_surface->size), std::set<std::shared_ptr<CachedSurface>>({ new_surface }))); 430 surface_cache.add(std::make_pair(boost::icl::interval<PAddr>::right_open(
431 new_surface->addr, new_surface->addr + new_surface->size),
432 std::set<std::shared_ptr<CachedSurface>>({new_surface})));
393 return new_surface.get(); 433 return new_surface.get();
394} 434}
395 435
396CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect) { 436CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params,
437 bool match_res_scale, bool load_if_create,
438 MathUtil::Rectangle<int>& out_rect) {
397 if (params.addr == 0) { 439 if (params.addr == 0) {
398 return nullptr; 440 return nullptr;
399 } 441 }
@@ -405,7 +447,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
405 CachedSurface* best_subrect_surface = nullptr; 447 CachedSurface* best_subrect_surface = nullptr;
406 float subrect_surface_goodness = -1.f; 448 float subrect_surface_goodness = -1.f;
407 449
408 auto surface_interval = boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size); 450 auto surface_interval =
451 boost::icl::interval<PAddr>::right_open(params.addr, params.addr + params_size);
409 auto cache_upper_bound = surface_cache.upper_bound(surface_interval); 452 auto cache_upper_bound = surface_cache.upper_bound(surface_interval);
410 for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { 453 for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) {
411 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { 454 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
@@ -414,14 +457,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
414 // Check if the request is contained in the surface 457 // Check if the request is contained in the surface
415 if (params.addr >= surface->addr && 458 if (params.addr >= surface->addr &&
416 params.addr + params_size - 1 <= surface->addr + surface->size - 1 && 459 params.addr + params_size - 1 <= surface->addr + surface->size - 1 &&
417 params.pixel_format == surface->pixel_format) 460 params.pixel_format == surface->pixel_format) {
418 {
419 // Make sure optional param-matching criteria are fulfilled 461 // Make sure optional param-matching criteria are fulfilled
420 bool tiling_match = (params.is_tiled == surface->is_tiled); 462 bool tiling_match = (params.is_tiled == surface->is_tiled);
421 bool res_scale_match = (params.res_scale_width == surface->res_scale_width && params.res_scale_height == surface->res_scale_height); 463 bool res_scale_match = (params.res_scale_width == surface->res_scale_width &&
464 params.res_scale_height == surface->res_scale_height);
422 if (!match_res_scale || res_scale_match) { 465 if (!match_res_scale || res_scale_match) {
423 // Prioritize same-tiling and highest resolution surfaces 466 // Prioritize same-tiling and highest resolution surfaces
424 float match_goodness = (float)tiling_match + surface->res_scale_width * surface->res_scale_height; 467 float match_goodness =
468 (float)tiling_match + surface->res_scale_width * surface->res_scale_height;
425 if (match_goodness > subrect_surface_goodness || surface->dirty) { 469 if (match_goodness > subrect_surface_goodness || surface->dirty) {
426 subrect_surface_goodness = match_goodness; 470 subrect_surface_goodness = match_goodness;
427 best_subrect_surface = surface; 471 best_subrect_surface = surface;
@@ -433,7 +477,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
433 477
434 // Return the best subrect surface if found 478 // Return the best subrect surface if found
435 if (best_subrect_surface != nullptr) { 479 if (best_subrect_surface != nullptr) {
436 unsigned int bytes_per_pixel = (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8); 480 unsigned int bytes_per_pixel =
481 (CachedSurface::GetFormatBpp(best_subrect_surface->pixel_format) / 8);
437 482
438 int x0, y0; 483 int x0, y0;
439 484
@@ -452,7 +497,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
452 y0 = begin_tile_index / tiles_per_row * 8; 497 y0 = begin_tile_index / tiles_per_row * 8;
453 498
454 // Tiled surfaces are flipped vertically in the rasterizer vs. 3DS memory. 499 // Tiled surfaces are flipped vertically in the rasterizer vs. 3DS memory.
455 out_rect = MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width, best_subrect_surface->height - (y0 + params.height)); 500 out_rect =
501 MathUtil::Rectangle<int>(x0, best_subrect_surface->height - y0, x0 + params.width,
502 best_subrect_surface->height - (y0 + params.height));
456 } 503 }
457 504
458 out_rect.left = (int)(out_rect.left * best_subrect_surface->res_scale_width); 505 out_rect.left = (int)(out_rect.left * best_subrect_surface->res_scale_width);
@@ -465,16 +512,20 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
465 512
466 // No subrect found - create and return a new surface 513 // No subrect found - create and return a new surface
467 if (!params.is_tiled) { 514 if (!params.is_tiled) {
468 out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width), (int)(params.height * params.res_scale_height)); 515 out_rect = MathUtil::Rectangle<int>(0, 0, (int)(params.width * params.res_scale_width),
516 (int)(params.height * params.res_scale_height));
469 } else { 517 } else {
470 out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height), (int)(params.width * params.res_scale_width), 0); 518 out_rect = MathUtil::Rectangle<int>(0, (int)(params.height * params.res_scale_height),
519 (int)(params.width * params.res_scale_width), 0);
471 } 520 }
472 521
473 return GetSurface(params, match_res_scale, load_if_create); 522 return GetSurface(params, match_res_scale, load_if_create);
474} 523}
475 524
476CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) { 525CachedSurface*
477 Pica::DebugUtils::TextureInfo info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); 526RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTextureConfig& config) {
527 Pica::DebugUtils::TextureInfo info =
528 Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
478 529
479 CachedSurface params; 530 CachedSurface params;
480 params.addr = info.physical_address; 531 params.addr = info.physical_address;
@@ -485,20 +536,28 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(const Pica::Regs::FullTe
485 return GetSurface(params, false, true); 536 return GetSurface(params, false, true);
486} 537}
487 538
488std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { 539std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
540RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) {
489 const auto& regs = Pica::g_state.regs; 541 const auto& regs = Pica::g_state.regs;
490 542
491 // Make sur that framebuffers don't overlap if both color and depth are being used 543 // Make sur that framebuffers don't overlap if both color and depth are being used
492 u32 fb_area = config.GetWidth() * config.GetHeight(); 544 u32 fb_area = config.GetWidth() * config.GetHeight();
493 bool framebuffers_overlap = config.GetColorBufferPhysicalAddress() != 0 && 545 bool framebuffers_overlap =
494 config.GetDepthBufferPhysicalAddress() != 0 && 546 config.GetColorBufferPhysicalAddress() != 0 &&
495 MathUtil::IntervalsIntersect(config.GetColorBufferPhysicalAddress(), fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), 547 config.GetDepthBufferPhysicalAddress() != 0 &&
496 config.GetDepthBufferPhysicalAddress(), fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); 548 MathUtil::IntervalsIntersect(
549 config.GetColorBufferPhysicalAddress(),
550 fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
551 config.GetDepthBufferPhysicalAddress(),
552 fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format));
497 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; 553 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0;
498 bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && (regs.output_merger.depth_test_enable || regs.output_merger.depth_write_enable || !framebuffers_overlap); 554 bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 &&
555 (regs.output_merger.depth_test_enable ||
556 regs.output_merger.depth_write_enable || !framebuffers_overlap);
499 557
500 if (framebuffers_overlap && using_color_fb && using_depth_fb) { 558 if (framebuffers_overlap && using_color_fb && using_depth_fb) {
501 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; overlapping framebuffers not supported!"); 559 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
560 "overlapping framebuffers not supported!");
502 using_depth_fb = false; 561 using_depth_fb = false;
503 } 562 }
504 563
@@ -512,8 +571,10 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC
512 auto layout = VideoCore::g_emu_window->GetFramebufferLayout(); 571 auto layout = VideoCore::g_emu_window->GetFramebufferLayout();
513 572
514 // Assume same scaling factor for top and bottom screens 573 // Assume same scaling factor for top and bottom screens
515 color_params.res_scale_width = depth_params.res_scale_width = (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; 574 color_params.res_scale_width = depth_params.res_scale_width =
516 color_params.res_scale_height = depth_params.res_scale_height = (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; 575 (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth;
576 color_params.res_scale_height = depth_params.res_scale_height =
577 (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight;
517 } 578 }
518 579
519 color_params.addr = config.GetColorBufferPhysicalAddress(); 580 color_params.addr = config.GetColorBufferPhysicalAddress();
@@ -523,22 +584,28 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC
523 depth_params.pixel_format = CachedSurface::PixelFormatFromDepthFormat(config.depth_format); 584 depth_params.pixel_format = CachedSurface::PixelFormatFromDepthFormat(config.depth_format);
524 585
525 MathUtil::Rectangle<int> color_rect; 586 MathUtil::Rectangle<int> color_rect;
526 CachedSurface* color_surface = using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr; 587 CachedSurface* color_surface =
588 using_color_fb ? GetSurfaceRect(color_params, true, true, color_rect) : nullptr;
527 589
528 MathUtil::Rectangle<int> depth_rect; 590 MathUtil::Rectangle<int> depth_rect;
529 CachedSurface* depth_surface = using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr; 591 CachedSurface* depth_surface =
592 using_depth_fb ? GetSurfaceRect(depth_params, true, true, depth_rect) : nullptr;
530 593
531 // Sanity check to make sure found surfaces aren't the same 594 // Sanity check to make sure found surfaces aren't the same
532 if (using_depth_fb && using_color_fb && color_surface == depth_surface) { 595 if (using_depth_fb && using_color_fb && color_surface == depth_surface) {
533 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!"); 596 LOG_CRITICAL(
597 Render_OpenGL,
598 "Color and depth framebuffer surfaces overlap; overlapping surfaces not supported!");
534 using_depth_fb = false; 599 using_depth_fb = false;
535 depth_surface = nullptr; 600 depth_surface = nullptr;
536 } 601 }
537 602
538 MathUtil::Rectangle<int> rect; 603 MathUtil::Rectangle<int> rect;
539 604
540 if (color_surface != nullptr && depth_surface != nullptr && (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) { 605 if (color_surface != nullptr && depth_surface != nullptr &&
541 // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if they don't match 606 (depth_rect.left != color_rect.left || depth_rect.top != color_rect.top)) {
607 // Can't specify separate color and depth viewport offsets in OpenGL, so re-zero both if
608 // they don't match
542 if (color_rect.left != 0 || color_rect.top != 0) { 609 if (color_rect.left != 0 || color_rect.top != 0) {
543 color_surface = GetSurface(color_params, true, true); 610 color_surface = GetSurface(color_params, true, true);
544 } 611 }
@@ -548,9 +615,13 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC
548 } 615 }
549 616
550 if (!color_surface->is_tiled) { 617 if (!color_surface->is_tiled) {
551 rect = MathUtil::Rectangle<int>(0, 0, (int)(color_params.width * color_params.res_scale_width), (int)(color_params.height * color_params.res_scale_height)); 618 rect = MathUtil::Rectangle<int>(
619 0, 0, (int)(color_params.width * color_params.res_scale_width),
620 (int)(color_params.height * color_params.res_scale_height));
552 } else { 621 } else {
553 rect = MathUtil::Rectangle<int>(0, (int)(color_params.height * color_params.res_scale_height), (int)(color_params.width * color_params.res_scale_width), 0); 622 rect = MathUtil::Rectangle<int>(
623 0, (int)(color_params.height * color_params.res_scale_height),
624 (int)(color_params.width * color_params.res_scale_width), 0);
554 } 625 }
555 } else if (color_surface != nullptr) { 626 } else if (color_surface != nullptr) {
556 rect = color_rect; 627 rect = color_rect;
@@ -564,7 +635,8 @@ std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> RasterizerC
564} 635}
565 636
566CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config) { 637CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config) {
567 auto surface_interval = boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress()); 638 auto surface_interval =
639 boost::icl::interval<PAddr>::right_open(config.GetStartAddress(), config.GetEndAddress());
568 auto range = surface_cache.equal_range(surface_interval); 640 auto range = surface_cache.equal_range(surface_interval);
569 for (auto it = range.first; it != range.second; ++it) { 641 for (auto it = range.first; it != range.second; ++it) {
570 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) { 642 for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
@@ -581,8 +653,9 @@ CachedSurface* RasterizerCacheOpenGL::TryGetFillSurface(const GPU::Regs::MemoryF
581 653
582 if (surface->addr == config.GetStartAddress() && 654 if (surface->addr == config.GetStartAddress() &&
583 CachedSurface::GetFormatBpp(surface->pixel_format) == bits_per_value && 655 CachedSurface::GetFormatBpp(surface->pixel_format) == bits_per_value &&
584 (surface->width * surface->height * CachedSurface::GetFormatBpp(surface->pixel_format) / 8) == (config.GetEndAddress() - config.GetStartAddress())) 656 (surface->width * surface->height *
585 { 657 CachedSurface::GetFormatBpp(surface->pixel_format) / 8) ==
658 (config.GetEndAddress() - config.GetStartAddress())) {
586 return surface; 659 return surface;
587 } 660 }
588 } 661 }
@@ -617,8 +690,11 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
617 if (surface->res_scale_width != 1.f || surface->res_scale_height != 1.f) { 690 if (surface->res_scale_width != 1.f || surface->res_scale_height != 1.f) {
618 unscaled_tex.Create(); 691 unscaled_tex.Create();
619 692
620 AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width, surface->height); 693 AllocateSurfaceTexture(unscaled_tex.handle, surface->pixel_format, surface->width,
621 BlitTextures(surface->texture.handle, unscaled_tex.handle, CachedSurface::GetFormatType(surface->pixel_format), 694 surface->height);
695 BlitTextures(
696 surface->texture.handle, unscaled_tex.handle,
697 CachedSurface::GetFormatType(surface->pixel_format),
622 MathUtil::Rectangle<int>(0, 0, surface->GetScaledWidth(), surface->GetScaledHeight()), 698 MathUtil::Rectangle<int>(0, 0, surface->GetScaledWidth(), surface->GetScaledHeight()),
623 MathUtil::Rectangle<int>(0, 0, surface->width, surface->height)); 699 MathUtil::Rectangle<int>(0, 0, surface->width, surface->height));
624 700
@@ -648,10 +724,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
648 724
649 glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, temp_gl_buffer.data()); 725 glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, temp_gl_buffer.data());
650 726
651 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. 727 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion
652 MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(), false); 728 // is necessary.
729 MortonCopyPixels(surface->pixel_format, surface->width, surface->height,
730 bytes_per_pixel, bytes_per_pixel, dst_buffer, temp_gl_buffer.data(),
731 false);
653 } else { 732 } else {
654 // Depth/Stencil formats need special treatment since they aren't sampleable using LookupTexture and can't use RGBA format 733 // Depth/Stencil formats need special treatment since they aren't sampleable using
734 // LookupTexture and can't use RGBA format
655 size_t tuple_idx = (size_t)surface->pixel_format - 14; 735 size_t tuple_idx = (size_t)surface->pixel_format - 14;
656 ASSERT(tuple_idx < depth_format_tuples.size()); 736 ASSERT(tuple_idx < depth_format_tuples.size());
657 const FormatTuple& tuple = depth_format_tuples[tuple_idx]; 737 const FormatTuple& tuple = depth_format_tuples[tuple_idx];
@@ -669,7 +749,9 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
669 749
670 u8* temp_gl_buffer_ptr = use_4bpp ? temp_gl_buffer.data() + 1 : temp_gl_buffer.data(); 750 u8* temp_gl_buffer_ptr = use_4bpp ? temp_gl_buffer.data() + 1 : temp_gl_buffer.data();
671 751
672 MortonCopyPixels(surface->pixel_format, surface->width, surface->height, bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr, false); 752 MortonCopyPixels(surface->pixel_format, surface->width, surface->height,
753 bytes_per_pixel, gl_bytes_per_pixel, dst_buffer, temp_gl_buffer_ptr,
754 false);
673 } 755 }
674 } 756 }
675 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 757 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
@@ -680,7 +762,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
680 cur_state.Apply(); 762 cur_state.Apply();
681} 763}
682 764
683void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate) { 765void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface,
766 bool invalidate) {
684 if (size == 0) { 767 if (size == 0) {
685 return; 768 return;
686 } 769 }
@@ -691,8 +774,11 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac
691 auto surface_interval = boost::icl::interval<PAddr>::right_open(addr, addr + size); 774 auto surface_interval = boost::icl::interval<PAddr>::right_open(addr, addr + size);
692 auto cache_upper_bound = surface_cache.upper_bound(surface_interval); 775 auto cache_upper_bound = surface_cache.upper_bound(surface_interval);
693 for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) { 776 for (auto it = surface_cache.lower_bound(surface_interval); it != cache_upper_bound; ++it) {
694 std::copy_if(it->second.begin(), it->second.end(), std::inserter(touching_surfaces, touching_surfaces.end()), 777 std::copy_if(it->second.begin(), it->second.end(),
695 [skip_surface](std::shared_ptr<CachedSurface> surface) { return (surface.get() != skip_surface); }); 778 std::inserter(touching_surfaces, touching_surfaces.end()),
779 [skip_surface](std::shared_ptr<CachedSurface> surface) {
780 return (surface.get() != skip_surface);
781 });
696 } 782 }
697 783
698 // Flush and invalidate surfaces 784 // Flush and invalidate surfaces
@@ -700,7 +786,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurfac
700 FlushSurface(surface.get()); 786 FlushSurface(surface.get());
701 if (invalidate) { 787 if (invalidate) {
702 Memory::RasterizerMarkRegionCached(surface->addr, surface->size, -1); 788 Memory::RasterizerMarkRegionCached(surface->addr, surface->size, -1);
703 surface_cache.subtract(std::make_pair(boost::icl::interval<PAddr>::right_open(surface->addr, surface->addr + surface->size), std::set<std::shared_ptr<CachedSurface>>({ surface }))); 789 surface_cache.subtract(
790 std::make_pair(boost::icl::interval<PAddr>::right_open(
791 surface->addr, surface->addr + surface->size),
792 std::set<std::shared_ptr<CachedSurface>>({surface})));
704 } 793 }
705 } 794 }
706} 795}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 225596415..db5b649da 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -22,7 +22,8 @@
22#include "video_core/renderer_opengl/gl_resource_manager.h" 22#include "video_core/renderer_opengl/gl_resource_manager.h"
23 23
24namespace MathUtil { 24namespace MathUtil {
25template <class T> struct Rectangle; 25template <class T>
26struct Rectangle;
26} 27}
27 28
28struct CachedSurface; 29struct CachedSurface;
@@ -32,38 +33,38 @@ using SurfaceCache = boost::icl::interval_map<PAddr, std::set<std::shared_ptr<Ca
32struct CachedSurface { 33struct CachedSurface {
33 enum class PixelFormat { 34 enum class PixelFormat {
34 // First 5 formats are shared between textures and color buffers 35 // First 5 formats are shared between textures and color buffers
35 RGBA8 = 0, 36 RGBA8 = 0,
36 RGB8 = 1, 37 RGB8 = 1,
37 RGB5A1 = 2, 38 RGB5A1 = 2,
38 RGB565 = 3, 39 RGB565 = 3,
39 RGBA4 = 4, 40 RGBA4 = 4,
40 41
41 // Texture-only formats 42 // Texture-only formats
42 IA8 = 5, 43 IA8 = 5,
43 RG8 = 6, 44 RG8 = 6,
44 I8 = 7, 45 I8 = 7,
45 A8 = 8, 46 A8 = 8,
46 IA4 = 9, 47 IA4 = 9,
47 I4 = 10, 48 I4 = 10,
48 A4 = 11, 49 A4 = 11,
49 ETC1 = 12, 50 ETC1 = 12,
50 ETC1A4 = 13, 51 ETC1A4 = 13,
51 52
52 // Depth buffer-only formats 53 // Depth buffer-only formats
53 D16 = 14, 54 D16 = 14,
54 // gap 55 // gap
55 D24 = 16, 56 D24 = 16,
56 D24S8 = 17, 57 D24S8 = 17,
57 58
58 Invalid = 255, 59 Invalid = 255,
59 }; 60 };
60 61
61 enum class SurfaceType { 62 enum class SurfaceType {
62 Color = 0, 63 Color = 0,
63 Texture = 1, 64 Texture = 1,
64 Depth = 2, 65 Depth = 2,
65 DepthStencil = 3, 66 DepthStencil = 3,
66 Invalid = 4, 67 Invalid = 4,
67 }; 68 };
68 69
69 static unsigned int GetFormatBpp(CachedSurface::PixelFormat format) { 70 static unsigned int GetFormatBpp(CachedSurface::PixelFormat format) {
@@ -101,7 +102,8 @@ struct CachedSurface {
101 } 102 }
102 103
103 static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { 104 static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) {
104 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) : PixelFormat::Invalid; 105 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
106 : PixelFormat::Invalid;
105 } 107 }
106 108
107 static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { 109 static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) {
@@ -120,7 +122,8 @@ struct CachedSurface {
120 SurfaceType a_type = GetFormatType(pixel_format_a); 122 SurfaceType a_type = GetFormatType(pixel_format_a);
121 SurfaceType b_type = GetFormatType(pixel_format_b); 123 SurfaceType b_type = GetFormatType(pixel_format_b);
122 124
123 if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { 125 if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) &&
126 (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) {
124 return true; 127 return true;
125 } 128 }
126 129
@@ -187,22 +190,30 @@ public:
187 ~RasterizerCacheOpenGL(); 190 ~RasterizerCacheOpenGL();
188 191
189 /// Blits one texture to another 192 /// Blits one texture to another
190 bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect); 193 bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type,
194 const MathUtil::Rectangle<int>& src_rect,
195 const MathUtil::Rectangle<int>& dst_rect);
191 196
192 /// Attempt to blit one surface's texture to another 197 /// Attempt to blit one surface's texture to another
193 bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect, CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect); 198 bool TryBlitSurfaces(CachedSurface* src_surface, const MathUtil::Rectangle<int>& src_rect,
199 CachedSurface* dst_surface, const MathUtil::Rectangle<int>& dst_rect);
194 200
195 /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) 201 /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached)
196 CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale, bool load_if_create); 202 CachedSurface* GetSurface(const CachedSurface& params, bool match_res_scale,
203 bool load_if_create);
197 204
198 /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from 3DS memory to OpenGL and caches it (if not already cached) 205 /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
199 CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale, bool load_if_create, MathUtil::Rectangle<int>& out_rect); 206 /// 3DS memory to OpenGL and caches it (if not already cached)
207 CachedSurface* GetSurfaceRect(const CachedSurface& params, bool match_res_scale,
208 bool load_if_create, MathUtil::Rectangle<int>& out_rect);
200 209
201 /// Gets a surface based on the texture configuration 210 /// Gets a surface based on the texture configuration
202 CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); 211 CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config);
203 212
204 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer configuration 213 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
205 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config); 214 /// configuration
215 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
216 GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config);
206 217
207 /// Attempt to get a surface that exactly matches the fill region and format 218 /// Attempt to get a surface that exactly matches the fill region and format
208 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); 219 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config);
@@ -210,7 +221,8 @@ public:
210 /// Write the surface back to memory 221 /// Write the surface back to memory
211 void FlushSurface(CachedSurface* surface); 222 void FlushSurface(CachedSurface* surface);
212 223
213 /// Write any cached resources overlapping the region back to memory (if dirty) and optionally invalidate them in the cache 224 /// Write any cached resources overlapping the region back to memory (if dirty) and optionally
225 /// invalidate them in the cache
214 void FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate); 226 void FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate);
215 227
216 /// Flush all cached resources tracked by this cache manager 228 /// Flush all cached resources tracked by this cache manager
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index eb128966c..2f40eb646 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -16,19 +16,28 @@
16class OGLTexture : private NonCopyable { 16class OGLTexture : private NonCopyable {
17public: 17public:
18 OGLTexture() = default; 18 OGLTexture() = default;
19 OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); } 19 OGLTexture(OGLTexture&& o) {
20 ~OGLTexture() { Release(); } 20 std::swap(handle, o.handle);
21 OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; } 21 }
22 ~OGLTexture() {
23 Release();
24 }
25 OGLTexture& operator=(OGLTexture&& o) {
26 std::swap(handle, o.handle);
27 return *this;
28 }
22 29
23 /// Creates a new internal OpenGL resource and stores the handle 30 /// Creates a new internal OpenGL resource and stores the handle
24 void Create() { 31 void Create() {
25 if (handle != 0) return; 32 if (handle != 0)
33 return;
26 glGenTextures(1, &handle); 34 glGenTextures(1, &handle);
27 } 35 }
28 36
29 /// Deletes the internal OpenGL resource 37 /// Deletes the internal OpenGL resource
30 void Release() { 38 void Release() {
31 if (handle == 0) return; 39 if (handle == 0)
40 return;
32 glDeleteTextures(1, &handle); 41 glDeleteTextures(1, &handle);
33 OpenGLState::ResetTexture(handle); 42 OpenGLState::ResetTexture(handle);
34 handle = 0; 43 handle = 0;
@@ -40,19 +49,28 @@ public:
40class OGLSampler : private NonCopyable { 49class OGLSampler : private NonCopyable {
41public: 50public:
42 OGLSampler() = default; 51 OGLSampler() = default;
43 OGLSampler(OGLSampler&& o) { std::swap(handle, o.handle); } 52 OGLSampler(OGLSampler&& o) {
44 ~OGLSampler() { Release(); } 53 std::swap(handle, o.handle);
45 OGLSampler& operator=(OGLSampler&& o) { std::swap(handle, o.handle); return *this; } 54 }
55 ~OGLSampler() {
56 Release();
57 }
58 OGLSampler& operator=(OGLSampler&& o) {
59 std::swap(handle, o.handle);
60 return *this;
61 }
46 62
47 /// Creates a new internal OpenGL resource and stores the handle 63 /// Creates a new internal OpenGL resource and stores the handle
48 void Create() { 64 void Create() {
49 if (handle != 0) return; 65 if (handle != 0)
66 return;
50 glGenSamplers(1, &handle); 67 glGenSamplers(1, &handle);
51 } 68 }
52 69
53 /// Deletes the internal OpenGL resource 70 /// Deletes the internal OpenGL resource
54 void Release() { 71 void Release() {
55 if (handle == 0) return; 72 if (handle == 0)
73 return;
56 glDeleteSamplers(1, &handle); 74 glDeleteSamplers(1, &handle);
57 OpenGLState::ResetSampler(handle); 75 OpenGLState::ResetSampler(handle);
58 handle = 0; 76 handle = 0;
@@ -64,19 +82,28 @@ public:
64class OGLShader : private NonCopyable { 82class OGLShader : private NonCopyable {
65public: 83public:
66 OGLShader() = default; 84 OGLShader() = default;
67 OGLShader(OGLShader&& o) { std::swap(handle, o.handle); } 85 OGLShader(OGLShader&& o) {
68 ~OGLShader() { Release(); } 86 std::swap(handle, o.handle);
69 OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; } 87 }
88 ~OGLShader() {
89 Release();
90 }
91 OGLShader& operator=(OGLShader&& o) {
92 std::swap(handle, o.handle);
93 return *this;
94 }
70 95
71 /// Creates a new internal OpenGL resource and stores the handle 96 /// Creates a new internal OpenGL resource and stores the handle
72 void Create(const char* vert_shader, const char* frag_shader) { 97 void Create(const char* vert_shader, const char* frag_shader) {
73 if (handle != 0) return; 98 if (handle != 0)
99 return;
74 handle = GLShader::LoadProgram(vert_shader, frag_shader); 100 handle = GLShader::LoadProgram(vert_shader, frag_shader);
75 } 101 }
76 102
77 /// Deletes the internal OpenGL resource 103 /// Deletes the internal OpenGL resource
78 void Release() { 104 void Release() {
79 if (handle == 0) return; 105 if (handle == 0)
106 return;
80 glDeleteProgram(handle); 107 glDeleteProgram(handle);
81 OpenGLState::ResetProgram(handle); 108 OpenGLState::ResetProgram(handle);
82 handle = 0; 109 handle = 0;
@@ -88,19 +115,28 @@ public:
88class OGLBuffer : private NonCopyable { 115class OGLBuffer : private NonCopyable {
89public: 116public:
90 OGLBuffer() = default; 117 OGLBuffer() = default;
91 OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); } 118 OGLBuffer(OGLBuffer&& o) {
92 ~OGLBuffer() { Release(); } 119 std::swap(handle, o.handle);
93 OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; } 120 }
121 ~OGLBuffer() {
122 Release();
123 }
124 OGLBuffer& operator=(OGLBuffer&& o) {
125 std::swap(handle, o.handle);
126 return *this;
127 }
94 128
95 /// Creates a new internal OpenGL resource and stores the handle 129 /// Creates a new internal OpenGL resource and stores the handle
96 void Create() { 130 void Create() {
97 if (handle != 0) return; 131 if (handle != 0)
132 return;
98 glGenBuffers(1, &handle); 133 glGenBuffers(1, &handle);
99 } 134 }
100 135
101 /// Deletes the internal OpenGL resource 136 /// Deletes the internal OpenGL resource
102 void Release() { 137 void Release() {
103 if (handle == 0) return; 138 if (handle == 0)
139 return;
104 glDeleteBuffers(1, &handle); 140 glDeleteBuffers(1, &handle);
105 OpenGLState::ResetBuffer(handle); 141 OpenGLState::ResetBuffer(handle);
106 handle = 0; 142 handle = 0;
@@ -112,19 +148,28 @@ public:
112class OGLVertexArray : private NonCopyable { 148class OGLVertexArray : private NonCopyable {
113public: 149public:
114 OGLVertexArray() = default; 150 OGLVertexArray() = default;
115 OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); } 151 OGLVertexArray(OGLVertexArray&& o) {
116 ~OGLVertexArray() { Release(); } 152 std::swap(handle, o.handle);
117 OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; } 153 }
154 ~OGLVertexArray() {
155 Release();
156 }
157 OGLVertexArray& operator=(OGLVertexArray&& o) {
158 std::swap(handle, o.handle);
159 return *this;
160 }
118 161
119 /// Creates a new internal OpenGL resource and stores the handle 162 /// Creates a new internal OpenGL resource and stores the handle
120 void Create() { 163 void Create() {
121 if (handle != 0) return; 164 if (handle != 0)
165 return;
122 glGenVertexArrays(1, &handle); 166 glGenVertexArrays(1, &handle);
123 } 167 }
124 168
125 /// Deletes the internal OpenGL resource 169 /// Deletes the internal OpenGL resource
126 void Release() { 170 void Release() {
127 if (handle == 0) return; 171 if (handle == 0)
172 return;
128 glDeleteVertexArrays(1, &handle); 173 glDeleteVertexArrays(1, &handle);
129 OpenGLState::ResetVertexArray(handle); 174 OpenGLState::ResetVertexArray(handle);
130 handle = 0; 175 handle = 0;
@@ -136,19 +181,28 @@ public:
136class OGLFramebuffer : private NonCopyable { 181class OGLFramebuffer : private NonCopyable {
137public: 182public:
138 OGLFramebuffer() = default; 183 OGLFramebuffer() = default;
139 OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); } 184 OGLFramebuffer(OGLFramebuffer&& o) {
140 ~OGLFramebuffer() { Release(); } 185 std::swap(handle, o.handle);
141 OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; } 186 }
187 ~OGLFramebuffer() {
188 Release();
189 }
190 OGLFramebuffer& operator=(OGLFramebuffer&& o) {
191 std::swap(handle, o.handle);
192 return *this;
193 }
142 194
143 /// Creates a new internal OpenGL resource and stores the handle 195 /// Creates a new internal OpenGL resource and stores the handle
144 void Create() { 196 void Create() {
145 if (handle != 0) return; 197 if (handle != 0)
198 return;
146 glGenFramebuffers(1, &handle); 199 glGenFramebuffers(1, &handle);
147 } 200 }
148 201
149 /// Deletes the internal OpenGL resource 202 /// Deletes the internal OpenGL resource
150 void Release() { 203 void Release() {
151 if (handle == 0) return; 204 if (handle == 0)
205 return;
152 glDeleteFramebuffers(1, &handle); 206 glDeleteFramebuffers(1, &handle);
153 OpenGLState::ResetFramebuffer(handle); 207 OpenGLState::ResetFramebuffer(handle);
154 handle = 0; 208 handle = 0;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 3de372f67..f86cffee5 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -21,19 +21,18 @@ namespace GLShader {
21 21
22/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) 22/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
23static bool IsPassThroughTevStage(const TevStageConfig& stage) { 23static bool IsPassThroughTevStage(const TevStageConfig& stage) {
24 return (stage.color_op == TevStageConfig::Operation::Replace && 24 return (stage.color_op == TevStageConfig::Operation::Replace &&
25 stage.alpha_op == TevStageConfig::Operation::Replace && 25 stage.alpha_op == TevStageConfig::Operation::Replace &&
26 stage.color_source1 == TevStageConfig::Source::Previous && 26 stage.color_source1 == TevStageConfig::Source::Previous &&
27 stage.alpha_source1 == TevStageConfig::Source::Previous && 27 stage.alpha_source1 == TevStageConfig::Source::Previous &&
28 stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && 28 stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
29 stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && 29 stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
30 stage.GetColorMultiplier() == 1 && 30 stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
31 stage.GetAlphaMultiplier() == 1);
32} 31}
33 32
34/// Writes the specified TEV stage source component(s) 33/// Writes the specified TEV stage source component(s)
35static void AppendSource(std::string& out, const PicaShaderConfig& config, TevStageConfig::Source source, 34static void AppendSource(std::string& out, const PicaShaderConfig& config,
36 const std::string& index_name) { 35 TevStageConfig::Source source, const std::string& index_name) {
37 const auto& state = config.state; 36 const auto& state = config.state;
38 using Source = TevStageConfig::Source; 37 using Source = TevStageConfig::Source;
39 switch (source) { 38 switch (source) {
@@ -48,7 +47,7 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt
48 break; 47 break;
49 case Source::Texture0: 48 case Source::Texture0:
50 // Only unit 0 respects the texturing type (according to 3DBrew) 49 // Only unit 0 respects the texturing type (according to 3DBrew)
51 switch(state.texture0_type) { 50 switch (state.texture0_type) {
52 case Pica::Regs::TextureConfig::Texture2D: 51 case Pica::Regs::TextureConfig::Texture2D:
53 out += "texture(tex[0], texcoord[0])"; 52 out += "texture(tex[0], texcoord[0])";
54 break; 53 break;
@@ -57,7 +56,8 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt
57 break; 56 break;
58 default: 57 default:
59 out += "texture(tex[0], texcoord[0])"; 58 out += "texture(tex[0], texcoord[0])";
60 LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", static_cast<int>(state.texture0_type)); 59 LOG_CRITICAL(HW_GPU, "Unhandled texture type %x",
60 static_cast<int>(state.texture0_type));
61 UNIMPLEMENTED(); 61 UNIMPLEMENTED();
62 break; 62 break;
63 } 63 }
@@ -85,8 +85,9 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, TevSt
85} 85}
86 86
87/// Writes the color components to use for the specified TEV stage color modifier 87/// Writes the color components to use for the specified TEV stage color modifier
88static void AppendColorModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::ColorModifier modifier, 88static void AppendColorModifier(std::string& out, const PicaShaderConfig& config,
89 TevStageConfig::Source source, const std::string& index_name) { 89 TevStageConfig::ColorModifier modifier,
90 TevStageConfig::Source source, const std::string& index_name) {
90 using ColorModifier = TevStageConfig::ColorModifier; 91 using ColorModifier = TevStageConfig::ColorModifier;
91 switch (modifier) { 92 switch (modifier) {
92 case ColorModifier::SourceColor: 93 case ColorModifier::SourceColor:
@@ -142,8 +143,9 @@ static void AppendColorModifier(std::string& out, const PicaShaderConfig& config
142} 143}
143 144
144/// Writes the alpha component to use for the specified TEV stage alpha modifier 145/// Writes the alpha component to use for the specified TEV stage alpha modifier
145static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config, TevStageConfig::AlphaModifier modifier, 146static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config,
146 TevStageConfig::Source source, const std::string& index_name) { 147 TevStageConfig::AlphaModifier modifier,
148 TevStageConfig::Source source, const std::string& index_name) {
147 using AlphaModifier = TevStageConfig::AlphaModifier; 149 using AlphaModifier = TevStageConfig::AlphaModifier;
148 switch (modifier) { 150 switch (modifier) {
149 case AlphaModifier::SourceAlpha: 151 case AlphaModifier::SourceAlpha:
@@ -191,7 +193,7 @@ static void AppendAlphaModifier(std::string& out, const PicaShaderConfig& config
191 193
192/// Writes the combiner function for the color components for the specified TEV stage operation 194/// Writes the combiner function for the color components for the specified TEV stage operation
193static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, 195static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
194 const std::string& variable_name) { 196 const std::string& variable_name) {
195 out += "clamp("; 197 out += "clamp(";
196 using Operation = TevStageConfig::Operation; 198 using Operation = TevStageConfig::Operation;
197 switch (operation) { 199 switch (operation) {
@@ -208,8 +210,10 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
208 out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; 210 out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)";
209 break; 211 break;
210 case Operation::Lerp: 212 case Operation::Lerp:
211 // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp 213 // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use
212 out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; 214 // builtin lerp
215 out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
216 "[1] * (vec3(1.0) - " + variable_name + "[2])";
213 break; 217 break;
214 case Operation::Subtract: 218 case Operation::Subtract:
215 out += variable_name + "[0] - " + variable_name + "[1]"; 219 out += variable_name + "[0] - " + variable_name + "[1]";
@@ -218,10 +222,12 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
218 out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; 222 out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
219 break; 223 break;
220 case Operation::AddThenMultiply: 224 case Operation::AddThenMultiply:
221 out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; 225 out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " +
226 variable_name + "[2]";
222 break; 227 break;
223 case Operation::Dot3_RGB: 228 case Operation::Dot3_RGB:
224 out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name + "[1] - vec3(0.5)) * 4.0)"; 229 out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name +
230 "[1] - vec3(0.5)) * 4.0)";
225 break; 231 break;
226 default: 232 default:
227 out += "vec3(0.0)"; 233 out += "vec3(0.0)";
@@ -233,7 +239,7 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
233 239
234/// Writes the combiner function for the alpha component for the specified TEV stage operation 240/// Writes the combiner function for the alpha component for the specified TEV stage operation
235static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, 241static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
236 const std::string& variable_name) { 242 const std::string& variable_name) {
237 out += "clamp("; 243 out += "clamp(";
238 using Operation = TevStageConfig::Operation; 244 using Operation = TevStageConfig::Operation;
239 switch (operation) { 245 switch (operation) {
@@ -250,7 +256,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
250 out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; 256 out += variable_name + "[0] + " + variable_name + "[1] - 0.5";
251 break; 257 break;
252 case Operation::Lerp: 258 case Operation::Lerp:
253 out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; 259 out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
260 "[1] * (1.0 - " + variable_name + "[2])";
254 break; 261 break;
255 case Operation::Subtract: 262 case Operation::Subtract:
256 out += variable_name + "[0] - " + variable_name + "[1]"; 263 out += variable_name + "[0] - " + variable_name + "[1]";
@@ -259,7 +266,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
259 out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; 266 out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
260 break; 267 break;
261 case Operation::AddThenMultiply: 268 case Operation::AddThenMultiply:
262 out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; 269 out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name +
270 "[2]";
263 break; 271 break;
264 default: 272 default:
265 out += "0.0"; 273 out += "0.0";
@@ -284,9 +292,10 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
284 case CompareFunc::LessThan: 292 case CompareFunc::LessThan:
285 case CompareFunc::LessThanOrEqual: 293 case CompareFunc::LessThanOrEqual:
286 case CompareFunc::GreaterThan: 294 case CompareFunc::GreaterThan:
287 case CompareFunc::GreaterThanOrEqual: 295 case CompareFunc::GreaterThanOrEqual: {
288 { 296 static const char* op[] = {
289 static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; 297 "!=", "==", ">=", ">", "<=", "<",
298 };
290 unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; 299 unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
291 out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; 300 out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref";
292 break; 301 break;
@@ -301,7 +310,8 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
301 310
302/// Writes the code to emulate the specified TEV stage 311/// Writes the code to emulate the specified TEV stage
303static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { 312static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
304 const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); 313 const auto stage =
314 static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]);
305 if (!IsPassThroughTevStage(stage)) { 315 if (!IsPassThroughTevStage(stage)) {
306 std::string index_name = std::to_string(index); 316 std::string index_name = std::to_string(index);
307 317
@@ -330,8 +340,12 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi
330 out += ";\n"; 340 out += ";\n";
331 341
332 out += "last_tex_env_out = vec4(" 342 out += "last_tex_env_out = vec4("
333 "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," 343 "clamp(color_output_" +
334 "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; 344 index_name + " * " + std::to_string(stage.GetColorMultiplier()) +
345 ".0, vec3(0.0), vec3(1.0)),"
346 "clamp(alpha_output_" +
347 index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) +
348 ".0, 0.0, 1.0));\n";
335 } 349 }
336 350
337 out += "combiner_buffer = next_combiner_buffer;\n"; 351 out += "combiner_buffer = next_combiner_buffer;\n";
@@ -355,13 +369,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
355 369
356 // Compute fragment normals 370 // Compute fragment normals
357 if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { 371 if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
358 // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture 372 // Bump mapping is enabled using a normal map, read perturbation vector from the selected
373 // texture
359 std::string bump_selector = std::to_string(lighting.bump_selector); 374 std::string bump_selector = std::to_string(lighting.bump_selector);
360 out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; 375 out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" +
376 bump_selector + "]).rgb - 1.0;\n";
361 377
362 // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result 378 // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher
379 // precision result
363 if (lighting.bump_renorm) { 380 if (lighting.bump_renorm) {
364 std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; 381 std::string val =
382 "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
365 out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; 383 out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
366 } 384 }
367 } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { 385 } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
@@ -373,7 +391,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
373 out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"; 391 out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
374 } 392 }
375 393
376 // Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace 394 // Rotate the surface-local normal by the interpolated normal quaternion to convert it to
395 // eyespace
377 out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; 396 out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
378 397
379 // Gets the index into the specified lookup table for specular lighting 398 // Gets the index into the specified lookup table for specular lighting
@@ -406,12 +425,14 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
406 425
407 if (abs) { 426 if (abs) {
408 // LUT index is in the range of (0.0, 1.0) 427 // LUT index is in the range of (0.0, 1.0)
409 index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; 428 index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")"
429 : "max(" + index + ", 0.f)";
410 return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; 430 return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))";
411 } else { 431 } else {
412 // LUT index is in the range of (-1.0, 1.0) 432 // LUT index is in the range of (-1.0, 1.0)
413 index = "clamp(" + index + ", -1.0, 1.0)"; 433 index = "clamp(" + index + ", -1.0, 1.0)";
414 return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0)"; 434 return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index +
435 ") / 2.0)";
415 } 436 }
416 437
417 return std::string(); 438 return std::string();
@@ -434,52 +455,74 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
434 else 455 else
435 out += "light_vector = normalize(" + light_src + ".position + view);\n"; 456 out += "light_vector = normalize(" + light_src + ".position + view);\n";
436 457
437 // Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided 458 // Compute dot product of light_vector and normal, adjust if lighting is one-sided or
438 std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)"; 459 // two-sided
460 std::string dot_product = light_config.two_sided_diffuse
461 ? "abs(dot(light_vector, normal))"
462 : "max(dot(light_vector, normal), 0.0)";
439 463
440 // If enabled, compute distance attenuation value 464 // If enabled, compute distance attenuation value
441 std::string dist_atten = "1.0"; 465 std::string dist_atten = "1.0";
442 if (light_config.dist_atten_enable) { 466 if (light_config.dist_atten_enable) {
443 std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + light_src + ".position) + " + light_src + ".dist_atten_bias)"; 467 std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " +
468 light_src + ".position) + " + light_src + ".dist_atten_bias)";
444 index = "((clamp(" + index + ", 0.0, FLOAT_255)))"; 469 index = "((clamp(" + index + ", 0.0, FLOAT_255)))";
445 const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); 470 const unsigned lut_num =
471 ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
446 dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); 472 dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
447 } 473 }
448 474
449 // If enabled, clamp specular component if lighting result is negative 475 // If enabled, clamp specular component if lighting result is negative
450 std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; 476 std::string clamp_highlights =
477 lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0";
451 478
452 // Specular 0 component 479 // Specular 0 component
453 std::string d0_lut_value = "1.0"; 480 std::string d0_lut_value = "1.0";
454 if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) { 481 if (lighting.lut_d0.enable &&
482 Pica::Regs::IsLightingSamplerSupported(lighting.config,
483 Pica::Regs::LightingSampler::Distribution0)) {
455 // Lookup specular "distribution 0" LUT value 484 // Lookup specular "distribution 0" LUT value
456 std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); 485 std::string index =
457 d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; 486 GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
487 d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " +
488 GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
458 } 489 }
459 std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; 490 std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
460 491
461 // If enabled, lookup ReflectRed value, otherwise, 1.0 is used 492 // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
462 if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) { 493 if (lighting.lut_rr.enable &&
463 std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); 494 Pica::Regs::IsLightingSamplerSupported(lighting.config,
464 std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; 495 Pica::Regs::LightingSampler::ReflectRed)) {
496 std::string index =
497 GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
498 std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " +
499 GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
465 out += "refl_value.r = " + value + ";\n"; 500 out += "refl_value.r = " + value + ";\n";
466 } else { 501 } else {
467 out += "refl_value.r = 1.0;\n"; 502 out += "refl_value.r = 1.0;\n";
468 } 503 }
469 504
470 // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used 505 // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
471 if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) { 506 if (lighting.lut_rg.enable &&
472 std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); 507 Pica::Regs::IsLightingSamplerSupported(lighting.config,
473 std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; 508 Pica::Regs::LightingSampler::ReflectGreen)) {
509 std::string index =
510 GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
511 std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " +
512 GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
474 out += "refl_value.g = " + value + ";\n"; 513 out += "refl_value.g = " + value + ";\n";
475 } else { 514 } else {
476 out += "refl_value.g = refl_value.r;\n"; 515 out += "refl_value.g = refl_value.r;\n";
477 } 516 }
478 517
479 // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used 518 // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
480 if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) { 519 if (lighting.lut_rb.enable &&
481 std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); 520 Pica::Regs::IsLightingSamplerSupported(lighting.config,
482 std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; 521 Pica::Regs::LightingSampler::ReflectBlue)) {
522 std::string index =
523 GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
524 std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " +
525 GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
483 out += "refl_value.b = " + value + ";\n"; 526 out += "refl_value.b = " + value + ";\n";
484 } else { 527 } else {
485 out += "refl_value.b = refl_value.r;\n"; 528 out += "refl_value.b = refl_value.r;\n";
@@ -487,18 +530,26 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
487 530
488 // Specular 1 component 531 // Specular 1 component
489 std::string d1_lut_value = "1.0"; 532 std::string d1_lut_value = "1.0";
490 if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) { 533 if (lighting.lut_d1.enable &&
534 Pica::Regs::IsLightingSamplerSupported(lighting.config,
535 Pica::Regs::LightingSampler::Distribution1)) {
491 // Lookup specular "distribution 1" LUT value 536 // Lookup specular "distribution 1" LUT value
492 std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); 537 std::string index =
493 d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; 538 GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
539 d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " +
540 GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
494 } 541 }
495 std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; 542 std::string specular_1 =
543 "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
496 544
497 // Fresnel 545 // Fresnel
498 if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) { 546 if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(
547 lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
499 // Lookup fresnel LUT value 548 // Lookup fresnel LUT value
500 std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); 549 std::string index =
501 std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; 550 GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
551 std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " +
552 GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
502 553
503 // Enabled for difffuse lighting alpha component 554 // Enabled for difffuse lighting alpha component
504 if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || 555 if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
@@ -512,10 +563,12 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
512 } 563 }
513 564
514 // Compute primary fragment color (diffuse lighting) function 565 // Compute primary fragment color (diffuse lighting) function
515 out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n"; 566 out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " +
567 light_src + ".ambient) * " + dist_atten + ";\n";
516 568
517 // Compute secondary fragment color (specular lighting) function 569 // Compute secondary fragment color (specular lighting) function
518 out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + clamp_highlights + " * " + dist_atten + ";\n"; 570 out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " +
571 clamp_highlights + " * " + dist_atten + ";\n";
519 } 572 }
520 573
521 // Sum final lighting result 574 // Sum final lighting result
@@ -598,9 +651,9 @@ vec4 secondary_fragment_color = vec4(0.0);
598 out += "!"; 651 out += "!";
599 // x2,y2 have +1 added to cover the entire pixel area 652 // x2,y2 have +1 added to cover the entire pixel area
600 out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " 653 out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && "
601 "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " 654 "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && "
602 "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " 655 "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && "
603 "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; 656 "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n";
604 } 657 }
605 658
606 out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; 659 out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
@@ -638,9 +691,11 @@ vec4 secondary_fragment_color = vec4(0.0);
638 out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"; 691 out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n";
639 out += "float fog_f = fog_index - fog_i;\n"; 692 out += "float fog_f = fog_index - fog_i;\n";
640 out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n"; 693 out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n";
641 out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> 19);\n"; // Extract signed difference 694 out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> "
695 "19);\n"; // Extract signed difference
642 out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n"; 696 out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n";
643 out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / 2047.0;\n"; 697 out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / "
698 "2047.0;\n";
644 out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n"; 699 out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n";
645 700
646 // Blend the fog 701 // Blend the fog
@@ -658,14 +713,20 @@ vec4 secondary_fragment_color = vec4(0.0);
658std::string GenerateVertexShader() { 713std::string GenerateVertexShader() {
659 std::string out = "#version 330 core\n"; 714 std::string out = "#version 330 core\n";
660 715
661 out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; 716 out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) +
662 out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; 717 ") in vec4 vert_position;\n";
663 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; 718 out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
664 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; 719 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) +
665 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; 720 ") in vec2 vert_texcoord0;\n";
666 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) + ") in float vert_texcoord0_w;\n"; 721 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) +
667 out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n"; 722 ") in vec2 vert_texcoord1;\n";
668 out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; 723 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) +
724 ") in vec2 vert_texcoord2;\n";
725 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) +
726 ") in float vert_texcoord0_w;\n";
727 out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) +
728 ") in vec4 vert_normquat;\n";
729 out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
669 730
670 out += R"( 731 out += R"(
671out vec4 primary_color; 732out vec4 primary_color;
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index dded3db46..7d90ec6a3 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -56,7 +56,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
56 if (result) { 56 if (result) {
57 LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); 57 LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
58 } else { 58 } else {
59 LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", &fragment_shader_error[0]); 59 LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s",
60 &fragment_shader_error[0]);
60 } 61 }
61 } 62 }
62 63
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 13ee986b9..a97269d44 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -106,11 +106,11 @@ void OpenGLState::Apply() const {
106 106
107 // Color mask 107 // Color mask
108 if (color_mask.red_enabled != cur_state.color_mask.red_enabled || 108 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
109 color_mask.green_enabled != cur_state.color_mask.green_enabled || 109 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
110 color_mask.blue_enabled != cur_state.color_mask.blue_enabled || 110 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
111 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { 111 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
112 glColorMask(color_mask.red_enabled, color_mask.green_enabled, 112 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
113 color_mask.blue_enabled, color_mask.alpha_enabled); 113 color_mask.alpha_enabled);
114 } 114 }
115 115
116 // Stencil test 116 // Stencil test
@@ -123,15 +123,16 @@ void OpenGLState::Apply() const {
123 } 123 }
124 124
125 if (stencil.test_func != cur_state.stencil.test_func || 125 if (stencil.test_func != cur_state.stencil.test_func ||
126 stencil.test_ref != cur_state.stencil.test_ref || 126 stencil.test_ref != cur_state.stencil.test_ref ||
127 stencil.test_mask != cur_state.stencil.test_mask) { 127 stencil.test_mask != cur_state.stencil.test_mask) {
128 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); 128 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
129 } 129 }
130 130
131 if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || 131 if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail ||
132 stencil.action_depth_pass != cur_state.stencil.action_depth_pass || 132 stencil.action_depth_pass != cur_state.stencil.action_depth_pass ||
133 stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { 133 stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) {
134 glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); 134 glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail,
135 stencil.action_depth_pass);
135 } 136 }
136 137
137 // Stencil mask 138 // Stencil mask
@@ -154,23 +155,22 @@ void OpenGLState::Apply() const {
154 } 155 }
155 156
156 if (blend.color.red != cur_state.blend.color.red || 157 if (blend.color.red != cur_state.blend.color.red ||
157 blend.color.green != cur_state.blend.color.green || 158 blend.color.green != cur_state.blend.color.green ||
158 blend.color.blue != cur_state.blend.color.blue || 159 blend.color.blue != cur_state.blend.color.blue ||
159 blend.color.alpha != cur_state.blend.color.alpha) { 160 blend.color.alpha != cur_state.blend.color.alpha) {
160 glBlendColor(blend.color.red, blend.color.green, 161 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
161 blend.color.blue, blend.color.alpha);
162 } 162 }
163 163
164 if (blend.src_rgb_func != cur_state.blend.src_rgb_func || 164 if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
165 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 165 blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
166 blend.src_a_func != cur_state.blend.src_a_func || 166 blend.src_a_func != cur_state.blend.src_a_func ||
167 blend.dst_a_func != cur_state.blend.dst_a_func) { 167 blend.dst_a_func != cur_state.blend.dst_a_func) {
168 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, 168 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
169 blend.src_a_func, blend.dst_a_func); 169 blend.dst_a_func);
170 } 170 }
171 171
172 if (blend.rgb_equation != cur_state.blend.rgb_equation || 172 if (blend.rgb_equation != cur_state.blend.rgb_equation ||
173 blend.a_equation != cur_state.blend.a_equation) { 173 blend.a_equation != cur_state.blend.a_equation) {
174 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); 174 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
175 } 175 }
176 176
@@ -237,8 +237,11 @@ void OpenGLState::Apply() const {
237GLenum OpenGLState::CheckFBStatus(GLenum target) { 237GLenum OpenGLState::CheckFBStatus(GLenum target) {
238 GLenum fb_status = glCheckFramebufferStatus(target); 238 GLenum fb_status = glCheckFramebufferStatus(target);
239 if (fb_status != GL_FRAMEBUFFER_COMPLETE) { 239 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
240 const char* fb_description = (target == GL_READ_FRAMEBUFFER ? "READ" : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK")); 240 const char* fb_description =
241 LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description, fb_status); 241 (target == GL_READ_FRAMEBUFFER ? "READ"
242 : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK"));
243 LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description,
244 fb_status);
242 } 245 }
243 246
244 return fb_status; 247 return fb_status;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 13c71b0a6..01dead883 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -9,14 +9,14 @@
9class OpenGLState { 9class OpenGLState {
10public: 10public:
11 struct { 11 struct {
12 bool enabled; // GL_CULL_FACE 12 bool enabled; // GL_CULL_FACE
13 GLenum mode; // GL_CULL_FACE_MODE 13 GLenum mode; // GL_CULL_FACE_MODE
14 GLenum front_face; // GL_FRONT_FACE 14 GLenum front_face; // GL_FRONT_FACE
15 } cull; 15 } cull;
16 16
17 struct { 17 struct {
18 bool test_enabled; // GL_DEPTH_TEST 18 bool test_enabled; // GL_DEPTH_TEST
19 GLenum test_func; // GL_DEPTH_FUNC 19 GLenum test_func; // GL_DEPTH_FUNC
20 GLboolean write_mask; // GL_DEPTH_WRITEMASK 20 GLboolean write_mask; // GL_DEPTH_WRITEMASK
21 } depth; 21 } depth;
22 22
@@ -28,24 +28,24 @@ public:
28 } color_mask; // GL_COLOR_WRITEMASK 28 } color_mask; // GL_COLOR_WRITEMASK
29 29
30 struct { 30 struct {
31 bool test_enabled; // GL_STENCIL_TEST 31 bool test_enabled; // GL_STENCIL_TEST
32 GLenum test_func; // GL_STENCIL_FUNC 32 GLenum test_func; // GL_STENCIL_FUNC
33 GLint test_ref; // GL_STENCIL_REF 33 GLint test_ref; // GL_STENCIL_REF
34 GLuint test_mask; // GL_STENCIL_VALUE_MASK 34 GLuint test_mask; // GL_STENCIL_VALUE_MASK
35 GLuint write_mask; // GL_STENCIL_WRITEMASK 35 GLuint write_mask; // GL_STENCIL_WRITEMASK
36 GLenum action_stencil_fail; // GL_STENCIL_FAIL 36 GLenum action_stencil_fail; // GL_STENCIL_FAIL
37 GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL 37 GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL
38 GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS 38 GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS
39 } stencil; 39 } stencil;
40 40
41 struct { 41 struct {
42 bool enabled; // GL_BLEND 42 bool enabled; // GL_BLEND
43 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 43 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
44 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 44 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
45 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 45 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
46 GLenum dst_rgb_func; // GL_BLEND_DST_RGB 46 GLenum dst_rgb_func; // GL_BLEND_DST_RGB
47 GLenum src_a_func; // GL_BLEND_SRC_ALPHA 47 GLenum src_a_func; // GL_BLEND_SRC_ALPHA
48 GLenum dst_a_func; // GL_BLEND_DST_ALPHA 48 GLenum dst_a_func; // GL_BLEND_DST_ALPHA
49 49
50 struct { 50 struct {
51 GLclampf red; 51 GLclampf red;
@@ -60,7 +60,7 @@ public:
60 // 3 texture units - one for each that is used in PICA fragment shader emulation 60 // 3 texture units - one for each that is used in PICA fragment shader emulation
61 struct { 61 struct {
62 GLuint texture_2d; // GL_TEXTURE_BINDING_2D 62 GLuint texture_2d; // GL_TEXTURE_BINDING_2D
63 GLuint sampler; // GL_SAMPLER_BINDING 63 GLuint sampler; // GL_SAMPLER_BINDING
64 } texture_units[3]; 64 } texture_units[3];
65 65
66 struct { 66 struct {
@@ -74,10 +74,10 @@ public:
74 struct { 74 struct {
75 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING 75 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
76 GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING 76 GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
77 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING 77 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
78 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING 78 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
79 GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING 79 GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
80 GLuint shader_program; // GL_CURRENT_PROGRAM 80 GLuint shader_program; // GL_CURRENT_PROGRAM
81 } draw; 81 } draw;
82 82
83 OpenGLState(); 83 OpenGLState();
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index d9b9c9cc2..a604e94d4 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -25,8 +25,8 @@ namespace PicaToGL {
25 25
26inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { 26inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
27 static const GLenum filter_mode_table[] = { 27 static const GLenum filter_mode_table[] = {
28 GL_NEAREST, // TextureFilter::Nearest 28 GL_NEAREST, // TextureFilter::Nearest
29 GL_LINEAR // TextureFilter::Linear 29 GL_LINEAR // TextureFilter::Linear
30 }; 30 };
31 31
32 // Range check table for input 32 // Range check table for input
@@ -52,10 +52,10 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
52 52
53inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { 53inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
54 static const GLenum wrap_mode_table[] = { 54 static const GLenum wrap_mode_table[] = {
55 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge 55 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
56 GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder 56 GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
57 GL_REPEAT, // WrapMode::Repeat 57 GL_REPEAT, // WrapMode::Repeat
58 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat 58 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat
59 }; 59 };
60 60
61 // Range check table for input 61 // Range check table for input
@@ -131,22 +131,22 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
131 131
132inline GLenum LogicOp(Pica::Regs::LogicOp op) { 132inline GLenum LogicOp(Pica::Regs::LogicOp op) {
133 static const GLenum logic_op_table[] = { 133 static const GLenum logic_op_table[] = {
134 GL_CLEAR, // Clear 134 GL_CLEAR, // Clear
135 GL_AND, // And 135 GL_AND, // And
136 GL_AND_REVERSE, // AndReverse 136 GL_AND_REVERSE, // AndReverse
137 GL_COPY, // Copy 137 GL_COPY, // Copy
138 GL_SET, // Set 138 GL_SET, // Set
139 GL_COPY_INVERTED, // CopyInverted 139 GL_COPY_INVERTED, // CopyInverted
140 GL_NOOP, // NoOp 140 GL_NOOP, // NoOp
141 GL_INVERT, // Invert 141 GL_INVERT, // Invert
142 GL_NAND, // Nand 142 GL_NAND, // Nand
143 GL_OR, // Or 143 GL_OR, // Or
144 GL_NOR, // Nor 144 GL_NOR, // Nor
145 GL_XOR, // Xor 145 GL_XOR, // Xor
146 GL_EQUIV, // Equiv 146 GL_EQUIV, // Equiv
147 GL_AND_INVERTED, // AndInverted 147 GL_AND_INVERTED, // AndInverted
148 GL_OR_REVERSE, // OrReverse 148 GL_OR_REVERSE, // OrReverse
149 GL_OR_INVERTED, // OrInverted 149 GL_OR_INVERTED, // OrInverted
150 }; 150 };
151 151
152 // Range check table for input 152 // Range check table for input
@@ -185,14 +185,14 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
185 185
186inline GLenum StencilOp(Pica::Regs::StencilAction action) { 186inline GLenum StencilOp(Pica::Regs::StencilAction action) {
187 static const GLenum stencil_op_table[] = { 187 static const GLenum stencil_op_table[] = {
188 GL_KEEP, // StencilAction::Keep 188 GL_KEEP, // StencilAction::Keep
189 GL_ZERO, // StencilAction::Zero 189 GL_ZERO, // StencilAction::Zero
190 GL_REPLACE, // StencilAction::Replace 190 GL_REPLACE, // StencilAction::Replace
191 GL_INCR, // StencilAction::Increment 191 GL_INCR, // StencilAction::Increment
192 GL_DECR, // StencilAction::Decrement 192 GL_DECR, // StencilAction::Decrement
193 GL_INVERT, // StencilAction::Invert 193 GL_INVERT, // StencilAction::Invert
194 GL_INCR_WRAP, // StencilAction::IncrementWrap 194 GL_INCR_WRAP, // StencilAction::IncrementWrap
195 GL_DECR_WRAP // StencilAction::DecrementWrap 195 GL_DECR_WRAP // StencilAction::DecrementWrap
196 }; 196 };
197 197
198 // Range check table for input 198 // Range check table for input
@@ -207,18 +207,12 @@ inline GLenum StencilOp(Pica::Regs::StencilAction action) {
207} 207}
208 208
209inline GLvec4 ColorRGBA8(const u32 color) { 209inline GLvec4 ColorRGBA8(const u32 color) {
210 return { { (color >> 0 & 0xFF) / 255.0f, 210 return {{(color >> 0 & 0xFF) / 255.0f, (color >> 8 & 0xFF) / 255.0f,
211 (color >> 8 & 0xFF) / 255.0f, 211 (color >> 16 & 0xFF) / 255.0f, (color >> 24 & 0xFF) / 255.0f}};
212 (color >> 16 & 0xFF) / 255.0f,
213 (color >> 24 & 0xFF) / 255.0f
214 } };
215} 212}
216 213
217inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { 214inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) {
218 return { { color.r / 255.0f, 215 return {{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}};
219 color.g / 255.0f,
220 color.b / 255.0f
221 } };
222} 216}
223 217
224} // namespace 218} // namespace
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8410e0a64..3cabda8f9 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -89,8 +89,12 @@ struct ScreenRectVertex {
89static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) { 89static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) {
90 std::array<GLfloat, 3 * 2> matrix; 90 std::array<GLfloat, 3 * 2> matrix;
91 91
92 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; 92 matrix[0] = 2.f / width;
93 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; 93 matrix[2] = 0.f;
94 matrix[4] = -1.f;
95 matrix[1] = 0.f;
96 matrix[3] = -2.f / height;
97 matrix[5] = 1.f;
94 // Last matrix row is implicitly assumed to be [0, 0, 1]. 98 // Last matrix row is implicitly assumed to be [0, 0, 1].
95 99
96 return matrix; 100 return matrix;
@@ -98,7 +102,7 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
98 102
99/// RendererOpenGL constructor 103/// RendererOpenGL constructor
100RendererOpenGL::RendererOpenGL() { 104RendererOpenGL::RendererOpenGL() {
101 resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); 105 resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
102 resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; 106 resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
103} 107}
104 108
@@ -116,13 +120,15 @@ void RendererOpenGL::SwapBuffers() {
116 const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; 120 const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
117 121
118 // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 122 // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04
119 u32 lcd_color_addr = (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); 123 u32 lcd_color_addr =
124 (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
120 lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; 125 lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr;
121 LCD::Regs::ColorFill color_fill = {0}; 126 LCD::Regs::ColorFill color_fill = {0};
122 LCD::Read(color_fill.raw, lcd_color_addr); 127 LCD::Read(color_fill.raw, lcd_color_addr);
123 128
124 if (color_fill.is_enabled) { 129 if (color_fill.is_enabled) {
125 LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i].texture); 130 LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b,
131 screen_infos[i].texture);
126 132
127 // Resize the texture in case the framebuffer size has changed 133 // Resize the texture in case the framebuffer size has changed
128 screen_infos[i].texture.width = 1; 134 screen_infos[i].texture.width = 1;
@@ -172,15 +178,14 @@ void RendererOpenGL::SwapBuffers() {
172 * Loads framebuffer from emulated memory into the active OpenGL texture. 178 * Loads framebuffer from emulated memory into the active OpenGL texture.
173 */ 179 */
174void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, 180void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
175 ScreenInfo& screen_info) { 181 ScreenInfo& screen_info) {
176 182
177 const PAddr framebuffer_addr = framebuffer.active_fb == 0 ? 183 const PAddr framebuffer_addr =
178 framebuffer.address_left1 : framebuffer.address_left2; 184 framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
179 185
180 LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", 186 LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
181 framebuffer.stride * framebuffer.height, 187 framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width,
182 framebuffer_addr, (int)framebuffer.width, 188 (int)framebuffer.height, (int)framebuffer.format);
183 (int)framebuffer.height, (int)framebuffer.format);
184 189
185 int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format); 190 int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
186 size_t pixel_stride = framebuffer.stride / bpp; 191 size_t pixel_stride = framebuffer.stride / bpp;
@@ -192,7 +197,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
192 // only allows rows to have a memory alignement of 4. 197 // only allows rows to have a memory alignement of 4.
193 ASSERT(pixel_stride % 4 == 0); 198 ASSERT(pixel_stride % 4 == 0);
194 199
195 if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride), screen_info)) { 200 if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr,
201 static_cast<u32>(pixel_stride), screen_info)) {
196 // Reset the screen info's display texture to its own permanent texture 202 // Reset the screen info's display texture to its own permanent texture
197 screen_info.display_texture = screen_info.texture.resource.handle; 203 screen_info.display_texture = screen_info.texture.resource.handle;
198 screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f); 204 screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
@@ -208,12 +214,14 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
208 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); 214 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
209 215
210 // Update existing texture 216 // Update existing texture
211 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they 217 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
218 // they
212 // differ from the LCD resolution. 219 // differ from the LCD resolution.
213 // TODO: Applications could theoretically crash Citra here by specifying too large 220 // TODO: Applications could theoretically crash Citra here by specifying too large
214 // framebuffer sizes. We should make sure that this cannot happen. 221 // framebuffer sizes. We should make sure that this cannot happen.
215 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, 222 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
216 screen_info.texture.gl_format, screen_info.texture.gl_type, framebuffer_data); 223 screen_info.texture.gl_format, screen_info.texture.gl_type,
224 framebuffer_data);
217 225
218 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 226 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
219 227
@@ -224,7 +232,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
224 232
225/** 233/**
226 * Fills active OpenGL texture with the given RGB color. 234 * Fills active OpenGL texture with the given RGB color.
227 * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered on. 235 * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered
236 * on.
228 * This has the added benefit of being *really fast*. 237 * This has the added benefit of being *really fast*.
229 */ 238 */
230void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, 239void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b,
@@ -233,7 +242,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
233 state.Apply(); 242 state.Apply();
234 243
235 glActiveTexture(GL_TEXTURE0); 244 glActiveTexture(GL_TEXTURE0);
236 u8 framebuffer_data[3] = { color_r, color_g, color_b }; 245 u8 framebuffer_data[3] = {color_r, color_g, color_b};
237 246
238 // Update existing texture 247 // Update existing texture
239 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data); 248 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data);
@@ -246,7 +255,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
246 * Initializes the OpenGL state and creates persistent objects. 255 * Initializes the OpenGL state and creates persistent objects.
247 */ 256 */
248void RendererOpenGL::InitOpenGLObjects() { 257void RendererOpenGL::InitOpenGLObjects() {
249 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); 258 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
259 0.0f);
250 260
251 // Link shaders and get variable locations 261 // Link shaders and get variable locations
252 shader.Create(vertex_shader, fragment_shader); 262 shader.Create(vertex_shader, fragment_shader);
@@ -270,8 +280,10 @@ void RendererOpenGL::InitOpenGLObjects() {
270 280
271 // Attach vertex data to VAO 281 // Attach vertex data to VAO
272 glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); 282 glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
273 glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position)); 283 glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
274 glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); 284 (GLvoid*)offsetof(ScreenRectVertex, position));
285 glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
286 (GLvoid*)offsetof(ScreenRectVertex, tex_coord));
275 glEnableVertexAttribArray(attrib_position); 287 glEnableVertexAttribArray(attrib_position);
276 glEnableVertexAttribArray(attrib_tex_coord); 288 glEnableVertexAttribArray(attrib_tex_coord);
277 289
@@ -352,23 +364,25 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
352 364
353 glActiveTexture(GL_TEXTURE0); 365 glActiveTexture(GL_TEXTURE0);
354 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 366 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
355 texture.gl_format, texture.gl_type, nullptr); 367 texture.gl_format, texture.gl_type, nullptr);
356 368
357 state.texture_units[0].texture_2d = 0; 369 state.texture_units[0].texture_2d = 0;
358 state.Apply(); 370 state.Apply();
359} 371}
360 372
361/** 373/**
362 * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. 374 * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
375 * rotation.
363 */ 376 */
364void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h) { 377void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y,
378 float w, float h) {
365 auto& texcoords = screen_info.display_texcoords; 379 auto& texcoords = screen_info.display_texcoords;
366 380
367 std::array<ScreenRectVertex, 4> vertices = {{ 381 std::array<ScreenRectVertex, 4> vertices = {{
368 ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), 382 ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
369 ScreenRectVertex(x+w, y, texcoords.bottom, texcoords.right), 383 ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
370 ScreenRectVertex(x, y+h, texcoords.top, texcoords.left), 384 ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
371 ScreenRectVertex(x+w, y+h, texcoords.top, texcoords.right), 385 ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
372 }}; 386 }};
373 387
374 state.texture_units[0].texture_2d = screen_info.display_texture; 388 state.texture_units[0].texture_2d = screen_info.display_texture;
@@ -391,18 +405,20 @@ void RendererOpenGL::DrawScreens() {
391 glClear(GL_COLOR_BUFFER_BIT); 405 glClear(GL_COLOR_BUFFER_BIT);
392 406
393 // Set projection matrix 407 // Set projection matrix
394 std::array<GLfloat, 3 * 2> ortho_matrix = MakeOrthographicMatrix((float)layout.width, 408 std::array<GLfloat, 3 * 2> ortho_matrix =
395 (float)layout.height); 409 MakeOrthographicMatrix((float)layout.width, (float)layout.height);
396 glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); 410 glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
397 411
398 // Bind texture in Texture Unit 0 412 // Bind texture in Texture Unit 0
399 glActiveTexture(GL_TEXTURE0); 413 glActiveTexture(GL_TEXTURE0);
400 glUniform1i(uniform_color_texture, 0); 414 glUniform1i(uniform_color_texture, 0);
401 415
402 DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, (float)layout.top_screen.top, 416 DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left,
403 (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight()); 417 (float)layout.top_screen.top, (float)layout.top_screen.GetWidth(),
404 DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top, 418 (float)layout.top_screen.GetHeight());
405 (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight()); 419 DrawSingleScreenRotated(screen_infos[1], (float)layout.bottom_screen.left,
420 (float)layout.bottom_screen.top, (float)layout.bottom_screen.GetWidth(),
421 (float)layout.bottom_screen.GetHeight());
406 422
407 m_current_frame++; 423 m_current_frame++;
408} 424}
@@ -420,14 +436,16 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
420} 436}
421 437
422static const char* GetSource(GLenum source) { 438static const char* GetSource(GLenum source) {
423#define RET(s) case GL_DEBUG_SOURCE_##s: return #s 439#define RET(s) \
440 case GL_DEBUG_SOURCE_##s: \
441 return #s
424 switch (source) { 442 switch (source) {
425 RET(API); 443 RET(API);
426 RET(WINDOW_SYSTEM); 444 RET(WINDOW_SYSTEM);
427 RET(SHADER_COMPILER); 445 RET(SHADER_COMPILER);
428 RET(THIRD_PARTY); 446 RET(THIRD_PARTY);
429 RET(APPLICATION); 447 RET(APPLICATION);
430 RET(OTHER); 448 RET(OTHER);
431 default: 449 default:
432 UNREACHABLE(); 450 UNREACHABLE();
433 } 451 }
@@ -435,23 +453,25 @@ static const char* GetSource(GLenum source) {
435} 453}
436 454
437static const char* GetType(GLenum type) { 455static const char* GetType(GLenum type) {
438#define RET(t) case GL_DEBUG_TYPE_##t: return #t 456#define RET(t) \
457 case GL_DEBUG_TYPE_##t: \
458 return #t
439 switch (type) { 459 switch (type) {
440 RET(ERROR); 460 RET(ERROR);
441 RET(DEPRECATED_BEHAVIOR); 461 RET(DEPRECATED_BEHAVIOR);
442 RET(UNDEFINED_BEHAVIOR); 462 RET(UNDEFINED_BEHAVIOR);
443 RET(PORTABILITY); 463 RET(PORTABILITY);
444 RET(PERFORMANCE); 464 RET(PERFORMANCE);
445 RET(OTHER); 465 RET(OTHER);
446 RET(MARKER); 466 RET(MARKER);
447 default: 467 default:
448 UNREACHABLE(); 468 UNREACHABLE();
449 } 469 }
450#undef RET 470#undef RET
451} 471}
452 472
453static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, 473static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
454 const GLchar* message, const void* user_param) { 474 GLsizei length, const GLchar* message, const void* user_param) {
455 Log::Level level; 475 Log::Level level;
456 switch (severity) { 476 switch (severity) {
457 case GL_DEBUG_SEVERITY_HIGH: 477 case GL_DEBUG_SEVERITY_HIGH:
@@ -465,8 +485,8 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
465 level = Log::Level::Debug; 485 level = Log::Level::Debug;
466 break; 486 break;
467 } 487 }
468 LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", 488 LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type),
469 GetSource(source), GetType(type), id, message); 489 id, message);
470} 490}
471 491
472/// Initialize the renderer 492/// Initialize the renderer
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 00e1044ab..faeb519ec 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -38,7 +38,6 @@ struct ScreenInfo {
38 38
39class RendererOpenGL : public RendererBase { 39class RendererOpenGL : public RendererBase {
40public: 40public:
41
42 RendererOpenGL(); 41 RendererOpenGL();
43 ~RendererOpenGL() override; 42 ~RendererOpenGL() override;
44 43
@@ -67,15 +66,14 @@ private:
67 66
68 // Loads framebuffer from emulated memory into the display information structure 67 // Loads framebuffer from emulated memory into the display information structure
69 void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, 68 void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
70 ScreenInfo& screen_info); 69 ScreenInfo& screen_info);
71 // Fills active OpenGL texture with the given RGB color. 70 // Fills active OpenGL texture with the given RGB color.
72 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, 71 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
73 const TextureInfo& texture);
74 72
75 EmuWindow* render_window; ///< Handle to render window 73 EmuWindow* render_window; ///< Handle to render window
76 74
77 int resolution_width; ///< Current resolution width 75 int resolution_width; ///< Current resolution width
78 int resolution_height; ///< Current resolution height 76 int resolution_height; ///< Current resolution height
79 77
80 OpenGLState state; 78 OpenGLState state;
81 79
@@ -83,7 +81,8 @@ private:
83 OGLVertexArray vertex_array; 81 OGLVertexArray vertex_array;
84 OGLBuffer vertex_buffer; 82 OGLBuffer vertex_buffer;
85 OGLShader shader; 83 OGLShader shader;
86 std::array<ScreenInfo, 2> screen_infos; ///< Display information for top and bottom screens respectively 84 std::array<ScreenInfo, 2>
85 screen_infos; ///< Display information for top and bottom screens respectively
87 // Shader uniform location indices 86 // Shader uniform location indices
88 GLuint uniform_modelview_matrix; 87 GLuint uniform_modelview_matrix;
89 GLuint uniform_color_texture; 88 GLuint uniform_color_texture;