video_core: simplify accelerated surface fetch and crop handling between APIs
This commit is contained in:
		| @@ -55,6 +55,7 @@ add_library(video_core STATIC | ||||
|     engines/maxwell_dma.h | ||||
|     engines/puller.cpp | ||||
|     engines/puller.h | ||||
|     framebuffer_config.cpp | ||||
|     framebuffer_config.h | ||||
|     fsr.cpp | ||||
|     fsr.h | ||||
|   | ||||
							
								
								
									
										55
									
								
								src/video_core/framebuffer_config.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/video_core/framebuffer_config.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include "common/assert.h" | ||||
| #include "video_core/framebuffer_config.h" | ||||
|  | ||||
| namespace Tegra { | ||||
|  | ||||
| Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width, | ||||
|                                      u32 texture_height) { | ||||
|     f32 left, top, right, bottom; | ||||
|  | ||||
|     if (!framebuffer.crop_rect.IsEmpty()) { | ||||
|         // If crop rectangle is not empty, apply properties from rectangle. | ||||
|         left = static_cast<f32>(framebuffer.crop_rect.left); | ||||
|         top = static_cast<f32>(framebuffer.crop_rect.top); | ||||
|         right = static_cast<f32>(framebuffer.crop_rect.right); | ||||
|         bottom = static_cast<f32>(framebuffer.crop_rect.bottom); | ||||
|     } else { | ||||
|         // Otherwise, fall back to framebuffer dimensions. | ||||
|         left = 0; | ||||
|         top = 0; | ||||
|         right = static_cast<f32>(framebuffer.width); | ||||
|         bottom = static_cast<f32>(framebuffer.height); | ||||
|     } | ||||
|  | ||||
|     // Apply transformation flags. | ||||
|     auto framebuffer_transform_flags = framebuffer.transform_flags; | ||||
|  | ||||
|     if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { | ||||
|         // Switch left and right. | ||||
|         std::swap(left, right); | ||||
|     } | ||||
|     if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { | ||||
|         // Switch top and bottom. | ||||
|         std::swap(top, bottom); | ||||
|     } | ||||
|  | ||||
|     framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; | ||||
|     framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; | ||||
|     if (True(framebuffer_transform_flags)) { | ||||
|         UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", | ||||
|                           static_cast<u32>(framebuffer_transform_flags)); | ||||
|     } | ||||
|  | ||||
|     // Normalize coordinate space. | ||||
|     left /= static_cast<f32>(texture_width); | ||||
|     top /= static_cast<f32>(texture_height); | ||||
|     right /= static_cast<f32>(texture_width); | ||||
|     bottom /= static_cast<f32>(texture_height); | ||||
|  | ||||
|     return Common::Rectangle<f32>(left, top, right, bottom); | ||||
| } | ||||
|  | ||||
| } // namespace Tegra | ||||
| @@ -24,4 +24,7 @@ struct FramebufferConfig { | ||||
|     Common::Rectangle<int> crop_rect; | ||||
| }; | ||||
|  | ||||
| Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width, | ||||
|                                      u32 texture_height); | ||||
|  | ||||
| } // namespace Tegra | ||||
|   | ||||
| @@ -155,12 +155,6 @@ public: | ||||
|     virtual void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||||
|                                           std::span<const u8> memory) = 0; | ||||
|  | ||||
|     /// Attempt to use a faster method to display the framebuffer to screen | ||||
|     [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                                  DAddr framebuffer_addr, u32 pixel_stride) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /// Initialize disk cached resources for the game being emulated | ||||
|     virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|                                    const DiskResourceLoadCallback& callback) {} | ||||
|   | ||||
| @@ -92,10 +92,6 @@ bool RasterizerNull::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surfac | ||||
| } | ||||
| void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||||
|                                               std::span<const u8> memory) {} | ||||
| bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                        DAddr framebuffer_addr, u32 pixel_stride) { | ||||
|     return true; | ||||
| } | ||||
| void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|                                        const VideoCore::DiskResourceLoadCallback& callback) {} | ||||
| void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) { | ||||
|   | ||||
| @@ -77,8 +77,6 @@ public: | ||||
|     Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | ||||
|     void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||||
|                                   std::span<const u8> memory) override; | ||||
|     bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||||
|                            u32 pixel_stride) override; | ||||
|     void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|                            const VideoCore::DiskResourceLoadCallback& callback) override; | ||||
|     void InitializeChannel(Tegra::Control::ChannelState& channel) override; | ||||
|   | ||||
| @@ -25,7 +25,7 @@ FSR::~FSR() = default; | ||||
|  | ||||
| void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | ||||
|                u32 input_image_width, u32 input_image_height, | ||||
|                const Common::Rectangle<int>& crop_rect) { | ||||
|                const Common::Rectangle<f32>& crop_rect) { | ||||
|  | ||||
|     const auto output_image_width = screen.GetWidth(); | ||||
|     const auto output_image_height = screen.GetHeight(); | ||||
| @@ -57,14 +57,19 @@ void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& sc | ||||
|     glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(output_image_width), | ||||
|                        static_cast<GLfloat>(output_image_height)); | ||||
|  | ||||
|     FsrConstants constants; | ||||
|     FsrEasuConOffset( | ||||
|         constants.data() + 0, constants.data() + 4, constants.data() + 8, constants.data() + 12, | ||||
|     const f32 input_width = static_cast<f32>(input_image_width); | ||||
|     const f32 input_height = static_cast<f32>(input_image_height); | ||||
|     const f32 output_width = static_cast<f32>(screen.GetWidth()); | ||||
|     const f32 output_height = static_cast<f32>(screen.GetHeight()); | ||||
|     const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_width; | ||||
|     const f32 viewport_x = crop_rect.left * input_width; | ||||
|     const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_height; | ||||
|     const f32 viewport_y = crop_rect.top * input_height; | ||||
|  | ||||
|         static_cast<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()), | ||||
|         static_cast<f32>(input_image_width), static_cast<f32>(input_image_height), | ||||
|         static_cast<f32>(output_image_width), static_cast<f32>(output_image_height), | ||||
|         static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top)); | ||||
|     FsrConstants constants; | ||||
|     FsrEasuConOffset(constants.data() + 0, constants.data() + 4, constants.data() + 8, | ||||
|                      constants.data() + 12, viewport_width, viewport_height, input_width, | ||||
|                      input_height, output_width, output_height, viewport_x, viewport_y); | ||||
|  | ||||
|     glProgramUniform4uiv(fsr_easu_frag.handle, 0, sizeof(constants), std::data(constants)); | ||||
|  | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public: | ||||
|  | ||||
|     void Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | ||||
|               u32 input_image_width, u32 input_image_height, | ||||
|               const Common::Rectangle<int>& crop_rect); | ||||
|               const Common::Rectangle<f32>& crop_rect); | ||||
|  | ||||
|     void InitBuffers(); | ||||
|  | ||||
|   | ||||
| @@ -71,10 +71,10 @@ std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryTy | ||||
|  | ||||
| RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | ||||
|                                    Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|                                    const Device& device_, ScreenInfo& screen_info_, | ||||
|                                    ProgramManager& program_manager_, StateTracker& state_tracker_) | ||||
|     : gpu(gpu_), device_memory(device_memory_), device(device_), screen_info(screen_info_), | ||||
|       program_manager(program_manager_), state_tracker(state_tracker_), | ||||
|                                    const Device& device_, ProgramManager& program_manager_, | ||||
|                                    StateTracker& state_tracker_) | ||||
|     : gpu(gpu_), device_memory(device_memory_), device(device_), program_manager(program_manager_), | ||||
|       state_tracker(state_tracker_), | ||||
|       texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool), | ||||
|       texture_cache(texture_cache_runtime, device_memory_), | ||||
|       buffer_cache_runtime(device, staging_buffer_pool), | ||||
| @@ -739,10 +739,10 @@ void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si | ||||
|     query_cache.InvalidateRegion(*cpu_addr, copy_size); | ||||
| } | ||||
|  | ||||
| bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                          DAddr framebuffer_addr, u32 pixel_stride) { | ||||
| std::optional<FramebufferTextureInfo> RasterizerOpenGL::AccelerateDisplay( | ||||
|     const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { | ||||
|     if (framebuffer_addr == 0) { | ||||
|         return false; | ||||
|         return {}; | ||||
|     } | ||||
|     MICROPROFILE_SCOPE(OpenGL_CacheManagement); | ||||
|  | ||||
| @@ -750,16 +750,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|     ImageView* const image_view{ | ||||
|         texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)}; | ||||
|     if (!image_view) { | ||||
|         return false; | ||||
|         return {}; | ||||
|     } | ||||
|     // Verify that the cached surface is the same size and format as the requested framebuffer | ||||
|     // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different"); | ||||
|     // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different"); | ||||
|  | ||||
|     screen_info.texture.width = image_view->size.width; | ||||
|     screen_info.texture.height = image_view->size.height; | ||||
|     screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); | ||||
|     return true; | ||||
|     FramebufferTextureInfo info{}; | ||||
|     info.display_texture = image_view->Handle(Shader::TextureType::Color2D); | ||||
|     info.width = image_view->size.width; | ||||
|     info.height = image_view->size.height; | ||||
|     return info; | ||||
| } | ||||
|  | ||||
| void RasterizerOpenGL::SyncState() { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ class MemoryManager; | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| struct ScreenInfo; | ||||
| struct FramebufferTextureInfo; | ||||
| struct ShaderEntries; | ||||
|  | ||||
| struct BindlessSSBO { | ||||
| @@ -76,8 +76,8 @@ class RasterizerOpenGL : public VideoCore::RasterizerInterface, | ||||
| public: | ||||
|     explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | ||||
|                               Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|                               const Device& device_, ScreenInfo& screen_info_, | ||||
|                               ProgramManager& program_manager_, StateTracker& state_tracker_); | ||||
|                               const Device& device_, ProgramManager& program_manager_, | ||||
|                               StateTracker& state_tracker_); | ||||
|     ~RasterizerOpenGL() override; | ||||
|  | ||||
|     void Draw(bool is_indexed, u32 instance_count) override; | ||||
| @@ -122,8 +122,6 @@ public: | ||||
|     Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | ||||
|     void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||||
|                                   std::span<const u8> memory) override; | ||||
|     bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||||
|                            u32 pixel_stride) override; | ||||
|     void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|                            const VideoCore::DiskResourceLoadCallback& callback) override; | ||||
|  | ||||
| @@ -144,6 +142,10 @@ public: | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                                             VAddr framebuffer_addr, | ||||
|                                                             u32 pixel_stride); | ||||
|  | ||||
| private: | ||||
|     static constexpr size_t MAX_TEXTURES = 192; | ||||
|     static constexpr size_t MAX_IMAGES = 48; | ||||
| @@ -237,7 +239,6 @@ private: | ||||
|     Tegra::MaxwellDeviceMemoryManager& device_memory; | ||||
|  | ||||
|     const Device& device; | ||||
|     ScreenInfo& screen_info; | ||||
|     ProgramManager& program_manager; | ||||
|     StateTracker& state_tracker; | ||||
|  | ||||
|   | ||||
| @@ -148,8 +148,7 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | ||||
|     : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, | ||||
|       emu_window{emu_window_}, device_memory{device_memory_}, gpu{gpu_}, device{emu_window_}, | ||||
|       state_tracker{}, program_manager{device}, | ||||
|       rasterizer(emu_window, gpu, device_memory, device, screen_info, program_manager, | ||||
|                  state_tracker) { | ||||
|       rasterizer(emu_window, gpu, device_memory, device, program_manager, state_tracker) { | ||||
|     if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { | ||||
|         glEnable(GL_DEBUG_OUTPUT); | ||||
|         glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | ||||
| @@ -184,11 +183,11 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     if (!framebuffer) { | ||||
|         return; | ||||
|     } | ||||
|     PrepareRendertarget(framebuffer); | ||||
|     RenderScreenshot(); | ||||
|  | ||||
|     RenderScreenshot(*framebuffer); | ||||
|  | ||||
|     state_tracker.BindFramebuffer(0); | ||||
|     DrawScreen(emu_window.GetFramebufferLayout()); | ||||
|     DrawScreen(*framebuffer, emu_window.GetFramebufferLayout()); | ||||
|  | ||||
|     ++m_current_frame; | ||||
|  | ||||
| @@ -199,41 +198,37 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     render_window.OnFrameDisplayed(); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     if (!framebuffer) { | ||||
|         return; | ||||
|     } | ||||
| FramebufferTextureInfo RendererOpenGL::PrepareRenderTarget( | ||||
|     const Tegra::FramebufferConfig& framebuffer) { | ||||
|     // If framebuffer is provided, reload it from memory to a texture | ||||
|     if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | ||||
|         screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || | ||||
|         screen_info.texture.pixel_format != framebuffer->pixel_format || | ||||
|     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(screen_info.texture, *framebuffer); | ||||
|         ConfigureFramebufferTexture(framebuffer); | ||||
|     } | ||||
|  | ||||
|     // Load the framebuffer from memory, draw it to the screen, and swap buffers | ||||
|     LoadFBToScreenInfo(*framebuffer); | ||||
|     // Load the framebuffer from memory if needed | ||||
|     return LoadFBToScreenInfo(framebuffer); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | ||||
|     // Framebuffer orientation handling | ||||
|     framebuffer_transform_flags = framebuffer.transform_flags; | ||||
|     framebuffer_crop_rect = framebuffer.crop_rect; | ||||
|     framebuffer_width = framebuffer.width; | ||||
|     framebuffer_height = framebuffer.height; | ||||
|  | ||||
| FramebufferTextureInfo RendererOpenGL::LoadFBToScreenInfo( | ||||
|     const Tegra::FramebufferConfig& framebuffer) { | ||||
|     const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; | ||||
|     screen_info.was_accelerated = | ||||
|     const auto accelerated_info = | ||||
|         rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); | ||||
|     if (screen_info.was_accelerated) { | ||||
|         return; | ||||
|     if (accelerated_info) { | ||||
|         return *accelerated_info; | ||||
|     } | ||||
|  | ||||
|     // Reset the screen info's display texture to its own permanent texture | ||||
|     screen_info.display_texture = screen_info.texture.resource.handle; | ||||
|     FramebufferTextureInfo info{}; | ||||
|     info.display_texture = framebuffer_texture.resource.handle; | ||||
|     info.width = framebuffer.width; | ||||
|     info.height = framebuffer.height; | ||||
|  | ||||
|     // TODO(Rodrigo): Read this from HLE | ||||
|     constexpr u32 block_height_log2 = 4; | ||||
| @@ -256,17 +251,13 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | ||||
|     //       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(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width, | ||||
|                         framebuffer.height, screen_info.texture.gl_format, | ||||
|                         screen_info.texture.gl_type, gl_framebuffer_data.data()); | ||||
|     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); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | ||||
|                                                 const TextureInfo& texture) { | ||||
|     const u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r}; | ||||
|     glClearTexImage(texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); | ||||
|     return info; | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::InitOpenGLObjects() { | ||||
| @@ -343,15 +334,15 @@ void RendererOpenGL::InitOpenGLObjects() { | ||||
|     glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | ||||
|  | ||||
|     // Allocate textures for the screen | ||||
|     screen_info.texture.resource.Create(GL_TEXTURE_2D); | ||||
|     framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||||
|  | ||||
|     const GLuint texture = screen_info.texture.resource.handle; | ||||
|     const GLuint texture = framebuffer_texture.resource.handle; | ||||
|     glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); | ||||
|  | ||||
|     screen_info.display_texture = screen_info.texture.resource.handle; | ||||
|  | ||||
|     // Clear screen to black | ||||
|     LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture); | ||||
|     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(); | ||||
|  | ||||
| @@ -380,60 +371,65 @@ void RendererOpenGL::AddTelemetryFields() { | ||||
|     telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | ||||
|                                                  const Tegra::FramebufferConfig& framebuffer) { | ||||
|     texture.width = framebuffer.width; | ||||
|     texture.height = framebuffer.height; | ||||
|     texture.pixel_format = framebuffer.pixel_format; | ||||
| 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(texture.width * texture.height * bytes_per_pixel); | ||||
|     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; | ||||
|         texture.gl_format = GL_RGBA; | ||||
|         texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||||
|         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; | ||||
|         texture.gl_format = GL_RGB; | ||||
|         texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; | ||||
|         framebuffer_texture.gl_format = GL_RGB; | ||||
|         framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; | ||||
|         break; | ||||
|     default: | ||||
|         internal_format = GL_RGBA8; | ||||
|         texture.gl_format = GL_RGBA; | ||||
|         texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||||
|         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; | ||||
|     } | ||||
|  | ||||
|     texture.resource.Release(); | ||||
|     texture.resource.Create(GL_TEXTURE_2D); | ||||
|     glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height); | ||||
|     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(screen_info.texture.width), | ||||
|                        Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | ||||
|                        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(screen_info.texture.width), | ||||
|                        Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | ||||
|                        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(screen_info.texture.width), | ||||
|                        Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | ||||
|                        Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||||
|                        Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
| 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(); | ||||
| @@ -469,7 +465,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||||
|     glDepthRangeIndexed(0, 0.0, 0.0); | ||||
|  | ||||
|     glBindTextureUnit(0, screen_info.display_texture); | ||||
|     glBindTextureUnit(0, info.display_texture); | ||||
|  | ||||
|     auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | ||||
|     if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { | ||||
| @@ -480,22 +476,22 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|  | ||||
|     if (anti_aliasing != Settings::AntiAliasing::None) { | ||||
|         glEnablei(GL_SCISSOR_TEST, 0); | ||||
|         auto viewport_width = screen_info.texture.width; | ||||
|         auto scissor_width = framebuffer_crop_rect.GetWidth(); | ||||
|         auto viewport_width = info.width; | ||||
|         auto scissor_width = static_cast<u32>(crop.GetWidth()); | ||||
|         if (scissor_width <= 0) { | ||||
|             scissor_width = viewport_width; | ||||
|         } | ||||
|         auto viewport_height = screen_info.texture.height; | ||||
|         auto scissor_height = framebuffer_crop_rect.GetHeight(); | ||||
|         auto viewport_height = info.height; | ||||
|         auto scissor_height = static_cast<u32>(crop.GetHeight()); | ||||
|         if (scissor_height <= 0) { | ||||
|             scissor_height = viewport_height; | ||||
|         } | ||||
|         if (screen_info.was_accelerated) { | ||||
|             viewport_width = Settings::values.resolution_info.ScaleUp(viewport_width); | ||||
|             scissor_width = Settings::values.resolution_info.ScaleUp(scissor_width); | ||||
|             viewport_height = Settings::values.resolution_info.ScaleUp(viewport_height); | ||||
|             scissor_height = Settings::values.resolution_info.ScaleUp(scissor_height); | ||||
|         } | ||||
|  | ||||
|         viewport_width = Settings::values.resolution_info.ScaleUp(viewport_width); | ||||
|         scissor_width = Settings::values.resolution_info.ScaleUp(scissor_width); | ||||
|         viewport_height = Settings::values.resolution_info.ScaleUp(viewport_height); | ||||
|         scissor_height = Settings::values.resolution_info.ScaleUp(scissor_height); | ||||
|  | ||||
|         glScissorIndexed(0, 0, 0, scissor_width, scissor_height); | ||||
|         glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width), | ||||
|                            static_cast<GLfloat>(viewport_height)); | ||||
| @@ -536,7 +532,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|                                                 smaa_blending_weight_calculation_frag.handle); | ||||
|             glDrawArrays(GL_TRIANGLES, 0, 3); | ||||
|  | ||||
|             glBindTextureUnit(0, screen_info.display_texture); | ||||
|             glBindTextureUnit(0, info.display_texture); | ||||
|             glBindTextureUnit(1, smaa_blend_tex.handle); | ||||
|             glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, | ||||
|                                       aa_texture.handle, 0); | ||||
| @@ -561,18 +557,10 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|             fsr->InitBuffers(); | ||||
|         } | ||||
|  | ||||
|         auto crop_rect = framebuffer_crop_rect; | ||||
|         if (crop_rect.GetWidth() == 0) { | ||||
|             crop_rect.right = framebuffer_width; | ||||
|         } | ||||
|         if (crop_rect.GetHeight() == 0) { | ||||
|             crop_rect.bottom = framebuffer_height; | ||||
|         } | ||||
|         crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); | ||||
|         const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(framebuffer_width); | ||||
|         const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(framebuffer_height); | ||||
|         const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(info.width); | ||||
|         const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(info.height); | ||||
|         glBindSampler(0, present_sampler.handle); | ||||
|         fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop_rect); | ||||
|         fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop); | ||||
|     } else { | ||||
|         if (fsr->AreBuffersInitialized()) { | ||||
|             fsr->ReleaseBuffers(); | ||||
| @@ -603,61 +591,34 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||||
|                                 ortho_matrix.data()); | ||||
|  | ||||
|     const auto& texcoords = screen_info.display_texcoords; | ||||
|     auto left = texcoords.left; | ||||
|     auto right = texcoords.right; | ||||
|     if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) { | ||||
|         if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) { | ||||
|             // Flip the framebuffer vertically | ||||
|             left = texcoords.right; | ||||
|             right = texcoords.left; | ||||
|         } else { | ||||
|             // Other transformations are unsupported | ||||
|             LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}", | ||||
|                          framebuffer_transform_flags); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented"); | ||||
|  | ||||
|     f32 left_start{}; | ||||
|     if (framebuffer_crop_rect.Top() > 0) { | ||||
|         left_start = static_cast<f32>(framebuffer_crop_rect.Top()) / | ||||
|                      static_cast<f32>(framebuffer_crop_rect.Bottom()); | ||||
|     } | ||||
|     f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); | ||||
|     f32 scale_v = | ||||
|         static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); | ||||
|  | ||||
|     if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::Fsr) { | ||||
|         // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering | ||||
|         // (e.g. handheld mode) on a 1920x1080 framebuffer. | ||||
|         if (framebuffer_crop_rect.GetWidth() > 0) { | ||||
|             scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / | ||||
|                       static_cast<f32>(screen_info.texture.width); | ||||
|         } | ||||
|         if (framebuffer_crop_rect.GetHeight() > 0) { | ||||
|             scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | ||||
|                       static_cast<f32>(screen_info.texture.height); | ||||
|         } | ||||
|     } | ||||
|     if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa && | ||||
|         !screen_info.was_accelerated) { | ||||
|         scale_u /= Settings::values.resolution_info.up_factor; | ||||
|         scale_v /= Settings::values.resolution_info.up_factor; | ||||
|     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(screen.left, screen.top, texcoords.top * scale_u, | ||||
|                          left_start + left * scale_v), | ||||
|         ScreenRectVertex(screen.right, screen.top, texcoords.bottom * scale_u, | ||||
|                          left_start + left * scale_v), | ||||
|         ScreenRectVertex(screen.left, screen.bottom, texcoords.top * scale_u, | ||||
|                          left_start + right * scale_v), | ||||
|         ScreenRectVertex(screen.right, screen.bottom, texcoords.bottom * scale_u, | ||||
|                          left_start + right * scale_v), | ||||
|         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)); | ||||
|  | ||||
| @@ -701,7 +662,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     // program_manager.RestoreGuestPipeline(); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::RenderScreenshot() { | ||||
| void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { | ||||
|     if (!renderer_settings.screenshot_requested) { | ||||
|         return; | ||||
|     } | ||||
| @@ -723,7 +684,7 @@ void RendererOpenGL::RenderScreenshot() { | ||||
|     glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); | ||||
|     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); | ||||
|  | ||||
|     DrawScreen(layout); | ||||
|     DrawScreen(framebuffer, layout); | ||||
|  | ||||
|     glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | ||||
|     glPixelStorei(GL_PACK_ROW_LENGTH, 0); | ||||
|   | ||||
| @@ -50,11 +50,10 @@ struct TextureInfo { | ||||
| }; | ||||
|  | ||||
| /// Structure used for storing information about the display target for the Switch screen | ||||
| struct ScreenInfo { | ||||
| struct FramebufferTextureInfo { | ||||
|     GLuint display_texture{}; | ||||
|     bool was_accelerated = false; | ||||
|     const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; | ||||
|     TextureInfo texture; | ||||
|     u32 width; | ||||
|     u32 height; | ||||
| }; | ||||
|  | ||||
| class RendererOpenGL final : public VideoCore::RendererBase { | ||||
| @@ -81,23 +80,18 @@ private: | ||||
|  | ||||
|     void AddTelemetryFields(); | ||||
|  | ||||
|     void ConfigureFramebufferTexture(TextureInfo& texture, | ||||
|                                      const Tegra::FramebufferConfig& framebuffer); | ||||
|     void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     /// Draws the emulated screens to the emulator window. | ||||
|     void DrawScreen(const Layout::FramebufferLayout& layout); | ||||
|     void DrawScreen(const Tegra::FramebufferConfig& framebuffer, | ||||
|                     const Layout::FramebufferLayout& layout); | ||||
|  | ||||
|     void RenderScreenshot(); | ||||
|     void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     /// Loads framebuffer from emulated memory into the active OpenGL texture. | ||||
|     void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | ||||
|     FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     /// Fills active OpenGL texture with the given RGB color.Since the color is solid, the texture | ||||
|     /// can be 1x1 but will stretch across whatever it's rendered on. | ||||
|     void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | ||||
|                                     const TextureInfo& texture); | ||||
|  | ||||
|     void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | ||||
|     FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     Core::TelemetrySession& telemetry_session; | ||||
|     Core::Frontend::EmuWindow& emu_window; | ||||
| @@ -126,7 +120,7 @@ private: | ||||
|     GLuint64EXT vertex_buffer_address = 0; | ||||
|  | ||||
|     /// Display information for Switch screen | ||||
|     ScreenInfo screen_info; | ||||
|     TextureInfo framebuffer_texture; | ||||
|     OGLTexture aa_texture; | ||||
|     OGLFramebuffer aa_framebuffer; | ||||
|  | ||||
| @@ -145,12 +139,6 @@ private: | ||||
|  | ||||
|     /// OpenGL framebuffer data | ||||
|     std::vector<u8> gl_framebuffer_data; | ||||
|  | ||||
|     /// Used for transforming the framebuffer orientation | ||||
|     Service::android::BufferTransformFlags framebuffer_transform_flags{}; | ||||
|     Common::Rectangle<int> framebuffer_crop_rect; | ||||
|     u32 framebuffer_width; | ||||
|     u32 framebuffer_height; | ||||
| }; | ||||
|  | ||||
| } // namespace OpenGL | ||||
|   | ||||
| @@ -98,9 +98,9 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | ||||
|       present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | ||||
|                       surface), | ||||
|       blit_screen(device_memory, render_window, device, memory_allocator, swapchain, | ||||
|                   present_manager, scheduler, screen_info), | ||||
|       rasterizer(render_window, gpu, device_memory, screen_info, device, memory_allocator, | ||||
|                  state_tracker, scheduler) { | ||||
|                   present_manager, scheduler), | ||||
|       rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, | ||||
|                  scheduler) { | ||||
|     if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { | ||||
|         turbo_mode.emplace(instance, dld); | ||||
|         scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); | ||||
| @@ -124,17 +124,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     if (!render_window.IsShown()) { | ||||
|         return; | ||||
|     } | ||||
|     // Update screen info if the framebuffer size has changed. | ||||
|     screen_info.width = framebuffer->width; | ||||
|     screen_info.height = framebuffer->height; | ||||
|  | ||||
|     const DAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | ||||
|     const bool use_accelerated = | ||||
|         rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); | ||||
|     RenderScreenshot(*framebuffer, use_accelerated); | ||||
|  | ||||
|     RenderScreenshot(*framebuffer); | ||||
|     Frame* frame = present_manager.GetRenderFrame(); | ||||
|     blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated); | ||||
|     blit_screen.DrawToSwapchain(rasterizer, frame, *framebuffer); | ||||
|     scheduler.Flush(*frame->render_ready); | ||||
|     present_manager.Present(frame); | ||||
|  | ||||
| @@ -168,8 +161,7 @@ void RendererVulkan::Report() const { | ||||
|     telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | ||||
| } | ||||
|  | ||||
| void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, | ||||
|                                               bool use_accelerated) { | ||||
| void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { | ||||
|     if (!renderer_settings.screenshot_requested) { | ||||
|         return; | ||||
|     } | ||||
| @@ -221,7 +213,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | ||||
|     }); | ||||
|     const VkExtent2D render_area{.width = layout.width, .height = layout.height}; | ||||
|     const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); | ||||
|     blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated); | ||||
|     blit_screen.Draw(rasterizer, framebuffer, *screenshot_fb, layout, render_area); | ||||
|  | ||||
|     const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | ||||
|     const VkBufferCreateInfo dst_buffer_info{ | ||||
|   | ||||
| @@ -59,7 +59,7 @@ public: | ||||
| private: | ||||
|     void Report() const; | ||||
|  | ||||
|     void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated); | ||||
|     void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     Core::TelemetrySession& telemetry_session; | ||||
|     Tegra::MaxwellDeviceMemoryManager& device_memory; | ||||
| @@ -72,8 +72,6 @@ private: | ||||
|     vk::DebugUtilsMessenger debug_messenger; | ||||
|     vk::SurfaceKHR surface; | ||||
|  | ||||
|     ScreenInfo screen_info; | ||||
|  | ||||
|     Device device; | ||||
|     MemoryAllocator memory_allocator; | ||||
|     StateTracker state_tracker; | ||||
|   | ||||
| @@ -124,11 +124,10 @@ struct BlitScreen::BufferData { | ||||
| BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|                        Core::Frontend::EmuWindow& render_window_, const Device& device_, | ||||
|                        MemoryAllocator& memory_allocator_, Swapchain& swapchain_, | ||||
|                        PresentManager& present_manager_, Scheduler& scheduler_, | ||||
|                        const ScreenInfo& screen_info_) | ||||
|                        PresentManager& present_manager_, Scheduler& scheduler_) | ||||
|     : device_memory{device_memory_}, render_window{render_window_}, device{device_}, | ||||
|       memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, | ||||
|       scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | ||||
|       scheduler{scheduler_}, image_count{swapchain.GetImageCount()} { | ||||
|     resource_ticks.resize(image_count); | ||||
|     swapchain_view_format = swapchain.GetImageViewFormat(); | ||||
|  | ||||
| @@ -138,56 +137,6 @@ BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|  | ||||
| BlitScreen::~BlitScreen() = default; | ||||
|  | ||||
| static Common::Rectangle<f32> NormalizeCrop(const Tegra::FramebufferConfig& framebuffer, | ||||
|                                             const ScreenInfo& screen_info) { | ||||
|     f32 left, top, right, bottom; | ||||
|  | ||||
|     if (!framebuffer.crop_rect.IsEmpty()) { | ||||
|         // If crop rectangle is not empty, apply properties from rectangle. | ||||
|         left = static_cast<f32>(framebuffer.crop_rect.left); | ||||
|         top = static_cast<f32>(framebuffer.crop_rect.top); | ||||
|         right = static_cast<f32>(framebuffer.crop_rect.right); | ||||
|         bottom = static_cast<f32>(framebuffer.crop_rect.bottom); | ||||
|     } else { | ||||
|         // Otherwise, fall back to framebuffer dimensions. | ||||
|         left = 0; | ||||
|         top = 0; | ||||
|         right = static_cast<f32>(framebuffer.width); | ||||
|         bottom = static_cast<f32>(framebuffer.height); | ||||
|     } | ||||
|  | ||||
|     // Apply transformation flags. | ||||
|     auto framebuffer_transform_flags = framebuffer.transform_flags; | ||||
|  | ||||
|     if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { | ||||
|         // Switch left and right. | ||||
|         std::swap(left, right); | ||||
|     } | ||||
|     if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { | ||||
|         // Switch top and bottom. | ||||
|         std::swap(top, bottom); | ||||
|     } | ||||
|  | ||||
|     framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; | ||||
|     framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; | ||||
|     if (True(framebuffer_transform_flags)) { | ||||
|         UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", | ||||
|                           static_cast<u32>(framebuffer_transform_flags)); | ||||
|     } | ||||
|  | ||||
|     // Get the screen properties. | ||||
|     const f32 screen_width = static_cast<f32>(screen_info.width); | ||||
|     const f32 screen_height = static_cast<f32>(screen_info.height); | ||||
|  | ||||
|     // Normalize coordinate space. | ||||
|     left /= screen_width; | ||||
|     top /= screen_height; | ||||
|     right /= screen_width; | ||||
|     bottom /= screen_height; | ||||
|  | ||||
|     return Common::Rectangle<f32>(left, top, right, bottom); | ||||
| } | ||||
|  | ||||
| void BlitScreen::Recreate() { | ||||
|     present_manager.WaitPresent(); | ||||
|     scheduler.Finish(); | ||||
| @@ -195,9 +144,16 @@ void BlitScreen::Recreate() { | ||||
|     CreateDynamicResources(); | ||||
| } | ||||
|  | ||||
| void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | ||||
| void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | ||||
|                       const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | ||||
|                       VkExtent2D render_area, bool use_accelerated) { | ||||
|                       VkExtent2D render_area) { | ||||
|  | ||||
|     const auto texture_info = rasterizer.AccelerateDisplay( | ||||
|         framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | ||||
|     const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | ||||
|     const u32 texture_height = texture_info ? texture_info->height : framebuffer.height; | ||||
|     const bool use_accelerated = texture_info.has_value(); | ||||
|  | ||||
|     RefreshResources(framebuffer); | ||||
|  | ||||
|     // Finish any pending renderpass | ||||
| @@ -206,13 +162,13 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | ||||
|     scheduler.Wait(resource_ticks[image_index]); | ||||
|     resource_ticks[image_index] = scheduler.CurrentTick(); | ||||
|  | ||||
|     VkImage source_image = use_accelerated ? screen_info.image : *raw_images[image_index]; | ||||
|     VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; | ||||
|     VkImageView source_image_view = | ||||
|         use_accelerated ? screen_info.image_view : *raw_image_views[image_index]; | ||||
|         texture_info ? texture_info->image_view : *raw_image_views[image_index]; | ||||
|  | ||||
|     BufferData data; | ||||
|     SetUniformData(data, layout); | ||||
|     SetVertexData(data, framebuffer, layout); | ||||
|     SetVertexData(data, framebuffer, layout, texture_width, texture_height); | ||||
|  | ||||
|     const std::span<u8> mapped_span = buffer.Mapped(); | ||||
|     std::memcpy(mapped_span.data(), &data, sizeof(data)); | ||||
| @@ -405,10 +361,10 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | ||||
|         source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); | ||||
|     } | ||||
|     if (fsr) { | ||||
|         const auto crop_rect = NormalizeCrop(framebuffer, screen_info); | ||||
|         const auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||||
|         const VkExtent2D fsr_input_size{ | ||||
|             .width = Settings::values.resolution_info.ScaleUp(screen_info.width), | ||||
|             .height = Settings::values.resolution_info.ScaleUp(screen_info.height), | ||||
|             .width = Settings::values.resolution_info.ScaleUp(texture_width), | ||||
|             .height = Settings::values.resolution_info.ScaleUp(texture_height), | ||||
|         }; | ||||
|         VkImageView fsr_image_view = | ||||
|             fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); | ||||
| @@ -480,8 +436,8 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | ||||
|     }); | ||||
| } | ||||
|  | ||||
| void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | ||||
|                                  bool use_accelerated) { | ||||
| void BlitScreen::DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, | ||||
|                                  const Tegra::FramebufferConfig& framebuffer) { | ||||
|     // Recreate dynamic resources if the the image count or input format changed | ||||
|     const VkFormat current_framebuffer_format = | ||||
|         std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | ||||
| @@ -500,7 +456,7 @@ void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& f | ||||
|     } | ||||
|  | ||||
|     const VkExtent2D render_area{frame->width, frame->height}; | ||||
|     Draw(framebuffer, *frame->framebuffer, layout, render_area, use_accelerated); | ||||
|     Draw(rasterizer, framebuffer, *frame->framebuffer, layout, render_area); | ||||
|     if (++image_index >= image_count) { | ||||
|         image_index = 0; | ||||
|     } | ||||
| @@ -1434,7 +1390,8 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou | ||||
| } | ||||
|  | ||||
| void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | ||||
|                                const Layout::FramebufferLayout layout) const { | ||||
|                                const Layout::FramebufferLayout layout, u32 texture_width, | ||||
|                                u32 texture_height) const { | ||||
|     f32 left, top, right, bottom; | ||||
|  | ||||
|     if (fsr) { | ||||
| @@ -1446,7 +1403,7 @@ void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& | ||||
|         bottom = 1; | ||||
|     } else { | ||||
|         // Get the normalized crop rectangle. | ||||
|         const auto crop = NormalizeCrop(framebuffer, screen_info); | ||||
|         const auto crop = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||||
|  | ||||
|         // Apply the crop. | ||||
|         left = crop.left; | ||||
|   | ||||
| @@ -32,8 +32,6 @@ enum class PixelFormat : u32; | ||||
|  | ||||
| namespace Vulkan { | ||||
|  | ||||
| struct ScreenInfo; | ||||
|  | ||||
| class Device; | ||||
| class FSR; | ||||
| class RasterizerVulkan; | ||||
| @@ -44,7 +42,7 @@ class PresentManager; | ||||
|  | ||||
| struct Frame; | ||||
|  | ||||
| struct ScreenInfo { | ||||
| struct FramebufferTextureInfo { | ||||
|     VkImage image{}; | ||||
|     VkImageView image_view{}; | ||||
|     u32 width{}; | ||||
| @@ -56,17 +54,17 @@ public: | ||||
|     explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, | ||||
|                         Core::Frontend::EmuWindow& render_window, const Device& device, | ||||
|                         MemoryAllocator& memory_manager, Swapchain& swapchain, | ||||
|                         PresentManager& present_manager, Scheduler& scheduler, | ||||
|                         const ScreenInfo& screen_info); | ||||
|                         PresentManager& present_manager, Scheduler& scheduler); | ||||
|     ~BlitScreen(); | ||||
|  | ||||
|     void Recreate(); | ||||
|  | ||||
|     void Draw(const Tegra::FramebufferConfig& framebuffer, const VkFramebuffer& host_framebuffer, | ||||
|               const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); | ||||
|     void Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | ||||
|               const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | ||||
|               VkExtent2D render_area); | ||||
|  | ||||
|     void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | ||||
|                          bool use_accelerated); | ||||
|     void DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, | ||||
|                          const Tegra::FramebufferConfig& framebuffer); | ||||
|  | ||||
|     [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | ||||
|                                                     VkExtent2D extent); | ||||
| @@ -99,7 +97,8 @@ private: | ||||
|     void UpdateAADescriptorSet(VkImageView image_view, bool nn) const; | ||||
|     void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; | ||||
|     void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | ||||
|                        const Layout::FramebufferLayout layout) const; | ||||
|                        const Layout::FramebufferLayout layout, u32 texture_width, | ||||
|                        u32 texture_height) const; | ||||
|  | ||||
|     void CreateSMAA(VkExtent2D smaa_size); | ||||
|     void CreateFSR(); | ||||
| @@ -116,7 +115,6 @@ private: | ||||
|     Scheduler& scheduler; | ||||
|     std::size_t image_count; | ||||
|     std::size_t image_index{}; | ||||
|     const ScreenInfo& screen_info; | ||||
|  | ||||
|     vk::ShaderModule vertex_shader; | ||||
|     vk::ShaderModule fxaa_vertex_shader; | ||||
|   | ||||
| @@ -165,10 +165,9 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, | ||||
|  | ||||
| RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | ||||
|                                    Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|                                    ScreenInfo& screen_info_, const Device& device_, | ||||
|                                    MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | ||||
|                                    Scheduler& scheduler_) | ||||
|     : gpu{gpu_}, device_memory{device_memory_}, screen_info{screen_info_}, device{device_}, | ||||
|                                    const Device& device_, MemoryAllocator& memory_allocator_, | ||||
|                                    StateTracker& state_tracker_, Scheduler& scheduler_) | ||||
|     : gpu{gpu_}, device_memory{device_memory_}, device{device_}, | ||||
|       memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, | ||||
|       staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), | ||||
|       guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), | ||||
| @@ -783,23 +782,25 @@ void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si | ||||
|     query_cache.InvalidateRegion(*cpu_addr, copy_size); | ||||
| } | ||||
|  | ||||
| bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                          DAddr framebuffer_addr, u32 pixel_stride) { | ||||
| std::optional<FramebufferTextureInfo> RasterizerVulkan::AccelerateDisplay( | ||||
|     const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { | ||||
|     if (!framebuffer_addr) { | ||||
|         return false; | ||||
|         return {}; | ||||
|     } | ||||
|     std::scoped_lock lock{texture_cache.mutex}; | ||||
|     ImageView* const image_view = | ||||
|         texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); | ||||
|     if (!image_view) { | ||||
|         return false; | ||||
|         return {}; | ||||
|     } | ||||
|     query_cache.NotifySegment(false); | ||||
|     screen_info.image = image_view->ImageHandle(); | ||||
|     screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); | ||||
|     screen_info.width = image_view->size.width; | ||||
|     screen_info.height = image_view->size.height; | ||||
|     return true; | ||||
|  | ||||
|     FramebufferTextureInfo info{}; | ||||
|     info.image = image_view->ImageHandle(); | ||||
|     info.image_view = image_view->Handle(Shader::TextureType::Color2D); | ||||
|     info.width = image_view->size.width; | ||||
|     info.height = image_view->size.height; | ||||
|     return info; | ||||
| } | ||||
|  | ||||
| void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class Maxwell3D; | ||||
|  | ||||
| namespace Vulkan { | ||||
|  | ||||
| struct ScreenInfo; | ||||
| struct FramebufferTextureInfo; | ||||
|  | ||||
| class StateTracker; | ||||
|  | ||||
| @@ -78,9 +78,8 @@ class RasterizerVulkan final : public VideoCore::RasterizerInterface, | ||||
| public: | ||||
|     explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | ||||
|                               Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||
|                               ScreenInfo& screen_info_, const Device& device_, | ||||
|                               MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | ||||
|                               Scheduler& scheduler_); | ||||
|                               const Device& device_, MemoryAllocator& memory_allocator_, | ||||
|                               StateTracker& state_tracker_, Scheduler& scheduler_); | ||||
|     ~RasterizerVulkan() override; | ||||
|  | ||||
|     void Draw(bool is_indexed, u32 instance_count) override; | ||||
| @@ -126,8 +125,6 @@ public: | ||||
|     Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | ||||
|     void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||||
|                                   std::span<const u8> memory) override; | ||||
|     bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||||
|                            u32 pixel_stride) override; | ||||
|     void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|                            const VideoCore::DiskResourceLoadCallback& callback) override; | ||||
|  | ||||
| @@ -137,6 +134,10 @@ public: | ||||
|  | ||||
|     void ReleaseChannel(s32 channel_id) override; | ||||
|  | ||||
|     std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|                                                             VAddr framebuffer_addr, | ||||
|                                                             u32 pixel_stride); | ||||
|  | ||||
| private: | ||||
|     static constexpr size_t MAX_TEXTURES = 192; | ||||
|     static constexpr size_t MAX_IMAGES = 48; | ||||
| @@ -182,7 +183,6 @@ private: | ||||
|     Tegra::GPU& gpu; | ||||
|     Tegra::MaxwellDeviceMemoryManager& device_memory; | ||||
|  | ||||
|     ScreenInfo& screen_info; | ||||
|     const Device& device; | ||||
|     MemoryAllocator& memory_allocator; | ||||
|     StateTracker& state_tracker; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Liam
					Liam