diff --git a/src/video_core/host_shaders/opengl_present.frag b/src/video_core/host_shaders/opengl_present.frag index 42dc53ee3..d17b8c177 100644 --- a/src/video_core/host_shaders/opengl_present.frag +++ b/src/video_core/host_shaders/opengl_present.frag @@ -9,11 +9,22 @@ layout(location = 0) out vec4 color; layout(binding = 0) uniform sampler2D color_texture; -uniform vec4 i_resolution; -uniform vec4 o_resolution; -uniform int layer; +uniform int convert_colors; +vec3 sRGBToLinear(vec3 c) { + return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c)); +} + +vec3 LinearTosRGB(vec3 c) { + return mix(c * 12.92, 1.055 * pow(c, vec3(1.0/2.4)) - 0.055, step(0.0031308, c)); +} void main() { - color = texture(color_texture, frag_tex_coord); + vec4 pixel = texture(color_texture, frag_tex_coord); + if (convert_colors == 1){ + pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a); + } else if (convert_colors == 2){ + pixel = vec4(sRGBToLinear(pixel.rgb), pixel.a); + } + color = pixel; } diff --git a/src/video_core/host_shaders/opengl_simple_present.frag b/src/video_core/host_shaders/opengl_simple_present.frag new file mode 100644 index 000000000..d17b8c177 --- /dev/null +++ b/src/video_core/host_shaders/opengl_simple_present.frag @@ -0,0 +1,30 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +//? #version 430 core + +layout(location = 0) in vec2 frag_tex_coord; +layout(location = 0) out vec4 color; + +layout(binding = 0) uniform sampler2D color_texture; + +uniform int convert_colors; + +vec3 sRGBToLinear(vec3 c) { + return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c)); +} + +vec3 LinearTosRGB(vec3 c) { + return mix(c * 12.92, 1.055 * pow(c, vec3(1.0/2.4)) - 0.055, step(0.0031308, c)); +} + +void main() { + vec4 pixel = texture(color_texture, frag_tex_coord); + if (convert_colors == 1){ + pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a); + } else if (convert_colors == 2){ + pixel = vec4(sRGBToLinear(pixel.rgb), pixel.a); + } + color = pixel; +} diff --git a/src/video_core/host_shaders/opengl_simple_present.vert b/src/video_core/host_shaders/opengl_simple_present.vert new file mode 100644 index 000000000..9f7709eba --- /dev/null +++ b/src/video_core/host_shaders/opengl_simple_present.vert @@ -0,0 +1,13 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +//? #version 430 core +layout(location = 0) in vec2 vert_position; +layout(location = 1) in vec2 vert_tex_coord; +layout(location = 0) out vec2 frag_tex_coord; + +void main() { + gl_Position = vec4(vert_position, 0.0, 1.0); + frag_tex_coord = vert_tex_coord; +} diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 74141ee9c..4edcd3f82 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -434,6 +434,7 @@ void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) { } uniform_i_resolution = glGetUniformLocation(shader.handle, "i_resolution"); uniform_o_resolution = glGetUniformLocation(shader.handle, "o_resolution"); + uniform_convert_colors = glGetUniformLocation(shader.handle, "convert_colors"); uniform_layer = glGetUniformLocation(shader.handle, "layer"); attrib_position = glGetAttribLocation(shader.handle, "vert_position"); attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord"); @@ -543,75 +544,69 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree // Rotate Internal Texture to Landscape (The 3DS stores images rotated 90° Counter Clockkwise internally) std::array landscape_rotation_vertices; landscape_rotation_vertices = {{ - ScreenRectVertex(0.f, 0.f, 1.f, 0.f), //Left, Top - ScreenRectVertex(textureWidth, 0.f, 1.f, 1.f), //Right, Top - ScreenRectVertex(0.f, textureHeight, 0.f, 0.f), //Left, Bottom - ScreenRectVertex(textureWidth, textureHeight, 0.f, 1.f), //Right, Bottom + ScreenRectVertex(-1.f, 1.f, 1.f, 0.f), //Left, Top + ScreenRectVertex(1.f, 1.f, 1.f, 1.f), //Right, Top + ScreenRectVertex(-1.f, -1.f, 0.f, 0.f), //Left, Bottom + ScreenRectVertex(1.f, -1.f, 0.f, 1.f), //Right, Bottom }}; // Vertices for 1:1 Texture Mapping. std::array pass_through_vertices; pass_through_vertices = {{ - ScreenRectVertex(0.f, 0.f, 0.f, 1.f), //Left, Top - ScreenRectVertex(textureWidth, 0.f, 1.f, 1.f), //Right, Top - ScreenRectVertex(0.f, textureHeight, 0.f, 0.f), //Left, Bottom - ScreenRectVertex(textureWidth, textureHeight, 1.f, 0.f), //Right, Bottom + ScreenRectVertex(-1.f, 1.f, 0.f, 1.f), //Left, Top + ScreenRectVertex(1.f, 1.f, 1.f, 1.f), //Right, Top + ScreenRectVertex(-1.f, -1.f, 0.f, 0.f), //Left, Bottom + ScreenRectVertex(1.f, -1.f, 1.f, 0.f), //Right, Bottom }}; // Rotate for Output Orientation, + // MAKE SURE TO USE ORTHOGRAPHIC MATRIX std::array output_vertices; - output_vertices = {{ - ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f), //Left, Top - ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f), //Right, Top - ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f), //Left, Bottom - ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f), //Right, Bottom - }}; - - - // switch (orientation) { - // case Layout::DisplayOrientation::Landscape: - // vertices = {{ - // ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), //Top Left - // ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right), //Top Right - // ScreenRectVertex(x, y + h, texcoords.top, texcoords.left), //Bottom Left - // ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right), //Bottom Right - // }}; - // break; - // case Layout::DisplayOrientation::Portrait: - // vertices = {{ - // ScreenRectVertex(x, y, texcoords.bottom, texcoords.right), - // ScreenRectVertex(x + w, y, texcoords.top, texcoords.right), - // ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left), - // ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left), - // }}; - // std::swap(h, w); - // break; - // case Layout::DisplayOrientation::LandscapeFlipped: - // vertices = {{ - // ScreenRectVertex(x, y, texcoords.top, texcoords.right), - // ScreenRectVertex(x + w, y, texcoords.top, texcoords.left), - // ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.right), - // ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left), - // }}; - // break; - // case Layout::DisplayOrientation::PortraitFlipped: - // vertices = {{ - // ScreenRectVertex(x, y, texcoords.top, texcoords.left), - // ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.left), - // ScreenRectVertex(x, y + h, texcoords.top, texcoords.right), - // ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.right), - // }}; - // std::swap(h, w); - // break; - // default: - // LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation); - // break; - // } + switch (orientation) { + case Layout::DisplayOrientation::Landscape: + output_vertices = {{ + ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f), //Left, Top + ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f), //Right, Top + ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f), //Left, Bottom + ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f), //Right, Bottom + }}; + break; + case Layout::DisplayOrientation::Portrait: + output_vertices = {{ + ScreenRectVertex(screenLeft, screenTop, 1.f, 1.f), //Left, Top + ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top + ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom + ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 0.f, 0.f), //Right, Bottom + }}; + std::swap(screenHeight, screenWidth); + break; + case Layout::DisplayOrientation::LandscapeFlipped: + output_vertices = {{ + ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top + ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top + ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom + ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom + }}; + break; + case Layout::DisplayOrientation::PortraitFlipped: + output_vertices = {{ + ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top + ScreenRectVertex(screenLeft + screenWidth, screenTop, 0.f, 1.f), //Right, Top + ScreenRectVertex(screenLeft, screenTop + screenHeight, 1.f, 0.f), //Left, Bottom + ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom + }}; + std::swap(screenHeight, screenWidth); + break; + default: + LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation); + break; + } const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle; glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight); glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight); + glUniform1i(uniform_convert_colors, 1); state.texture_units[0].texture_2d = screen_info.display_texture; state.texture_units[0].sampler = sampler; state.Apply(); @@ -625,6 +620,8 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree Then do: initial rotation shader -> opengl_present shader (and all the variants) + simple present is used for internal textures. It uses ndc coordinates directly + present is used for final mapping to screen. It uses screen coordinates, and transforms it accordingly */ GLuint old_read_fb = state.draw.read_framebuffer; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 2f2b318ed..413f26349 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -102,6 +102,9 @@ private: GLuint uniform_color_texture; GLuint uniform_color_texture_r; + // Shader Uniform for converting colors. 0 is no conversion, 1 is Linear -> sRGB, 2 is sRGB -> linear + GLuint uniform_convert_colors; + // Shader uniform for Dolphin compatibility GLuint uniform_i_resolution; GLuint uniform_o_resolution;