diff options
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.cpp | 519 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.h | 110 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 506 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 78 | 
6 files changed, 639 insertions, 577 deletions
| diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 36aa7bb66..c158970f2 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -118,6 +118,8 @@ add_library(video_core STATIC      renderer_null/renderer_null.h      renderer_opengl/blit_image.cpp      renderer_opengl/blit_image.h +    renderer_opengl/gl_blit_screen.cpp +    renderer_opengl/gl_blit_screen.h      renderer_opengl/gl_buffer_cache_base.cpp      renderer_opengl/gl_buffer_cache.cpp      renderer_opengl/gl_buffer_cache.h diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp new file mode 100644 index 000000000..88757ba38 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp @@ -0,0 +1,519 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "video_core/framebuffer_config.h" +#include "video_core/host_shaders/ffx_a_h.h" +#include "video_core/host_shaders/ffx_fsr1_h.h" +#include "video_core/host_shaders/full_screen_triangle_vert.h" +#include "video_core/host_shaders/fxaa_frag.h" +#include "video_core/host_shaders/fxaa_vert.h" +#include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h" +#include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h" +#include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h" +#include "video_core/host_shaders/opengl_present_frag.h" +#include "video_core/host_shaders/opengl_present_scaleforce_frag.h" +#include "video_core/host_shaders/opengl_present_vert.h" +#include "video_core/host_shaders/opengl_smaa_glsl.h" +#include "video_core/host_shaders/present_bicubic_frag.h" +#include "video_core/host_shaders/present_gaussian_frag.h" +#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h" +#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h" +#include "video_core/host_shaders/smaa_edge_detection_frag.h" +#include "video_core/host_shaders/smaa_edge_detection_vert.h" +#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h" +#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h" +#include "video_core/renderer_opengl/gl_blit_screen.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" +#include "video_core/renderer_opengl/gl_shader_manager.h" +#include "video_core/renderer_opengl/gl_shader_util.h" +#include "video_core/renderer_opengl/gl_state_tracker.h" +#include "video_core/smaa_area_tex.h" +#include "video_core/smaa_search_tex.h" +#include "video_core/textures/decoders.h" + +namespace OpenGL { + +namespace { +constexpr GLint PositionLocation = 0; +constexpr GLint TexCoordLocation = 1; +constexpr GLint ModelViewMatrixLocation = 0; + +struct ScreenRectVertex { +    constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) +        : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} + +    std::array<GLfloat, 2> position; +    std::array<GLfloat, 2> tex_coord; +}; + +/** + * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left + * corner and (width, height) on the lower-bottom. + * + * The projection part of the matrix is trivial, hence these operations are represented + * by a 3x2 matrix. + */ +std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { +    std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order + +    // clang-format off +    matrix[0] = 2.f / width; matrix[2] =  0.f;          matrix[4] = -1.f; +    matrix[1] = 0.f;         matrix[3] = -2.f / height; matrix[5] =  1.f; +    // Last matrix row is implicitly assumed to be [0, 0, 1]. +    // clang-format on + +    return matrix; +} +} // namespace + +BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, +                       Tegra::MaxwellDeviceMemoryManager& device_memory_, +                       StateTracker& state_tracker_, ProgramManager& program_manager_, +                       Device& device_) +    : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), +      program_manager(program_manager_), device(device_) { +    // Create shader programs +    fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER); +    fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER); + +    const auto replace_include = [](std::string& shader_source, std::string_view include_name, +                                    std::string_view include_content) { +        const std::string include_string = fmt::format("#include \"{}\"", include_name); +        const std::size_t pos = shader_source.find(include_string); +        ASSERT(pos != std::string::npos); +        shader_source.replace(pos, include_string.size(), include_content); +    }; + +    const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) { +        std::string shader_source{specialized_source}; +        replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL); +        return CreateProgram(shader_source, stage); +    }; + +    smaa_edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER); +    smaa_edge_detection_frag = +        SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER); +    smaa_blending_weight_calculation_vert = +        SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER); +    smaa_blending_weight_calculation_frag = +        SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER); +    smaa_neighborhood_blending_vert = +        SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER); +    smaa_neighborhood_blending_frag = +        SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); + +    present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); +    present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER); +    present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER); +    present_gaussian_fragment = +        CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER); +    present_scaleforce_fragment = +        CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), +                      GL_FRAGMENT_SHADER); + +    std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG}; +    replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H); +    replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H); + +    std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG}; +    std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG}; +    replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); +    replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); + +    fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source, +                                fsr_rcas_frag_source); + +    // Generate presentation sampler +    present_sampler.Create(); +    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + +    present_sampler_nn.Create(); +    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + +    // Generate VBO handle for drawing +    vertex_buffer.Create(); + +    // Attach vertex data to VAO +    glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); + +    // Allocate textures for the screen +    framebuffer_texture.resource.Create(GL_TEXTURE_2D); + +    const GLuint texture = framebuffer_texture.resource.handle; +    glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); + +    // Clear screen to black +    const u8 framebuffer_data[4] = {0, 0, 0, 0}; +    glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, +                    framebuffer_data); + +    aa_framebuffer.Create(); + +    smaa_area_tex.Create(GL_TEXTURE_2D); +    glTextureStorage2D(smaa_area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); +    glTextureSubImage2D(smaa_area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG, +                        GL_UNSIGNED_BYTE, areaTexBytes); +    smaa_search_tex.Create(GL_TEXTURE_2D); +    glTextureStorage2D(smaa_search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT); +    glTextureSubImage2D(smaa_search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED, +                        GL_UNSIGNED_BYTE, searchTexBytes); + +    // Enable unified vertex attributes and query vertex buffer address when the driver supports it +    if (device.HasVertexBufferUnifiedMemory()) { +        glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); +        glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); +        glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); +        glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, +                                         &vertex_buffer_address); +    } +} + +FramebufferTextureInfo BlitScreen::PrepareRenderTarget( +    const Tegra::FramebufferConfig& framebuffer) { +    // If framebuffer is provided, reload it from memory to a texture +    if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) || +        framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) || +        framebuffer_texture.pixel_format != framebuffer.pixel_format || +        gl_framebuffer_data.empty()) { +        // Reallocate texture if the framebuffer size has changed. +        // This is expected to not happen very often and hence should not be a +        // performance problem. +        ConfigureFramebufferTexture(framebuffer); +    } + +    // Load the framebuffer from memory if needed +    return LoadFBToScreenInfo(framebuffer); +} + +FramebufferTextureInfo BlitScreen::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { +    const DAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; +    const auto accelerated_info = +        rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); +    if (accelerated_info) { +        return *accelerated_info; +    } + +    // Reset the screen info's display texture to its own permanent texture +    FramebufferTextureInfo info{}; +    info.display_texture = framebuffer_texture.resource.handle; +    info.width = framebuffer.width; +    info.height = framebuffer.height; +    info.scaled_width = framebuffer.width; +    info.scaled_height = framebuffer.height; + +    // TODO(Rodrigo): Read this from HLE +    constexpr u32 block_height_log2 = 4; +    const auto pixel_format{ +        VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; +    const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; +    const u64 size_in_bytes{Tegra::Texture::CalculateSize( +        true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; +    const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; +    const std::span<const u8> input_data(host_ptr, size_in_bytes); +    Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, +                                     framebuffer.width, framebuffer.height, 1, block_height_log2, +                                     0); + +    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); +    glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); + +    // Update existing texture +    // TODO: Test what happens on hardware when you change the framebuffer dimensions so that +    //       they differ from the LCD resolution. +    // TODO: Applications could theoretically crash yuzu here by specifying too large +    //       framebuffer sizes. We should make sure that this cannot happen. +    glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width, +                        framebuffer.height, framebuffer_texture.gl_format, +                        framebuffer_texture.gl_type, gl_framebuffer_data.data()); + +    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + +    return info; +} + +void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) { +    framebuffer_texture.width = framebuffer.width; +    framebuffer_texture.height = framebuffer.height; +    framebuffer_texture.pixel_format = framebuffer.pixel_format; + +    const auto pixel_format{ +        VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; +    const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; +    gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height * +                               bytes_per_pixel); + +    GLint internal_format; +    switch (framebuffer.pixel_format) { +    case Service::android::PixelFormat::Rgba8888: +        internal_format = GL_RGBA8; +        framebuffer_texture.gl_format = GL_RGBA; +        framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; +        break; +    case Service::android::PixelFormat::Rgb565: +        internal_format = GL_RGB565; +        framebuffer_texture.gl_format = GL_RGB; +        framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; +        break; +    default: +        internal_format = GL_RGBA8; +        framebuffer_texture.gl_format = GL_RGBA; +        framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; +        // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", +        //                   static_cast<u32>(framebuffer.pixel_format)); +        break; +    } + +    framebuffer_texture.resource.Release(); +    framebuffer_texture.resource.Create(GL_TEXTURE_2D); +    glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, +                       framebuffer_texture.width, framebuffer_texture.height); +    aa_texture.Release(); +    aa_texture.Create(GL_TEXTURE_2D); +    glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F, +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); +    glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0); +    smaa_edges_tex.Release(); +    smaa_edges_tex.Create(GL_TEXTURE_2D); +    glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F, +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); +    smaa_blend_tex.Release(); +    smaa_blend_tex.Create(GL_TEXTURE_2D); +    glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F, +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), +                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); +} + +void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, +                            const Layout::FramebufferLayout& layout) { +    FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); +    const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); + +    // TODO: Signal state tracker about these changes +    state_tracker.NotifyScreenDrawVertexArray(); +    state_tracker.NotifyPolygonModes(); +    state_tracker.NotifyViewport0(); +    state_tracker.NotifyScissor0(); +    state_tracker.NotifyColorMask(0); +    state_tracker.NotifyBlend0(); +    state_tracker.NotifyFramebuffer(); +    state_tracker.NotifyFrontFace(); +    state_tracker.NotifyCullTest(); +    state_tracker.NotifyDepthTest(); +    state_tracker.NotifyStencilTest(); +    state_tracker.NotifyPolygonOffset(); +    state_tracker.NotifyRasterizeEnable(); +    state_tracker.NotifyFramebufferSRGB(); +    state_tracker.NotifyLogicOp(); +    state_tracker.NotifyClipControl(); +    state_tracker.NotifyAlphaTest(); + +    state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); + +    glEnable(GL_CULL_FACE); +    glDisable(GL_COLOR_LOGIC_OP); +    glDisable(GL_DEPTH_TEST); +    glDisable(GL_STENCIL_TEST); +    glDisable(GL_POLYGON_OFFSET_FILL); +    glDisable(GL_RASTERIZER_DISCARD); +    glDisable(GL_ALPHA_TEST); +    glDisablei(GL_BLEND, 0); +    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +    glCullFace(GL_BACK); +    glFrontFace(GL_CW); +    glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +    glDepthRangeIndexed(0, 0.0, 0.0); + +    glBindTextureUnit(0, info.display_texture); + +    auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); +    if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { +        LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing); +        anti_aliasing = Settings::AntiAliasing::None; +        Settings::values.anti_aliasing.SetValue(anti_aliasing); +    } + +    if (anti_aliasing != Settings::AntiAliasing::None) { +        glEnablei(GL_SCISSOR_TEST, 0); +        auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); +        auto viewport_width = static_cast<GLfloat>(scissor_width); +        auto scissor_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height); +        auto viewport_height = static_cast<GLfloat>(scissor_height); + +        glScissorIndexed(0, 0, 0, scissor_width, scissor_height); +        glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); + +        glBindSampler(0, present_sampler.handle); +        GLint old_read_fb; +        GLint old_draw_fb; +        glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); +        glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); + +        switch (anti_aliasing) { +        case Settings::AntiAliasing::Fxaa: { +            program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle); +            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle); +            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +        } break; +        case Settings::AntiAliasing::Smaa: { +            glClearColor(0, 0, 0, 0); +            glFrontFace(GL_CCW); +            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle); +            glBindSampler(1, present_sampler.handle); +            glBindSampler(2, present_sampler.handle); + +            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, +                                      smaa_edges_tex.handle, 0); +            glClear(GL_COLOR_BUFFER_BIT); +            program_manager.BindPresentPrograms(smaa_edge_detection_vert.handle, +                                                smaa_edge_detection_frag.handle); +            glDrawArrays(GL_TRIANGLES, 0, 3); + +            glBindTextureUnit(0, smaa_edges_tex.handle); +            glBindTextureUnit(1, smaa_area_tex.handle); +            glBindTextureUnit(2, smaa_search_tex.handle); +            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, +                                      smaa_blend_tex.handle, 0); +            glClear(GL_COLOR_BUFFER_BIT); +            program_manager.BindPresentPrograms(smaa_blending_weight_calculation_vert.handle, +                                                smaa_blending_weight_calculation_frag.handle); +            glDrawArrays(GL_TRIANGLES, 0, 3); + +            glBindTextureUnit(0, info.display_texture); +            glBindTextureUnit(1, smaa_blend_tex.handle); +            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, +                                      aa_texture.handle, 0); +            program_manager.BindPresentPrograms(smaa_neighborhood_blending_vert.handle, +                                                smaa_neighborhood_blending_frag.handle); +            glDrawArrays(GL_TRIANGLES, 0, 3); +            glFrontFace(GL_CW); +        } break; +        default: +            UNREACHABLE(); +        } + +        glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); +        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); + +        glBindTextureUnit(0, aa_texture.handle); +    } +    glDisablei(GL_SCISSOR_TEST, 0); + +    if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { +        if (!fsr->AreBuffersInitialized()) { +            fsr->InitBuffers(); +        } + +        glBindSampler(0, present_sampler.handle); +        fsr->Draw(program_manager, layout.screen, info.scaled_width, info.scaled_height, crop); +    } else { +        if (fsr->AreBuffersInitialized()) { +            fsr->ReleaseBuffers(); +        } +    } + +    const std::array ortho_matrix = +        MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); + +    const auto fragment_handle = [this]() { +        switch (Settings::values.scaling_filter.GetValue()) { +        case Settings::ScalingFilter::NearestNeighbor: +        case Settings::ScalingFilter::Bilinear: +            return present_bilinear_fragment.handle; +        case Settings::ScalingFilter::Bicubic: +            return present_bicubic_fragment.handle; +        case Settings::ScalingFilter::Gaussian: +            return present_gaussian_fragment.handle; +        case Settings::ScalingFilter::ScaleForce: +            return present_scaleforce_fragment.handle; +        case Settings::ScalingFilter::Fsr: +            return fsr->GetPresentFragmentProgram().handle; +        default: +            return present_bilinear_fragment.handle; +        } +    }(); +    program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); +    glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, +                                ortho_matrix.data()); + +    f32 left, top, right, bottom; +    if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { +        // FSR has already applied the crop, so we just want to render the image +        // it has produced. +        left = 0; +        top = 0; +        right = 1; +        bottom = 1; +    } else { +        // Apply the precomputed crop. +        left = crop.left; +        top = crop.top; +        right = crop.right; +        bottom = crop.bottom; +    } + +    // Map the coordinates to the screen. +    const auto& screen = layout.screen; +    const auto x = screen.left; +    const auto y = screen.top; +    const auto w = screen.GetWidth(); +    const auto h = screen.GetHeight(); + +    const std::array vertices = { +        ScreenRectVertex(x, y, left, top), +        ScreenRectVertex(x + w, y, right, top), +        ScreenRectVertex(x, y + h, left, bottom), +        ScreenRectVertex(x + w, y + h, right, bottom), +    }; +    glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); + +    glDisable(GL_FRAMEBUFFER_SRGB); +    glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), +                       static_cast<GLfloat>(layout.height)); + +    glEnableVertexAttribArray(PositionLocation); +    glEnableVertexAttribArray(TexCoordLocation); +    glVertexAttribDivisor(PositionLocation, 0); +    glVertexAttribDivisor(TexCoordLocation, 0); +    glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, +                         offsetof(ScreenRectVertex, position)); +    glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, +                         offsetof(ScreenRectVertex, tex_coord)); +    glVertexAttribBinding(PositionLocation, 0); +    glVertexAttribBinding(TexCoordLocation, 0); +    if (device.HasVertexBufferUnifiedMemory()) { +        glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); +        glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, +                               sizeof(vertices)); +    } else { +        glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); +    } + +    if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { +        glBindSampler(0, present_sampler.handle); +    } else { +        glBindSampler(0, present_sampler_nn.handle); +    } + +    // Update background color before drawing +    glClearColor(Settings::values.bg_red.GetValue() / 255.0f, +                 Settings::values.bg_green.GetValue() / 255.0f, +                 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); + +    glClear(GL_COLOR_BUFFER_BIT); +    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + +    // TODO +    // program_manager.RestoreGuestPipeline(); +} + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h new file mode 100644 index 000000000..13d769958 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_blit_screen.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <vector> + +#include "core/hle/service/nvnflinger/pixel_format.h" +#include "video_core/host1x/gpu_device_memory_manager.h" +#include "video_core/renderer_opengl/gl_fsr.h" +#include "video_core/renderer_opengl/gl_resource_manager.h" + +namespace Layout { +struct FramebufferLayout; +} + +namespace Tegra { +struct FramebufferConfig; +} + +namespace OpenGL { + +class Device; +class RasterizerOpenGL; +class StateTracker; + +/// Structure used for storing information about the textures for the Switch screen +struct TextureInfo { +    OGLTexture resource; +    GLsizei width; +    GLsizei height; +    GLenum gl_format; +    GLenum gl_type; +    Service::android::PixelFormat pixel_format; +}; + +/// Structure used for storing information about the display target for the Switch screen +struct FramebufferTextureInfo { +    GLuint display_texture{}; +    u32 width; +    u32 height; +    u32 scaled_width; +    u32 scaled_height; +}; + +class BlitScreen { +public: +    explicit BlitScreen(RasterizerOpenGL& rasterizer, +                        Tegra::MaxwellDeviceMemoryManager& device_memory, +                        StateTracker& state_tracker, ProgramManager& program_manager, +                        Device& device); + +    void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); + +    /// Draws the emulated screens to the emulator window. +    void DrawScreen(const Tegra::FramebufferConfig& framebuffer, +                    const Layout::FramebufferLayout& layout); + +    void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); + +    /// Loads framebuffer from emulated memory into the active OpenGL texture. +    FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); + +    FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); + +private: +    RasterizerOpenGL& rasterizer; +    Tegra::MaxwellDeviceMemoryManager& device_memory; +    StateTracker& state_tracker; +    ProgramManager& program_manager; +    Device& device; + +    OGLSampler present_sampler; +    OGLSampler present_sampler_nn; +    OGLBuffer vertex_buffer; +    OGLProgram fxaa_vertex; +    OGLProgram fxaa_fragment; +    OGLProgram present_vertex; +    OGLProgram present_bilinear_fragment; +    OGLProgram present_bicubic_fragment; +    OGLProgram present_gaussian_fragment; +    OGLProgram present_scaleforce_fragment; + +    /// Display information for Switch screen +    TextureInfo framebuffer_texture; +    OGLTexture aa_texture; +    OGLFramebuffer aa_framebuffer; + +    OGLProgram smaa_edge_detection_vert; +    OGLProgram smaa_blending_weight_calculation_vert; +    OGLProgram smaa_neighborhood_blending_vert; +    OGLProgram smaa_edge_detection_frag; +    OGLProgram smaa_blending_weight_calculation_frag; +    OGLProgram smaa_neighborhood_blending_frag; +    OGLTexture smaa_area_tex; +    OGLTexture smaa_search_tex; +    OGLTexture smaa_edges_tex; +    OGLTexture smaa_blend_tex; + +    std::unique_ptr<FSR> fsr; + +    /// OpenGL framebuffer data +    std::vector<u8> gl_framebuffer_data; + +    // GPU address of the vertex buffer +    GLuint64EXT vertex_buffer_address = 0; +}; + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index ee82d9f3a..6eae51ff7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -16,6 +16,7 @@  #include "video_core/engines/maxwell_dma.h"  #include "video_core/rasterizer_interface.h"  #include "video_core/renderer_opengl/blit_image.h" +#include "video_core/renderer_opengl/gl_blit_screen.h"  #include "video_core/renderer_opengl/gl_buffer_cache.h"  #include "video_core/renderer_opengl/gl_device.h"  #include "video_core/renderer_opengl/gl_fence_manager.h" diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 2b9ebff92..38b0aacf4 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -16,68 +16,16 @@  #include "core/core_timing.h"  #include "core/frontend/emu_window.h"  #include "core/telemetry_session.h" -#include "video_core/host_shaders/ffx_a_h.h" -#include "video_core/host_shaders/ffx_fsr1_h.h" -#include "video_core/host_shaders/full_screen_triangle_vert.h" -#include "video_core/host_shaders/fxaa_frag.h" -#include "video_core/host_shaders/fxaa_vert.h" -#include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h" -#include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h" -#include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h" -#include "video_core/host_shaders/opengl_present_frag.h" -#include "video_core/host_shaders/opengl_present_scaleforce_frag.h" -#include "video_core/host_shaders/opengl_present_vert.h" -#include "video_core/host_shaders/opengl_smaa_glsl.h" -#include "video_core/host_shaders/present_bicubic_frag.h" -#include "video_core/host_shaders/present_gaussian_frag.h" -#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h" -#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h" -#include "video_core/host_shaders/smaa_edge_detection_frag.h" -#include "video_core/host_shaders/smaa_edge_detection_vert.h" -#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h" -#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h" +#include "video_core/renderer_opengl/gl_blit_screen.h"  #include "video_core/renderer_opengl/gl_fsr.h"  #include "video_core/renderer_opengl/gl_rasterizer.h"  #include "video_core/renderer_opengl/gl_shader_manager.h"  #include "video_core/renderer_opengl/gl_shader_util.h"  #include "video_core/renderer_opengl/renderer_opengl.h" -#include "video_core/smaa_area_tex.h" -#include "video_core/smaa_search_tex.h"  #include "video_core/textures/decoders.h"  namespace OpenGL {  namespace { -constexpr GLint PositionLocation = 0; -constexpr GLint TexCoordLocation = 1; -constexpr GLint ModelViewMatrixLocation = 0; - -struct ScreenRectVertex { -    constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) -        : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} - -    std::array<GLfloat, 2> position; -    std::array<GLfloat, 2> tex_coord; -}; - -/** - * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left - * corner and (width, height) on the lower-bottom. - * - * The projection part of the matrix is trivial, hence these operations are represented - * by a 3x2 matrix. - */ -std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { -    std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order - -    // clang-format off -    matrix[0] = 2.f / width; matrix[2] =  0.f;          matrix[4] = -1.f; -    matrix[1] = 0.f;         matrix[3] = -2.f / height; matrix[5] =  1.f; -    // Last matrix row is implicitly assumed to be [0, 0, 1]. -    // clang-format on - -    return matrix; -} -  const char* GetSource(GLenum source) {      switch (source) {      case GL_DEBUG_SOURCE_API: @@ -155,7 +103,6 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,          glDebugMessageCallback(DebugHandler, nullptr);      }      AddTelemetryFields(); -    InitOpenGLObjects();      // Initialize default attributes to match hardware's disabled attributes      GLint max_attribs{}; @@ -167,14 +114,8 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,      if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) {          glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);      } -    // Enable unified vertex attributes and query vertex buffer address when the driver supports it -    if (device.HasVertexBufferUnifiedMemory()) { -        glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); -        glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); -        glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); -        glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, -                                         &vertex_buffer_address); -    } +    blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, +                                               program_manager, device);  }  RendererOpenGL::~RendererOpenGL() = default; @@ -187,7 +128,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {      RenderScreenshot(*framebuffer);      state_tracker.BindFramebuffer(0); -    DrawScreen(*framebuffer, emu_window.GetFramebufferLayout()); +    blit_screen->DrawScreen(*framebuffer, emu_window.GetFramebufferLayout());      ++m_current_frame; @@ -198,166 +139,6 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {      render_window.OnFrameDisplayed();  } -FramebufferTextureInfo RendererOpenGL::PrepareRenderTarget( -    const Tegra::FramebufferConfig& framebuffer) { -    // If framebuffer is provided, reload it from memory to a texture -    if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) || -        framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) || -        framebuffer_texture.pixel_format != framebuffer.pixel_format || -        gl_framebuffer_data.empty()) { -        // Reallocate texture if the framebuffer size has changed. -        // This is expected to not happen very often and hence should not be a -        // performance problem. -        ConfigureFramebufferTexture(framebuffer); -    } - -    // Load the framebuffer from memory if needed -    return LoadFBToScreenInfo(framebuffer); -} - -FramebufferTextureInfo RendererOpenGL::LoadFBToScreenInfo( -    const Tegra::FramebufferConfig& framebuffer) { -    const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; -    const auto accelerated_info = -        rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); -    if (accelerated_info) { -        return *accelerated_info; -    } - -    // Reset the screen info's display texture to its own permanent texture -    FramebufferTextureInfo info{}; -    info.display_texture = framebuffer_texture.resource.handle; -    info.width = framebuffer.width; -    info.height = framebuffer.height; -    info.scaled_width = framebuffer.width; -    info.scaled_height = framebuffer.height; - -    // TODO(Rodrigo): Read this from HLE -    constexpr u32 block_height_log2 = 4; -    const auto pixel_format{ -        VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; -    const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; -    const u64 size_in_bytes{Tegra::Texture::CalculateSize( -        true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; -    const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; -    const std::span<const u8> input_data(host_ptr, size_in_bytes); -    Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, -                                     framebuffer.width, framebuffer.height, 1, block_height_log2, -                                     0); - -    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); -    glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); - -    // Update existing texture -    // TODO: Test what happens on hardware when you change the framebuffer dimensions so that -    //       they differ from the LCD resolution. -    // TODO: Applications could theoretically crash yuzu here by specifying too large -    //       framebuffer sizes. We should make sure that this cannot happen. -    glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width, -                        framebuffer.height, framebuffer_texture.gl_format, -                        framebuffer_texture.gl_type, gl_framebuffer_data.data()); - -    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - -    return info; -} - -void RendererOpenGL::InitOpenGLObjects() { -    // Create shader programs -    fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER); -    fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER); - -    const auto replace_include = [](std::string& shader_source, std::string_view include_name, -                                    std::string_view include_content) { -        const std::string include_string = fmt::format("#include \"{}\"", include_name); -        const std::size_t pos = shader_source.find(include_string); -        ASSERT(pos != std::string::npos); -        shader_source.replace(pos, include_string.size(), include_content); -    }; - -    const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) { -        std::string shader_source{specialized_source}; -        replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL); -        return CreateProgram(shader_source, stage); -    }; - -    smaa_edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER); -    smaa_edge_detection_frag = -        SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER); -    smaa_blending_weight_calculation_vert = -        SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER); -    smaa_blending_weight_calculation_frag = -        SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER); -    smaa_neighborhood_blending_vert = -        SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER); -    smaa_neighborhood_blending_frag = -        SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); - -    present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); -    present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER); -    present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER); -    present_gaussian_fragment = -        CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER); -    present_scaleforce_fragment = -        CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), -                      GL_FRAGMENT_SHADER); - -    std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG}; -    replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H); -    replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H); - -    std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG}; -    std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG}; -    replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); -    replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source); - -    fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source, -                                fsr_rcas_frag_source); - -    // Generate presentation sampler -    present_sampler.Create(); -    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -    glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - -    present_sampler_nn.Create(); -    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -    glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - -    // Generate VBO handle for drawing -    vertex_buffer.Create(); - -    // Attach vertex data to VAO -    glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); - -    // Allocate textures for the screen -    framebuffer_texture.resource.Create(GL_TEXTURE_2D); - -    const GLuint texture = framebuffer_texture.resource.handle; -    glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); - -    // Clear screen to black -    const u8 framebuffer_data[4] = {0, 0, 0, 0}; -    glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, -                    framebuffer_data); - -    aa_framebuffer.Create(); - -    smaa_area_tex.Create(GL_TEXTURE_2D); -    glTextureStorage2D(smaa_area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); -    glTextureSubImage2D(smaa_area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG, -                        GL_UNSIGNED_BYTE, areaTexBytes); -    smaa_search_tex.Create(GL_TEXTURE_2D); -    glTextureStorage2D(smaa_search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT); -    glTextureSubImage2D(smaa_search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED, -                        GL_UNSIGNED_BYTE, searchTexBytes); -} -  void RendererOpenGL::AddTelemetryFields() {      const char* const gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))};      const char* const gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))}; @@ -373,283 +154,6 @@ void RendererOpenGL::AddTelemetryFields() {      telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));  } -void RendererOpenGL::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) { -    framebuffer_texture.width = framebuffer.width; -    framebuffer_texture.height = framebuffer.height; -    framebuffer_texture.pixel_format = framebuffer.pixel_format; - -    const auto pixel_format{ -        VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; -    const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; -    gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height * -                               bytes_per_pixel); - -    GLint internal_format; -    switch (framebuffer.pixel_format) { -    case Service::android::PixelFormat::Rgba8888: -        internal_format = GL_RGBA8; -        framebuffer_texture.gl_format = GL_RGBA; -        framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; -        break; -    case Service::android::PixelFormat::Rgb565: -        internal_format = GL_RGB565; -        framebuffer_texture.gl_format = GL_RGB; -        framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; -        break; -    default: -        internal_format = GL_RGBA8; -        framebuffer_texture.gl_format = GL_RGBA; -        framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; -        // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", -        //                   static_cast<u32>(framebuffer.pixel_format)); -        break; -    } - -    framebuffer_texture.resource.Release(); -    framebuffer_texture.resource.Create(GL_TEXTURE_2D); -    glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, -                       framebuffer_texture.width, framebuffer_texture.height); -    aa_texture.Release(); -    aa_texture.Create(GL_TEXTURE_2D); -    glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F, -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); -    glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0); -    smaa_edges_tex.Release(); -    smaa_edges_tex.Create(GL_TEXTURE_2D); -    glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F, -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); -    smaa_blend_tex.Release(); -    smaa_blend_tex.Create(GL_TEXTURE_2D); -    glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F, -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), -                       Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); -} - -void RendererOpenGL::DrawScreen(const Tegra::FramebufferConfig& framebuffer, -                                const Layout::FramebufferLayout& layout) { -    FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); -    const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); - -    // TODO: Signal state tracker about these changes -    state_tracker.NotifyScreenDrawVertexArray(); -    state_tracker.NotifyPolygonModes(); -    state_tracker.NotifyViewport0(); -    state_tracker.NotifyScissor0(); -    state_tracker.NotifyColorMask(0); -    state_tracker.NotifyBlend0(); -    state_tracker.NotifyFramebuffer(); -    state_tracker.NotifyFrontFace(); -    state_tracker.NotifyCullTest(); -    state_tracker.NotifyDepthTest(); -    state_tracker.NotifyStencilTest(); -    state_tracker.NotifyPolygonOffset(); -    state_tracker.NotifyRasterizeEnable(); -    state_tracker.NotifyFramebufferSRGB(); -    state_tracker.NotifyLogicOp(); -    state_tracker.NotifyClipControl(); -    state_tracker.NotifyAlphaTest(); - -    state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); - -    glEnable(GL_CULL_FACE); -    glDisable(GL_COLOR_LOGIC_OP); -    glDisable(GL_DEPTH_TEST); -    glDisable(GL_STENCIL_TEST); -    glDisable(GL_POLYGON_OFFSET_FILL); -    glDisable(GL_RASTERIZER_DISCARD); -    glDisable(GL_ALPHA_TEST); -    glDisablei(GL_BLEND, 0); -    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -    glCullFace(GL_BACK); -    glFrontFace(GL_CW); -    glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -    glDepthRangeIndexed(0, 0.0, 0.0); - -    glBindTextureUnit(0, info.display_texture); - -    auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); -    if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { -        LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing); -        anti_aliasing = Settings::AntiAliasing::None; -        Settings::values.anti_aliasing.SetValue(anti_aliasing); -    } - -    if (anti_aliasing != Settings::AntiAliasing::None) { -        glEnablei(GL_SCISSOR_TEST, 0); -        auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); -        auto viewport_width = static_cast<GLfloat>(scissor_width); -        auto scissor_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height); -        auto viewport_height = static_cast<GLfloat>(scissor_height); - -        glScissorIndexed(0, 0, 0, scissor_width, scissor_height); -        glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); - -        glBindSampler(0, present_sampler.handle); -        GLint old_read_fb; -        GLint old_draw_fb; -        glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); -        glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); - -        switch (anti_aliasing) { -        case Settings::AntiAliasing::Fxaa: { -            program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle); -            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle); -            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -        } break; -        case Settings::AntiAliasing::Smaa: { -            glClearColor(0, 0, 0, 0); -            glFrontFace(GL_CCW); -            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle); -            glBindSampler(1, present_sampler.handle); -            glBindSampler(2, present_sampler.handle); - -            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, -                                      smaa_edges_tex.handle, 0); -            glClear(GL_COLOR_BUFFER_BIT); -            program_manager.BindPresentPrograms(smaa_edge_detection_vert.handle, -                                                smaa_edge_detection_frag.handle); -            glDrawArrays(GL_TRIANGLES, 0, 3); - -            glBindTextureUnit(0, smaa_edges_tex.handle); -            glBindTextureUnit(1, smaa_area_tex.handle); -            glBindTextureUnit(2, smaa_search_tex.handle); -            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, -                                      smaa_blend_tex.handle, 0); -            glClear(GL_COLOR_BUFFER_BIT); -            program_manager.BindPresentPrograms(smaa_blending_weight_calculation_vert.handle, -                                                smaa_blending_weight_calculation_frag.handle); -            glDrawArrays(GL_TRIANGLES, 0, 3); - -            glBindTextureUnit(0, info.display_texture); -            glBindTextureUnit(1, smaa_blend_tex.handle); -            glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, -                                      aa_texture.handle, 0); -            program_manager.BindPresentPrograms(smaa_neighborhood_blending_vert.handle, -                                                smaa_neighborhood_blending_frag.handle); -            glDrawArrays(GL_TRIANGLES, 0, 3); -            glFrontFace(GL_CW); -        } break; -        default: -            UNREACHABLE(); -        } - -        glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); -        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); - -        glBindTextureUnit(0, aa_texture.handle); -    } -    glDisablei(GL_SCISSOR_TEST, 0); - -    if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { -        if (!fsr->AreBuffersInitialized()) { -            fsr->InitBuffers(); -        } - -        glBindSampler(0, present_sampler.handle); -        fsr->Draw(program_manager, layout.screen, info.scaled_width, info.scaled_height, crop); -    } else { -        if (fsr->AreBuffersInitialized()) { -            fsr->ReleaseBuffers(); -        } -    } - -    const std::array ortho_matrix = -        MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); - -    const auto fragment_handle = [this]() { -        switch (Settings::values.scaling_filter.GetValue()) { -        case Settings::ScalingFilter::NearestNeighbor: -        case Settings::ScalingFilter::Bilinear: -            return present_bilinear_fragment.handle; -        case Settings::ScalingFilter::Bicubic: -            return present_bicubic_fragment.handle; -        case Settings::ScalingFilter::Gaussian: -            return present_gaussian_fragment.handle; -        case Settings::ScalingFilter::ScaleForce: -            return present_scaleforce_fragment.handle; -        case Settings::ScalingFilter::Fsr: -            return fsr->GetPresentFragmentProgram().handle; -        default: -            return present_bilinear_fragment.handle; -        } -    }(); -    program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); -    glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, -                                ortho_matrix.data()); - -    f32 left, top, right, bottom; -    if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { -        // FSR has already applied the crop, so we just want to render the image -        // it has produced. -        left = 0; -        top = 0; -        right = 1; -        bottom = 1; -    } else { -        // Apply the precomputed crop. -        left = crop.left; -        top = crop.top; -        right = crop.right; -        bottom = crop.bottom; -    } - -    // Map the coordinates to the screen. -    const auto& screen = layout.screen; -    const auto x = screen.left; -    const auto y = screen.top; -    const auto w = screen.GetWidth(); -    const auto h = screen.GetHeight(); - -    const std::array vertices = { -        ScreenRectVertex(x, y, left, top), -        ScreenRectVertex(x + w, y, right, top), -        ScreenRectVertex(x, y + h, left, bottom), -        ScreenRectVertex(x + w, y + h, right, bottom), -    }; -    glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); - -    glDisable(GL_FRAMEBUFFER_SRGB); -    glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), -                       static_cast<GLfloat>(layout.height)); - -    glEnableVertexAttribArray(PositionLocation); -    glEnableVertexAttribArray(TexCoordLocation); -    glVertexAttribDivisor(PositionLocation, 0); -    glVertexAttribDivisor(TexCoordLocation, 0); -    glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, -                         offsetof(ScreenRectVertex, position)); -    glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, -                         offsetof(ScreenRectVertex, tex_coord)); -    glVertexAttribBinding(PositionLocation, 0); -    glVertexAttribBinding(TexCoordLocation, 0); -    if (device.HasVertexBufferUnifiedMemory()) { -        glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); -        glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, -                               sizeof(vertices)); -    } else { -        glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); -    } - -    if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { -        glBindSampler(0, present_sampler.handle); -    } else { -        glBindSampler(0, present_sampler_nn.handle); -    } - -    // Update background color before drawing -    glClearColor(Settings::values.bg_red.GetValue() / 255.0f, -                 Settings::values.bg_green.GetValue() / 255.0f, -                 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); - -    glClear(GL_COLOR_BUFFER_BIT); -    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - -    // TODO -    // program_manager.RestoreGuestPipeline(); -} -  void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) {      if (!renderer_settings.screenshot_requested) {          return; @@ -672,7 +176,7 @@ void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffe      glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height);      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); -    DrawScreen(framebuffer, layout); +    blit_screen->DrawScreen(framebuffer, layout);      glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);      glPixelStorei(GL_PACK_ROW_LENGTH, 0); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 3a83a9b78..23aff055a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -25,38 +25,13 @@ namespace Core::Frontend {  class EmuWindow;  } -namespace Core::Memory { -class Memory; -} - -namespace Layout { -struct FramebufferLayout; -} -  namespace Tegra {  class GPU;  }  namespace OpenGL { -/// Structure used for storing information about the textures for the Switch screen -struct TextureInfo { -    OGLTexture resource; -    GLsizei width; -    GLsizei height; -    GLenum gl_format; -    GLenum gl_type; -    Service::android::PixelFormat pixel_format; -}; - -/// Structure used for storing information about the display target for the Switch screen -struct FramebufferTextureInfo { -    GLuint display_texture{}; -    u32 width; -    u32 height; -    u32 scaled_width; -    u32 scaled_height; -}; +class BlitScreen;  class RendererOpenGL final : public VideoCore::RendererBase {  public: @@ -77,24 +52,9 @@ public:      }  private: -    /// Initializes the OpenGL state and creates persistent objects. -    void InitOpenGLObjects(); -      void AddTelemetryFields(); - -    void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); - -    /// Draws the emulated screens to the emulator window. -    void DrawScreen(const Tegra::FramebufferConfig& framebuffer, -                    const Layout::FramebufferLayout& layout); -      void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); -    /// Loads framebuffer from emulated memory into the active OpenGL texture. -    FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); - -    FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); -      Core::TelemetrySession& telemetry_session;      Core::Frontend::EmuWindow& emu_window;      Tegra::MaxwellDeviceMemoryManager& device_memory; @@ -104,43 +64,9 @@ private:      StateTracker state_tracker;      ProgramManager program_manager;      RasterizerOpenGL rasterizer; - -    // OpenGL object IDs -    OGLSampler present_sampler; -    OGLSampler present_sampler_nn; -    OGLBuffer vertex_buffer; -    OGLProgram fxaa_vertex; -    OGLProgram fxaa_fragment; -    OGLProgram present_vertex; -    OGLProgram present_bilinear_fragment; -    OGLProgram present_bicubic_fragment; -    OGLProgram present_gaussian_fragment; -    OGLProgram present_scaleforce_fragment;      OGLFramebuffer screenshot_framebuffer; -    // GPU address of the vertex buffer -    GLuint64EXT vertex_buffer_address = 0; - -    /// Display information for Switch screen -    TextureInfo framebuffer_texture; -    OGLTexture aa_texture; -    OGLFramebuffer aa_framebuffer; - -    OGLProgram smaa_edge_detection_vert; -    OGLProgram smaa_blending_weight_calculation_vert; -    OGLProgram smaa_neighborhood_blending_vert; -    OGLProgram smaa_edge_detection_frag; -    OGLProgram smaa_blending_weight_calculation_frag; -    OGLProgram smaa_neighborhood_blending_frag; -    OGLTexture smaa_area_tex; -    OGLTexture smaa_search_tex; -    OGLTexture smaa_edges_tex; -    OGLTexture smaa_blend_tex; - -    std::unique_ptr<FSR> fsr; - -    /// OpenGL framebuffer data -    std::vector<u8> gl_framebuffer_data; +    std::unique_ptr<BlitScreen> blit_screen;  };  } // namespace OpenGL | 
