mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #4613 from BreadFish64/gles5
video_core: add GLES support
This commit is contained in:
		
						commit
						f409342ab5
					
				
					 19 changed files with 8937 additions and 1747 deletions
				
			
		|  | @ -105,6 +105,7 @@ void Config::ReadValues() { | |||
|     Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | ||||
| 
 | ||||
|     // Renderer
 | ||||
|     Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false); | ||||
|     Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true); | ||||
| #ifdef __APPLE__ | ||||
|     // Hardware shader is broken on macos thanks to poor drivers.
 | ||||
|  |  | |||
|  | @ -92,6 +92,10 @@ udp_pad_index= | |||
| use_cpu_jit = | ||||
| 
 | ||||
| [Renderer] | ||||
| # Whether to render using GLES or OpenGL | ||||
| # 0 (default): OpenGL, 1: GLES | ||||
| use_gles = | ||||
| 
 | ||||
| # Whether to use software or hardware rendering. | ||||
| # 0: Software, 1 (default): Hardware | ||||
| use_hw_renderer = | ||||
|  |  | |||
|  | @ -122,8 +122,13 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
|     SDL_SetMainReady(); | ||||
| 
 | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | ||||
|     if (Settings::values.use_gles) { | ||||
|         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); | ||||
|         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); | ||||
|     } else { | ||||
|         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||||
|         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | ||||
|     } | ||||
|     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||||
|     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||||
|     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); | ||||
|  | @ -155,7 +160,9 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | ||||
|     auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader; | ||||
| 
 | ||||
|     if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError()); | ||||
|         exit(1); | ||||
|     } | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ void LogSetting(const std::string& name, const T& value) { | |||
| void LogSettings() { | ||||
|     LOG_INFO(Config, "Citra Configuration:"); | ||||
|     LogSetting("Core_UseCpuJit", Settings::values.use_cpu_jit); | ||||
|     LogSetting("Renderer_UseGLES", Settings::values.use_gles); | ||||
|     LogSetting("Renderer_UseHwRenderer", Settings::values.use_hw_renderer); | ||||
|     LogSetting("Renderer_UseHwShader", Settings::values.use_hw_shader); | ||||
|     LogSetting("Renderer_ShadersAccurateGs", Settings::values.shaders_accurate_gs); | ||||
|  |  | |||
|  | @ -130,6 +130,7 @@ struct Values { | |||
|     u64 init_time; | ||||
| 
 | ||||
|     // Renderer
 | ||||
|     bool use_gles; | ||||
|     bool use_hw_renderer; | ||||
|     bool use_hw_shader; | ||||
|     bool shaders_accurate_gs; | ||||
|  |  | |||
|  | @ -41,6 +41,8 @@ add_library(video_core STATIC | |||
|     renderer_opengl/gl_state.h | ||||
|     renderer_opengl/gl_stream_buffer.cpp | ||||
|     renderer_opengl/gl_stream_buffer.h | ||||
|     renderer_opengl/gl_vars.cpp | ||||
|     renderer_opengl/gl_vars.h | ||||
|     renderer_opengl/pica_to_gl.h | ||||
|     renderer_opengl/renderer_opengl.cpp | ||||
|     renderer_opengl/renderer_opengl.h | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ | |||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
|  | @ -50,6 +51,17 @@ static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{ | |||
|     {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},   // RGBA4
 | ||||
| }}; | ||||
| 
 | ||||
| // Same as above, with minor changes for OpenGL ES. Replaced
 | ||||
| // GL_UNSIGNED_INT_8_8_8_8 with GL_UNSIGNED_BYTE and
 | ||||
| // GL_BGR with GL_RGB
 | ||||
| static constexpr std::array<FormatTuple, 5> fb_format_tuples_oes = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},            // RGBA8
 | ||||
|     {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE},              // RGB8
 | ||||
|     {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1
 | ||||
|     {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},     // RGB565
 | ||||
|     {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},   // RGBA4
 | ||||
| }}; | ||||
| 
 | ||||
| static constexpr std::array<FormatTuple, 4> depth_format_tuples = {{ | ||||
|     {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
 | ||||
|     {}, | ||||
|  | @ -63,6 +75,9 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | |||
|     const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); | ||||
|     if (type == SurfaceType::Color) { | ||||
|         ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size()); | ||||
|         if (GLES) { | ||||
|             return fb_format_tuples_oes[static_cast<unsigned int>(pixel_format)]; | ||||
|         } | ||||
|         return fb_format_tuples[static_cast<unsigned int>(pixel_format)]; | ||||
|     } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) { | ||||
|         std::size_t tuple_idx = static_cast<std::size_t>(pixel_format) - 14; | ||||
|  | @ -72,6 +87,77 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | |||
|     return tex_tuple; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * OpenGL ES does not support glGetTexImage. Obtain the pixels by attaching the | ||||
|  * texture to a framebuffer. | ||||
|  * Originally from https://github.com/apitrace/apitrace/blob/master/retrace/glstate_images.cpp
 | ||||
|  */ | ||||
| static inline void GetTexImageOES(GLenum target, GLint level, GLenum format, GLenum type, | ||||
|                                   GLint height, GLint width, GLint depth, GLubyte* pixels) { | ||||
| 
 | ||||
|     memset(pixels, 0x80, height * width * 4); | ||||
| 
 | ||||
|     GLenum texture_binding = GL_NONE; | ||||
|     switch (target) { | ||||
|     case GL_TEXTURE_2D: | ||||
|         texture_binding = GL_TEXTURE_BINDING_2D; | ||||
|         break; | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_X: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: | ||||
|         texture_binding = GL_TEXTURE_BINDING_CUBE_MAP; | ||||
|         break; | ||||
|     case GL_TEXTURE_3D_OES: | ||||
|         texture_binding = GL_TEXTURE_BINDING_3D_OES; | ||||
|     default: | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     GLint texture = 0; | ||||
|     glGetIntegerv(texture_binding, &texture); | ||||
|     if (!texture) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     GLint prev_fbo = 0; | ||||
|     GLuint fbo = 0; | ||||
|     glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo); | ||||
|     glGenFramebuffers(1, &fbo); | ||||
|     glBindFramebuffer(GL_FRAMEBUFFER, fbo); | ||||
| 
 | ||||
|     switch (target) { | ||||
|     case GL_TEXTURE_2D: | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_X: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: | ||||
|     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: | ||||
|     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { | ||||
|         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level); | ||||
|         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | ||||
|         if (status != GL_FRAMEBUFFER_COMPLETE) { | ||||
|             LOG_DEBUG(Render_OpenGL, "Framebuffer is incomplete, status: {:X}", status); | ||||
|         } | ||||
|         glReadPixels(0, 0, width, height, format, type, pixels); | ||||
|         break; | ||||
|     } | ||||
|     case GL_TEXTURE_3D_OES: | ||||
|         for (int i = 0; i < depth; i++) { | ||||
|             glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture, | ||||
|                                    level, i); | ||||
|             glReadPixels(0, 0, width, height, format, type, pixels + 4 * i * width * height); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo); | ||||
| 
 | ||||
|     glDeleteFramebuffers(1, &fbo); | ||||
| } | ||||
| 
 | ||||
| template <typename Map, typename Interval> | ||||
| constexpr auto RangeFromInterval(Map& map, const Interval& interval) { | ||||
|     return boost::make_iterator_range(map.equal_range(interval)); | ||||
|  | @ -841,7 +927,12 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui | |||
|         state.Apply(); | ||||
| 
 | ||||
|         glActiveTexture(GL_TEXTURE0); | ||||
|         glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||||
|         if (GLES) { | ||||
|             GetTexImageOES(GL_TEXTURE_2D, 0, tuple.format, tuple.type, height, width, 0, | ||||
|                            &gl_buffer[buffer_offset]); | ||||
|         } else { | ||||
|             glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||||
|         } | ||||
|     } else { | ||||
|         state.ResetTexture(texture.handle); | ||||
|         state.draw.read_framebuffer = read_fb_handle; | ||||
|  | @ -982,16 +1073,15 @@ RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | |||
|     d24s8_abgr_buffer.Create(); | ||||
|     d24s8_abgr_buffer_size = 0; | ||||
| 
 | ||||
|     const char* vs_source = R"( | ||||
| #version 330 core | ||||
|     std::string vs_source = R"( | ||||
| const vec2 vertices[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0)); | ||||
| void main() { | ||||
|     gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); | ||||
| } | ||||
| )"; | ||||
|     const char* fs_source = R"( | ||||
| #version 330 core | ||||
| 
 | ||||
|     std::string fs_source = GLES ? fragment_shader_precision_OES : ""; | ||||
|     fs_source += R"( | ||||
| uniform samplerBuffer tbo; | ||||
| uniform vec2 tbo_size; | ||||
| uniform vec4 viewport; | ||||
|  | @ -1004,7 +1094,7 @@ void main() { | |||
|     color = texelFetch(tbo, tbo_offset).rabg; | ||||
| } | ||||
| )"; | ||||
|     d24s8_abgr_shader.Create(vs_source, fs_source); | ||||
|     d24s8_abgr_shader.Create(vs_source.c_str(), fs_source.c_str()); | ||||
| 
 | ||||
|     OpenGLState state = OpenGLState::GetCurState(); | ||||
|     GLuint old_program = state.draw.shader_program; | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ | |||
| #include "video_core/renderer_opengl/gl_shader_decompiler.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_gen.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| using Pica::FramebufferRegs; | ||||
|  | @ -1250,7 +1251,6 @@ std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_sh | |||
|     const auto& state = config.state; | ||||
| 
 | ||||
|     std::string out = R"( | ||||
| #version 330 core | ||||
| #extension GL_ARB_shader_image_load_store : enable | ||||
| #extension GL_ARB_shader_image_size : enable | ||||
| #define ALLOW_SHADOW (defined(GL_ARB_shader_image_load_store) && defined(GL_ARB_shader_image_size)) | ||||
|  | @ -1260,10 +1260,16 @@ std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_sh | |||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||
|     } | ||||
| 
 | ||||
|     if (GLES) { | ||||
|         out += fragment_shader_precision_OES; | ||||
|     } | ||||
| 
 | ||||
|     out += GetVertexInterfaceDeclaration(false, separable_shader); | ||||
| 
 | ||||
|     out += R"( | ||||
| #ifndef CITRA_GLES | ||||
| in vec4 gl_FragCoord; | ||||
| #endif // CITRA_GLES
 | ||||
| 
 | ||||
| out vec4 color; | ||||
| 
 | ||||
|  | @ -1300,13 +1306,13 @@ float LookupLightingLUT(int lut_index, int index, float delta) { | |||
| 
 | ||||
| float LookupLightingLUTUnsigned(int lut_index, float pos) { | ||||
|     int index = clamp(int(pos * 256.0), 0, 255); | ||||
|     float delta = pos * 256.0 - index; | ||||
|     float delta = pos * 256.0 - float(index); | ||||
|     return LookupLightingLUT(lut_index, index, delta); | ||||
| } | ||||
| 
 | ||||
| float LookupLightingLUTSigned(int lut_index, float pos) { | ||||
|     int index = clamp(int(pos * 128.0), -128, 127); | ||||
|     float delta = pos * 128.0 - index; | ||||
|     float delta = pos * 128.0 - float(index); | ||||
|     if (index < 0) index += 256; | ||||
|     return LookupLightingLUT(lut_index, index, delta); | ||||
| } | ||||
|  | @ -1492,10 +1498,10 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
|         // Negate the condition if we have to keep only the pixels outside the scissor box
 | ||||
|         if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include) | ||||
|             out += "!"; | ||||
|         out += "(gl_FragCoord.x >= scissor_x1 && " | ||||
|                "gl_FragCoord.y >= scissor_y1 && " | ||||
|                "gl_FragCoord.x < scissor_x2 && " | ||||
|                "gl_FragCoord.y < scissor_y2)) discard;\n"; | ||||
|         out += "(gl_FragCoord.x >= float(scissor_x1) && " | ||||
|                "gl_FragCoord.y >= float(scissor_y1) && " | ||||
|                "gl_FragCoord.x < float(scissor_x2) && " | ||||
|                "gl_FragCoord.y < float(scissor_y2))) discard;\n"; | ||||
|     } | ||||
| 
 | ||||
|     // After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
 | ||||
|  | @ -1527,7 +1533,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
|     if (state.fog_mode == TexturingRegs::FogMode::Fog) { | ||||
|         // Get index into fog LUT
 | ||||
|         if (state.fog_flip) { | ||||
|             out += "float fog_index = (1.0 - depth) * 128.0;\n"; | ||||
|             out += "float fog_index = (1.0 - float(depth)) * 128.0;\n"; | ||||
|         } else { | ||||
|             out += "float fog_index = depth * 128.0;\n"; | ||||
|         } | ||||
|  | @ -1589,7 +1595,7 @@ do { | |||
| } | ||||
| 
 | ||||
| std::string GenerateTrivialVertexShader(bool separable_shader) { | ||||
|     std::string out = "#version 330 core\n"; | ||||
|     std::string out = ""; | ||||
|     if (separable_shader) { | ||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||
|     } | ||||
|  | @ -1624,8 +1630,10 @@ void main() { | |||
|     normquat = vert_normquat; | ||||
|     view = vert_view; | ||||
|     gl_Position = vert_position; | ||||
| #if !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance) | ||||
|     gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
 | ||||
|     gl_ClipDistance[1] = dot(clip_coef, vert_position); | ||||
| #endif // !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)
 | ||||
| } | ||||
| )"; | ||||
| 
 | ||||
|  | @ -1634,7 +1642,7 @@ void main() { | |||
| 
 | ||||
| std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup, | ||||
|                                                 const PicaVSConfig& config, bool separable_shader) { | ||||
|     std::string out = "#version 330 core\n"; | ||||
|     std::string out = ""; | ||||
|     if (separable_shader) { | ||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||
|     } | ||||
|  | @ -1742,9 +1750,12 @@ struct Vertex { | |||
|            semantic(VSOutputAttributes::POSITION_Y) + ", " + | ||||
|            semantic(VSOutputAttributes::POSITION_Z) + ", " + | ||||
|            semantic(VSOutputAttributes::POSITION_W) + ");\n"; | ||||
|     semantic(VSOutputAttributes::POSITION_W) + ");\n"; | ||||
|     out += "    gl_Position = vtx_pos;\n"; | ||||
|     out += "#if !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)\n"; | ||||
|     out += "    gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0
 | ||||
|     out += "    gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n\n"; | ||||
|     out += "    gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n"; | ||||
|     out += "#endif // !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)\n\n"; | ||||
| 
 | ||||
|     out += "    vec4 vtx_quat = GetVertexQuaternion(vtx);\n"; | ||||
|     out += "    normquat = mix(vtx_quat, -vtx_quat, bvec4(quats_opposite));\n\n"; | ||||
|  | @ -1787,7 +1798,7 @@ void EmitPrim(Vertex vtx0, Vertex vtx1, Vertex vtx2) { | |||
| }; | ||||
| 
 | ||||
| std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader) { | ||||
|     std::string out = "#version 330 core\n"; | ||||
|     std::string out = ""; | ||||
|     if (separable_shader) { | ||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; | ||||
|     } | ||||
|  | @ -1822,7 +1833,7 @@ void main() { | |||
| std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup, | ||||
|                                                   const PicaGSConfig& config, | ||||
|                                                   bool separable_shader) { | ||||
|     std::string out = "#version 330 core\n"; | ||||
|     std::string out = ""; | ||||
|     if (separable_shader) { | ||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||
|     } | ||||
|  |  | |||
|  | @ -2,15 +2,33 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <glad/glad.h> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| GLuint LoadShader(const char* source, GLenum type) { | ||||
|     const std::string version = GLES ? R"( | ||||
| #version 310 es | ||||
| 
 | ||||
| #define CITRA_GLES | ||||
| 
 | ||||
| #if defined(GL_ANDROID_extension_pack_es31a) | ||||
| #extension GL_ANDROID_extension_pack_es31a : enable | ||||
| #endif // defined(GL_ANDROID_extension_pack_es31a)
 | ||||
| 
 | ||||
| #if defined(GL_EXT_clip_cull_distance) | ||||
| #extension GL_EXT_clip_cull_distance : enable | ||||
| #endif // defined(GL_EXT_clip_cull_distance)
 | ||||
| )" | ||||
|                                      : "#version 330\n"; | ||||
| 
 | ||||
|     const char* debug_type; | ||||
|     switch (type) { | ||||
|     case GL_VERTEX_SHADER: | ||||
|  | @ -26,8 +44,9 @@ GLuint LoadShader(const char* source, GLenum type) { | |||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     std::array<const char*, 2> src_arr{version.data(), source}; | ||||
|     GLuint shader_id = glCreateShader(type); | ||||
|     glShaderSource(shader_id, 1, &source, nullptr); | ||||
|     glShaderSource(shader_id, static_cast<GLsizei>(src_arr.size()), src_arr.data(), nullptr); | ||||
|     LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); | ||||
|     glCompileShader(shader_id); | ||||
| 
 | ||||
|  | @ -44,7 +63,7 @@ GLuint LoadShader(const char* source, GLenum type) { | |||
|         } else { | ||||
|             LOG_ERROR(Render_OpenGL, "Error compiling {} shader:\n{}", debug_type, | ||||
|                       &shader_error[0]); | ||||
|             LOG_ERROR(Render_OpenGL, "Shader source code:\n{}", source); | ||||
|             LOG_ERROR(Render_OpenGL, "Shader source code:\n{}{}", src_arr[0], src_arr[1]); | ||||
|         } | ||||
|     } | ||||
|     return shader_id; | ||||
|  |  | |||
|  | @ -9,6 +9,17 @@ | |||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| // High precision may or may not supported in GLES3. If it isn't, use medium precision instead.
 | ||||
| static constexpr char fragment_shader_precision_OES[] = R"( | ||||
| #ifdef GL_FRAGMENT_PRECISION_HIGH | ||||
|     precision highp float; | ||||
| precision highp samplerBuffer; | ||||
| #else | ||||
|     precision mediump float; | ||||
| precision mediump samplerBuffer; | ||||
| #endif // GL_FRAGMENT_PRECISION_HIGH
 | ||||
| )"; | ||||
| 
 | ||||
| /**
 | ||||
|  * Utility function to create and compile an OpenGL GLSL shader | ||||
|  * @param source String of the GLSL shader program | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include "common/common_funcs.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
|  | @ -193,8 +194,13 @@ void OpenGLState::Apply() const { | |||
|         glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); | ||||
|     } | ||||
| 
 | ||||
|     if (logic_op != cur_state.logic_op) { | ||||
|         glLogicOp(logic_op); | ||||
|     // GLES3 does not support glLogicOp
 | ||||
|     if (!GLES) { | ||||
|         if (logic_op != cur_state.logic_op) { | ||||
|             glLogicOp(logic_op); | ||||
|         } | ||||
|     } else { | ||||
|         LOG_TRACE(Render_OpenGL, "glLogicOps are unimplemented..."); | ||||
|     } | ||||
| 
 | ||||
|     // Textures
 | ||||
|  | @ -319,12 +325,14 @@ void OpenGLState::Apply() const { | |||
|     } | ||||
| 
 | ||||
|     // Clip distance
 | ||||
|     for (std::size_t i = 0; i < clip_distance.size(); ++i) { | ||||
|         if (clip_distance[i] != cur_state.clip_distance[i]) { | ||||
|             if (clip_distance[i]) { | ||||
|                 glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); | ||||
|             } else { | ||||
|                 glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); | ||||
|     if (!GLES || GLAD_GL_EXT_clip_cull_distance) { | ||||
|         for (size_t i = 0; i < clip_distance.size(); ++i) { | ||||
|             if (clip_distance[i] != cur_state.clip_distance[i]) { | ||||
|                 if (clip_distance[i]) { | ||||
|                     glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); | ||||
|                 } else { | ||||
|                     glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										9
									
								
								src/video_core/renderer_opengl/gl_vars.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/video_core/renderer_opengl/gl_vars.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| // Copyright 2019 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| bool GLES; | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/video_core/renderer_opengl/gl_vars.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/video_core/renderer_opengl/gl_vars.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| // Copyright 2019 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| extern bool GLES; | ||||
| } | ||||
|  | @ -21,14 +21,13 @@ | |||
| #include "core/tracer/recorder.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/renderer_opengl/renderer_opengl.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| static const char vertex_shader[] = R"( | ||||
| #version 150 core | ||||
| 
 | ||||
| in vec2 vert_position; | ||||
| in vec2 vert_tex_coord; | ||||
| out vec2 frag_tex_coord; | ||||
|  | @ -50,8 +49,6 @@ void main() { | |||
| )"; | ||||
| 
 | ||||
| static const char fragment_shader[] = R"( | ||||
| #version 150 core | ||||
| 
 | ||||
| in vec2 frag_tex_coord; | ||||
| out vec4 color; | ||||
| 
 | ||||
|  | @ -279,7 +276,13 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
|                  0.0f); | ||||
| 
 | ||||
|     // Link shaders and get variable locations
 | ||||
|     shader.Create(vertex_shader, fragment_shader); | ||||
|     if (GLES) { | ||||
|         std::string frag_source(fragment_shader_precision_OES); | ||||
|         frag_source += fragment_shader; | ||||
|         shader.Create(vertex_shader, frag_source.data()); | ||||
|     } else { | ||||
|         shader.Create(vertex_shader, fragment_shader); | ||||
|     } | ||||
|     state.draw.shader_program = shader.handle; | ||||
|     state.Apply(); | ||||
|     uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix"); | ||||
|  | @ -344,7 +347,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
|     case GPU::Regs::PixelFormat::RGBA8: | ||||
|         internal_format = GL_RGBA; | ||||
|         texture.gl_format = GL_RGBA; | ||||
|         texture.gl_type = GL_UNSIGNED_INT_8_8_8_8; | ||||
|         texture.gl_type = GLES ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_8_8_8_8; | ||||
|         break; | ||||
| 
 | ||||
|     case GPU::Regs::PixelFormat::RGB8: | ||||
|  | @ -353,7 +356,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
|         // mostly everywhere) for words or half-words.
 | ||||
|         // TODO: check how those behave on big-endian processors.
 | ||||
|         internal_format = GL_RGB; | ||||
|         texture.gl_format = GL_BGR; | ||||
| 
 | ||||
|         // GLES Dosen't support BGR , Use RGB instead
 | ||||
|         texture.gl_format = GLES ? GL_RGB : GL_BGR; | ||||
|         texture.gl_type = GL_UNSIGNED_BYTE; | ||||
|         break; | ||||
| 
 | ||||
|  | @ -555,7 +560,7 @@ Core::System::ResultStatus RendererOpenGL::Init() { | |||
|         return Core::System::ResultStatus::ErrorVideoCore_ErrorGenericDrivers; | ||||
|     } | ||||
| 
 | ||||
|     if (!GLAD_GL_VERSION_3_3) { | ||||
|     if (!(GLAD_GL_VERSION_3_3 || GLAD_GL_ES_VERSION_3_1)) { | ||||
|         return Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include "core/settings.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/renderer_opengl/renderer_opengl.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
|  | @ -36,6 +37,8 @@ Core::System::ResultStatus Init(EmuWindow& emu_window, Memory::MemorySystem& mem | |||
|     g_memory = &memory; | ||||
|     Pica::Init(); | ||||
| 
 | ||||
|     OpenGL::GLES = Settings::values.use_gles; | ||||
| 
 | ||||
|     g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window); | ||||
|     Core::System::ResultStatus result = g_renderer->Init(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue