diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 42 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.cpp | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 5 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | 8 |
9 files changed, 50 insertions, 82 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e43ba9d6b..05f8e511b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -257,10 +257,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 257 | continue; | 257 | continue; |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 | ||
| 261 | |||
| 262 | GLShader::MaxwellUniformData ubo{}; | 260 | GLShader::MaxwellUniformData ubo{}; |
| 263 | ubo.SetFromRegs(gpu, stage); | 261 | ubo.SetFromRegs(gpu); |
| 264 | const auto [buffer, offset] = | 262 | const auto [buffer, offset] = |
| 265 | buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment()); | 263 | buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment()); |
| 266 | 264 | ||
| @@ -269,10 +267,11 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 269 | 267 | ||
| 270 | Shader shader{shader_cache.GetStageProgram(program)}; | 268 | Shader shader{shader_cache.GetStageProgram(program)}; |
| 271 | 269 | ||
| 272 | const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); | 270 | // Stage indices are 0 - 5 |
| 273 | SetupDrawConstBuffers(stage_enum, shader); | 271 | const auto stage = static_cast<Maxwell::ShaderStage>(index == 0 ? 0 : index - 1); |
| 274 | SetupDrawGlobalMemory(stage_enum, shader); | 272 | SetupDrawConstBuffers(stage, shader); |
| 275 | const auto texture_buffer_usage{SetupDrawTextures(stage_enum, shader, base_bindings)}; | 273 | SetupDrawGlobalMemory(stage, shader); |
| 274 | const auto texture_buffer_usage{SetupDrawTextures(stage, shader, base_bindings)}; | ||
| 276 | 275 | ||
| 277 | const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; | 276 | const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; |
| 278 | const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); | 277 | const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); |
| @@ -1055,6 +1054,15 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | |||
| 1055 | } | 1054 | } |
| 1056 | state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; | 1055 | state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; |
| 1057 | state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; | 1056 | state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; |
| 1057 | |||
| 1058 | bool flip_y = false; | ||
| 1059 | if (regs.viewport_transform[0].scale_y < 0.0) { | ||
| 1060 | flip_y = !flip_y; | ||
| 1061 | } | ||
| 1062 | if (regs.screen_y_control.y_negate != 0) { | ||
| 1063 | flip_y = !flip_y; | ||
| 1064 | } | ||
| 1065 | state.clip_control.origin = flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT; | ||
| 1058 | } | 1066 | } |
| 1059 | 1067 | ||
| 1060 | void RasterizerOpenGL::SyncClipEnabled( | 1068 | void RasterizerOpenGL::SyncClipEnabled( |
| @@ -1077,28 +1085,14 @@ void RasterizerOpenGL::SyncClipCoef() { | |||
| 1077 | } | 1085 | } |
| 1078 | 1086 | ||
| 1079 | void RasterizerOpenGL::SyncCullMode() { | 1087 | void RasterizerOpenGL::SyncCullMode() { |
| 1080 | auto& maxwell3d = system.GPU().Maxwell3D(); | 1088 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1081 | |||
| 1082 | const auto& regs = maxwell3d.regs; | ||
| 1083 | 1089 | ||
| 1084 | state.cull.enabled = regs.cull.enabled != 0; | 1090 | state.cull.enabled = regs.cull.enabled != 0; |
| 1085 | if (state.cull.enabled) { | 1091 | if (state.cull.enabled) { |
| 1086 | state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); | ||
| 1087 | state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); | 1092 | state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); |
| 1088 | |||
| 1089 | const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 || | ||
| 1090 | regs.viewport_transform[0].scale_y < 0.0f}; | ||
| 1091 | |||
| 1092 | // If the GPU is configured to flip the rasterized triangles, then we need to flip the | ||
| 1093 | // notion of front and back. Note: We flip the triangles when the value of the register is 0 | ||
| 1094 | // because OpenGL already does it for us. | ||
| 1095 | if (flip_triangles) { | ||
| 1096 | if (state.cull.front_face == GL_CCW) | ||
| 1097 | state.cull.front_face = GL_CW; | ||
| 1098 | else if (state.cull.front_face == GL_CW) | ||
| 1099 | state.cull.front_face = GL_CCW; | ||
| 1100 | } | ||
| 1101 | } | 1093 | } |
| 1094 | |||
| 1095 | state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); | ||
| 1102 | } | 1096 | } |
| 1103 | 1097 | ||
| 1104 | void RasterizerOpenGL::SyncPrimitiveRestart() { | 1098 | void RasterizerOpenGL::SyncPrimitiveRestart() { |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e56ed51de..4f2b49170 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1892,10 +1892,6 @@ private: | |||
| 1892 | Expression EmitVertex(Operation operation) { | 1892 | Expression EmitVertex(Operation operation) { |
| 1893 | ASSERT_MSG(stage == ProgramType::Geometry, | 1893 | ASSERT_MSG(stage == ProgramType::Geometry, |
| 1894 | "EmitVertex is expected to be used in a geometry shader."); | 1894 | "EmitVertex is expected to be used in a geometry shader."); |
| 1895 | |||
| 1896 | // If a geometry shader is attached, it will always flip (it's the last stage before | ||
| 1897 | // fragment). For more info about flipping, refer to gl_shader_gen.cpp. | ||
| 1898 | code.AddLine("gl_Position.xy *= viewport_flip.xy;"); | ||
| 1899 | code.AddLine("EmitVertex();"); | 1895 | code.AddLine("EmitVertex();"); |
| 1900 | return {}; | 1896 | return {}; |
| 1901 | } | 1897 | } |
| @@ -1903,14 +1899,12 @@ private: | |||
| 1903 | Expression EndPrimitive(Operation operation) { | 1899 | Expression EndPrimitive(Operation operation) { |
| 1904 | ASSERT_MSG(stage == ProgramType::Geometry, | 1900 | ASSERT_MSG(stage == ProgramType::Geometry, |
| 1905 | "EndPrimitive is expected to be used in a geometry shader."); | 1901 | "EndPrimitive is expected to be used in a geometry shader."); |
| 1906 | |||
| 1907 | code.AddLine("EndPrimitive();"); | 1902 | code.AddLine("EndPrimitive();"); |
| 1908 | return {}; | 1903 | return {}; |
| 1909 | } | 1904 | } |
| 1910 | 1905 | ||
| 1911 | Expression YNegate(Operation operation) { | 1906 | Expression YNegate(Operation operation) { |
| 1912 | // Config pack's third value is Y_NEGATE's state. | 1907 | return {"y_direction", Type::Float}; |
| 1913 | return {"config_pack[2]", Type::Uint}; | ||
| 1914 | } | 1908 | } |
| 1915 | 1909 | ||
| 1916 | template <u32 element> | 1910 | template <u32 element> |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 0e22eede9..af17216bd 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -20,8 +20,7 @@ std::string GenerateVertexShader(const Device& device, const ShaderIR& ir, const | |||
| 20 | std::string out = GetCommonDeclarations(); | 20 | std::string out = GetCommonDeclarations(); |
| 21 | out += R"( | 21 | out += R"( |
| 22 | layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { | 22 | layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { |
| 23 | vec4 viewport_flip; | 23 | float y_direction; |
| 24 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding | ||
| 25 | }; | 24 | }; |
| 26 | 25 | ||
| 27 | )"; | 26 | )"; |
| @@ -35,23 +34,10 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { | |||
| 35 | void main() { | 34 | void main() { |
| 36 | execute_vertex(); | 35 | execute_vertex(); |
| 37 | )"; | 36 | )"; |
| 38 | |||
| 39 | if (ir_b) { | 37 | if (ir_b) { |
| 40 | out += " execute_vertex_b();"; | 38 | out += " execute_vertex_b();"; |
| 41 | } | 39 | } |
| 42 | 40 | out += "}\n"; | |
| 43 | out += R"( | ||
| 44 | |||
| 45 | // Set Position Y direction | ||
| 46 | gl_Position.y *= utof(config_pack[2]); | ||
| 47 | // Check if the flip stage is VertexB | ||
| 48 | // Config pack's second value is flip_stage | ||
| 49 | if (config_pack[1] == 1) { | ||
| 50 | // Viewport can be flipped, which is unsupported by glViewport | ||
| 51 | gl_Position.xy *= viewport_flip.xy; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | )"; | ||
| 55 | return out; | 41 | return out; |
| 56 | } | 42 | } |
| 57 | 43 | ||
| @@ -59,8 +45,7 @@ std::string GenerateGeometryShader(const Device& device, const ShaderIR& ir) { | |||
| 59 | std::string out = GetCommonDeclarations(); | 45 | std::string out = GetCommonDeclarations(); |
| 60 | out += R"( | 46 | out += R"( |
| 61 | layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { | 47 | layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { |
| 62 | vec4 viewport_flip; | 48 | float y_direction; |
| 63 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding | ||
| 64 | }; | 49 | }; |
| 65 | 50 | ||
| 66 | )"; | 51 | )"; |
| @@ -87,8 +72,7 @@ layout (location = 6) out vec4 FragColor6; | |||
| 87 | layout (location = 7) out vec4 FragColor7; | 72 | layout (location = 7) out vec4 FragColor7; |
| 88 | 73 | ||
| 89 | layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { | 74 | layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { |
| 90 | vec4 viewport_flip; | 75 | float y_direction; |
| 91 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding | ||
| 92 | }; | 76 | }; |
| 93 | 77 | ||
| 94 | )"; | 78 | )"; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index b05f90f20..75d3fac04 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -40,27 +40,11 @@ void ProgramManager::UpdatePipeline() { | |||
| 40 | old_state = current_state; | 40 | old_state = current_state; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shader_stage) { | 43 | void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell) { |
| 44 | const auto& regs = maxwell.regs; | 44 | const auto& regs = maxwell.regs; |
| 45 | const auto& state = maxwell.state; | ||
| 46 | |||
| 47 | // TODO(bunnei): Support more than one viewport | ||
| 48 | viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; | ||
| 49 | viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; | ||
| 50 | |||
| 51 | instance_id = state.current_instance; | ||
| 52 | |||
| 53 | // Assign in which stage the position has to be flipped | ||
| 54 | // (the last stage before the fragment shader). | ||
| 55 | constexpr u32 geometry_index = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); | ||
| 56 | if (maxwell.regs.shader_config[geometry_index].enable) { | ||
| 57 | flip_stage = geometry_index; | ||
| 58 | } else { | ||
| 59 | flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); | ||
| 60 | } | ||
| 61 | 45 | ||
| 62 | // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. | 46 | // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. |
| 63 | y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f; | 47 | y_direction = regs.screen_y_control.y_negate == 0 ? 1.0f : -1.0f; |
| 64 | } | 48 | } |
| 65 | 49 | ||
| 66 | } // namespace OpenGL::GLShader | 50 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 6961e702a..3703e7018 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -18,17 +18,12 @@ namespace OpenGL::GLShader { | |||
| 18 | /// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at | 18 | /// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at |
| 19 | /// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. | 19 | /// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. |
| 20 | /// Not following that rule will cause problems on some AMD drivers. | 20 | /// Not following that rule will cause problems on some AMD drivers. |
| 21 | struct MaxwellUniformData { | 21 | struct alignas(16) MaxwellUniformData { |
| 22 | void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell, std::size_t shader_stage); | 22 | void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell); |
| 23 | 23 | ||
| 24 | alignas(16) GLvec4 viewport_flip; | 24 | GLfloat y_direction; |
| 25 | struct alignas(16) { | ||
| 26 | GLuint instance_id; | ||
| 27 | GLuint flip_stage; | ||
| 28 | GLfloat y_direction; | ||
| 29 | }; | ||
| 30 | }; | 25 | }; |
| 31 | static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect"); | 26 | static_assert(sizeof(MaxwellUniformData) == 16, "MaxwellUniformData structure size is incorrect"); |
| 32 | static_assert(sizeof(MaxwellUniformData) < 16384, | 27 | static_assert(sizeof(MaxwellUniformData) < 16384, |
| 33 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); | 28 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); |
| 34 | 29 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index f25148362..ccbe5912e 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -410,6 +410,12 @@ void OpenGLState::ApplyAlphaTest() { | |||
| 410 | } | 410 | } |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | void OpenGLState::ApplyClipControl() { | ||
| 414 | if (UpdateValue(cur_state.clip_control.origin, clip_control.origin)) { | ||
| 415 | glClipControl(clip_control.origin, GL_NEGATIVE_ONE_TO_ONE); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 413 | void OpenGLState::ApplyTextures() { | 419 | void OpenGLState::ApplyTextures() { |
| 414 | if (const auto update = UpdateArray(cur_state.textures, textures)) { | 420 | if (const auto update = UpdateArray(cur_state.textures, textures)) { |
| 415 | glBindTextures(update->first, update->second, textures.data() + update->first); | 421 | glBindTextures(update->first, update->second, textures.data() + update->first); |
| @@ -453,6 +459,7 @@ void OpenGLState::Apply() { | |||
| 453 | ApplyImages(); | 459 | ApplyImages(); |
| 454 | ApplyPolygonOffset(); | 460 | ApplyPolygonOffset(); |
| 455 | ApplyAlphaTest(); | 461 | ApplyAlphaTest(); |
| 462 | ApplyClipControl(); | ||
| 456 | } | 463 | } |
| 457 | 464 | ||
| 458 | void OpenGLState::EmulateViewportWithScissor() { | 465 | void OpenGLState::EmulateViewportWithScissor() { |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index cca25206b..eaff22bda 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -146,6 +146,10 @@ public: | |||
| 146 | 146 | ||
| 147 | std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE | 147 | std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE |
| 148 | 148 | ||
| 149 | struct { | ||
| 150 | GLenum origin = GL_LOWER_LEFT; | ||
| 151 | } clip_control; | ||
| 152 | |||
| 149 | OpenGLState(); | 153 | OpenGLState(); |
| 150 | 154 | ||
| 151 | /// Get the currently active OpenGL state | 155 | /// Get the currently active OpenGL state |
| @@ -182,6 +186,7 @@ public: | |||
| 182 | void ApplyDepthClamp(); | 186 | void ApplyDepthClamp(); |
| 183 | void ApplyPolygonOffset(); | 187 | void ApplyPolygonOffset(); |
| 184 | void ApplyAlphaTest(); | 188 | void ApplyAlphaTest(); |
| 189 | void ApplyClipControl(); | ||
| 185 | 190 | ||
| 186 | /// Resets any references to the given resource | 191 | /// Resets any references to the given resource |
| 187 | OpenGLState& UnbindTexture(GLuint handle); | 192 | OpenGLState& UnbindTexture(GLuint handle); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 160613ee1..867f8e913 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -817,6 +817,9 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() { | |||
| 817 | if (!GLAD_GL_ARB_multi_bind) { | 817 | if (!GLAD_GL_ARB_multi_bind) { |
| 818 | unsupported_ext.append(QStringLiteral("ARB_multi_bind")); | 818 | unsupported_ext.append(QStringLiteral("ARB_multi_bind")); |
| 819 | } | 819 | } |
| 820 | if (!GLAD_GL_ARB_clip_control) { | ||
| 821 | unsupported_ext.append(QStringLiteral("ARB_clip_control")); | ||
| 822 | } | ||
| 820 | 823 | ||
| 821 | // Extensions required to support some texture formats. | 824 | // Extensions required to support some texture formats. |
| 822 | if (!GLAD_GL_EXT_texture_compression_s3tc) { | 825 | if (!GLAD_GL_EXT_texture_compression_s3tc) { |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index f91b071bf..6fde694a2 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -50,7 +50,7 @@ private: | |||
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | 52 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { |
| 53 | std::vector<std::string> unsupported_ext; | 53 | std::vector<std::string_view> unsupported_ext; |
| 54 | 54 | ||
| 55 | if (!GLAD_GL_ARB_buffer_storage) | 55 | if (!GLAD_GL_ARB_buffer_storage) |
| 56 | unsupported_ext.push_back("ARB_buffer_storage"); | 56 | unsupported_ext.push_back("ARB_buffer_storage"); |
| @@ -62,6 +62,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 62 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | 62 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); |
| 63 | if (!GLAD_GL_ARB_multi_bind) | 63 | if (!GLAD_GL_ARB_multi_bind) |
| 64 | unsupported_ext.push_back("ARB_multi_bind"); | 64 | unsupported_ext.push_back("ARB_multi_bind"); |
| 65 | if (!GLAD_GL_ARB_clip_control) | ||
| 66 | unsupported_ext.push_back("ARB_clip_control"); | ||
| 65 | 67 | ||
| 66 | // Extensions required to support some texture formats. | 68 | // Extensions required to support some texture formats. |
| 67 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 69 | if (!GLAD_GL_EXT_texture_compression_s3tc) |
| @@ -71,8 +73,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 71 | if (!GLAD_GL_ARB_depth_buffer_float) | 73 | if (!GLAD_GL_ARB_depth_buffer_float) |
| 72 | unsupported_ext.push_back("ARB_depth_buffer_float"); | 74 | unsupported_ext.push_back("ARB_depth_buffer_float"); |
| 73 | 75 | ||
| 74 | for (const std::string& ext : unsupported_ext) | 76 | for (const auto& extension : unsupported_ext) |
| 75 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | 77 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); |
| 76 | 78 | ||
| 77 | return unsupported_ext.empty(); | 79 | return unsupported_ext.empty(); |
| 78 | } | 80 | } |