diff options
| author | 2024-01-03 22:46:59 -0500 | |
|---|---|---|
| committer | 2024-01-31 11:27:20 -0500 | |
| commit | 80de01a5b4a7f57ec7850079fbd38fac76b9d08f (patch) | |
| tree | 18086d7a71ffcd9f5bc6651aec20de37e3b1c33d /src/video_core | |
| parent | Merge pull request #12760 from liamwhite/mp-am (diff) | |
| download | yuzu-80de01a5b4a7f57ec7850079fbd38fac76b9d08f.tar.gz yuzu-80de01a5b4a7f57ec7850079fbd38fac76b9d08f.tar.xz yuzu-80de01a5b4a7f57ec7850079fbd38fac76b9d08f.zip | |
video_core: simplify accelerated surface fetch and crop handling between APIs
Diffstat (limited to 'src/video_core')
18 files changed, 262 insertions, 316 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 0755ba772..36aa7bb66 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -55,6 +55,7 @@ add_library(video_core STATIC | |||
| 55 | engines/maxwell_dma.h | 55 | engines/maxwell_dma.h |
| 56 | engines/puller.cpp | 56 | engines/puller.cpp |
| 57 | engines/puller.h | 57 | engines/puller.h |
| 58 | framebuffer_config.cpp | ||
| 58 | framebuffer_config.h | 59 | framebuffer_config.h |
| 59 | fsr.cpp | 60 | fsr.cpp |
| 60 | fsr.h | 61 | fsr.h |
diff --git a/src/video_core/framebuffer_config.cpp b/src/video_core/framebuffer_config.cpp new file mode 100644 index 000000000..e28d41f84 --- /dev/null +++ b/src/video_core/framebuffer_config.cpp | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "video_core/framebuffer_config.h" | ||
| 6 | |||
| 7 | namespace Tegra { | ||
| 8 | |||
| 9 | Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width, | ||
| 10 | u32 texture_height) { | ||
| 11 | f32 left, top, right, bottom; | ||
| 12 | |||
| 13 | if (!framebuffer.crop_rect.IsEmpty()) { | ||
| 14 | // If crop rectangle is not empty, apply properties from rectangle. | ||
| 15 | left = static_cast<f32>(framebuffer.crop_rect.left); | ||
| 16 | top = static_cast<f32>(framebuffer.crop_rect.top); | ||
| 17 | right = static_cast<f32>(framebuffer.crop_rect.right); | ||
| 18 | bottom = static_cast<f32>(framebuffer.crop_rect.bottom); | ||
| 19 | } else { | ||
| 20 | // Otherwise, fall back to framebuffer dimensions. | ||
| 21 | left = 0; | ||
| 22 | top = 0; | ||
| 23 | right = static_cast<f32>(framebuffer.width); | ||
| 24 | bottom = static_cast<f32>(framebuffer.height); | ||
| 25 | } | ||
| 26 | |||
| 27 | // Apply transformation flags. | ||
| 28 | auto framebuffer_transform_flags = framebuffer.transform_flags; | ||
| 29 | |||
| 30 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { | ||
| 31 | // Switch left and right. | ||
| 32 | std::swap(left, right); | ||
| 33 | } | ||
| 34 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { | ||
| 35 | // Switch top and bottom. | ||
| 36 | std::swap(top, bottom); | ||
| 37 | } | ||
| 38 | |||
| 39 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; | ||
| 40 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; | ||
| 41 | if (True(framebuffer_transform_flags)) { | ||
| 42 | UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", | ||
| 43 | static_cast<u32>(framebuffer_transform_flags)); | ||
| 44 | } | ||
| 45 | |||
| 46 | // Normalize coordinate space. | ||
| 47 | left /= static_cast<f32>(texture_width); | ||
| 48 | top /= static_cast<f32>(texture_height); | ||
| 49 | right /= static_cast<f32>(texture_width); | ||
| 50 | bottom /= static_cast<f32>(texture_height); | ||
| 51 | |||
| 52 | return Common::Rectangle<f32>(left, top, right, bottom); | ||
| 53 | } | ||
| 54 | |||
| 55 | } // namespace Tegra | ||
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h index 856f4bd52..10ddc75a7 100644 --- a/src/video_core/framebuffer_config.h +++ b/src/video_core/framebuffer_config.h | |||
| @@ -24,4 +24,7 @@ struct FramebufferConfig { | |||
| 24 | Common::Rectangle<int> crop_rect; | 24 | Common::Rectangle<int> crop_rect; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width, | ||
| 28 | u32 texture_height); | ||
| 29 | |||
| 27 | } // namespace Tegra | 30 | } // namespace Tegra |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 8fa4e4d9a..6e2eccfbf 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -155,12 +155,6 @@ public: | |||
| 155 | virtual void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 155 | virtual void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 156 | std::span<const u8> memory) = 0; | 156 | std::span<const u8> memory) = 0; |
| 157 | 157 | ||
| 158 | /// Attempt to use a faster method to display the framebuffer to screen | ||
| 159 | [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 160 | DAddr framebuffer_addr, u32 pixel_stride) { | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | |||
| 164 | /// Initialize disk cached resources for the game being emulated | 158 | /// Initialize disk cached resources for the game being emulated |
| 165 | virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 159 | virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 166 | const DiskResourceLoadCallback& callback) {} | 160 | const DiskResourceLoadCallback& callback) {} |
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp index abfabb65b..a5cda0f38 100644 --- a/src/video_core/renderer_null/null_rasterizer.cpp +++ b/src/video_core/renderer_null/null_rasterizer.cpp | |||
| @@ -92,10 +92,6 @@ bool RasterizerNull::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surfac | |||
| 92 | } | 92 | } |
| 93 | void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 93 | void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 94 | std::span<const u8> memory) {} | 94 | std::span<const u8> memory) {} |
| 95 | bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 96 | DAddr framebuffer_addr, u32 pixel_stride) { | ||
| 97 | return true; | ||
| 98 | } | ||
| 99 | void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 95 | void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 100 | const VideoCore::DiskResourceLoadCallback& callback) {} | 96 | const VideoCore::DiskResourceLoadCallback& callback) {} |
| 101 | void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) { | 97 | void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) { |
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h index a5789604f..c7f5849c7 100644 --- a/src/video_core/renderer_null/null_rasterizer.h +++ b/src/video_core/renderer_null/null_rasterizer.h | |||
| @@ -77,8 +77,6 @@ public: | |||
| 77 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | 77 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; |
| 78 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 78 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 79 | std::span<const u8> memory) override; | 79 | std::span<const u8> memory) override; |
| 80 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||
| 81 | u32 pixel_stride) override; | ||
| 82 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 80 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 83 | const VideoCore::DiskResourceLoadCallback& callback) override; | 81 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| 84 | void InitializeChannel(Tegra::Control::ChannelState& channel) override; | 82 | void InitializeChannel(Tegra::Control::ChannelState& channel) override; |
diff --git a/src/video_core/renderer_opengl/gl_fsr.cpp b/src/video_core/renderer_opengl/gl_fsr.cpp index 77262dcf1..429dcdc6c 100644 --- a/src/video_core/renderer_opengl/gl_fsr.cpp +++ b/src/video_core/renderer_opengl/gl_fsr.cpp | |||
| @@ -25,7 +25,7 @@ FSR::~FSR() = default; | |||
| 25 | 25 | ||
| 26 | void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | 26 | void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, |
| 27 | u32 input_image_width, u32 input_image_height, | 27 | u32 input_image_width, u32 input_image_height, |
| 28 | const Common::Rectangle<int>& crop_rect) { | 28 | const Common::Rectangle<f32>& crop_rect) { |
| 29 | 29 | ||
| 30 | const auto output_image_width = screen.GetWidth(); | 30 | const auto output_image_width = screen.GetWidth(); |
| 31 | const auto output_image_height = screen.GetHeight(); | 31 | const auto output_image_height = screen.GetHeight(); |
| @@ -57,14 +57,19 @@ void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& sc | |||
| 57 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(output_image_width), | 57 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(output_image_width), |
| 58 | static_cast<GLfloat>(output_image_height)); | 58 | static_cast<GLfloat>(output_image_height)); |
| 59 | 59 | ||
| 60 | FsrConstants constants; | 60 | const f32 input_width = static_cast<f32>(input_image_width); |
| 61 | FsrEasuConOffset( | 61 | const f32 input_height = static_cast<f32>(input_image_height); |
| 62 | constants.data() + 0, constants.data() + 4, constants.data() + 8, constants.data() + 12, | 62 | const f32 output_width = static_cast<f32>(screen.GetWidth()); |
| 63 | const f32 output_height = static_cast<f32>(screen.GetHeight()); | ||
| 64 | const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_width; | ||
| 65 | const f32 viewport_x = crop_rect.left * input_width; | ||
| 66 | const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_height; | ||
| 67 | const f32 viewport_y = crop_rect.top * input_height; | ||
| 63 | 68 | ||
| 64 | static_cast<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()), | 69 | FsrConstants constants; |
| 65 | static_cast<f32>(input_image_width), static_cast<f32>(input_image_height), | 70 | FsrEasuConOffset(constants.data() + 0, constants.data() + 4, constants.data() + 8, |
| 66 | static_cast<f32>(output_image_width), static_cast<f32>(output_image_height), | 71 | constants.data() + 12, viewport_width, viewport_height, input_width, |
| 67 | static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top)); | 72 | input_height, output_width, output_height, viewport_x, viewport_y); |
| 68 | 73 | ||
| 69 | glProgramUniform4uiv(fsr_easu_frag.handle, 0, sizeof(constants), std::data(constants)); | 74 | glProgramUniform4uiv(fsr_easu_frag.handle, 0, sizeof(constants), std::data(constants)); |
| 70 | 75 | ||
diff --git a/src/video_core/renderer_opengl/gl_fsr.h b/src/video_core/renderer_opengl/gl_fsr.h index 1f6ae3115..a5092e396 100644 --- a/src/video_core/renderer_opengl/gl_fsr.h +++ b/src/video_core/renderer_opengl/gl_fsr.h | |||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | 22 | ||
| 23 | void Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, | 23 | void Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen, |
| 24 | u32 input_image_width, u32 input_image_height, | 24 | u32 input_image_width, u32 input_image_height, |
| 25 | const Common::Rectangle<int>& crop_rect); | 25 | const Common::Rectangle<f32>& crop_rect); |
| 26 | 26 | ||
| 27 | void InitBuffers(); | 27 | void InitBuffers(); |
| 28 | 28 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d5354ef2d..050a74cca 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -71,10 +71,10 @@ std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryTy | |||
| 71 | 71 | ||
| 72 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 72 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 73 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 73 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 74 | const Device& device_, ScreenInfo& screen_info_, | 74 | const Device& device_, ProgramManager& program_manager_, |
| 75 | ProgramManager& program_manager_, StateTracker& state_tracker_) | 75 | StateTracker& state_tracker_) |
| 76 | : gpu(gpu_), device_memory(device_memory_), device(device_), screen_info(screen_info_), | 76 | : gpu(gpu_), device_memory(device_memory_), device(device_), program_manager(program_manager_), |
| 77 | program_manager(program_manager_), state_tracker(state_tracker_), | 77 | state_tracker(state_tracker_), |
| 78 | texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool), | 78 | texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool), |
| 79 | texture_cache(texture_cache_runtime, device_memory_), | 79 | texture_cache(texture_cache_runtime, device_memory_), |
| 80 | buffer_cache_runtime(device, staging_buffer_pool), | 80 | buffer_cache_runtime(device, staging_buffer_pool), |
| @@ -739,10 +739,10 @@ void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si | |||
| 739 | query_cache.InvalidateRegion(*cpu_addr, copy_size); | 739 | query_cache.InvalidateRegion(*cpu_addr, copy_size); |
| 740 | } | 740 | } |
| 741 | 741 | ||
| 742 | bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | 742 | std::optional<FramebufferTextureInfo> RasterizerOpenGL::AccelerateDisplay( |
| 743 | DAddr framebuffer_addr, u32 pixel_stride) { | 743 | const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { |
| 744 | if (framebuffer_addr == 0) { | 744 | if (framebuffer_addr == 0) { |
| 745 | return false; | 745 | return {}; |
| 746 | } | 746 | } |
| 747 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 747 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 748 | 748 | ||
| @@ -750,16 +750,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 750 | ImageView* const image_view{ | 750 | ImageView* const image_view{ |
| 751 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)}; | 751 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)}; |
| 752 | if (!image_view) { | 752 | if (!image_view) { |
| 753 | return false; | 753 | return {}; |
| 754 | } | 754 | } |
| 755 | // Verify that the cached surface is the same size and format as the requested framebuffer | ||
| 756 | // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different"); | ||
| 757 | // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different"); | ||
| 758 | 755 | ||
| 759 | screen_info.texture.width = image_view->size.width; | 756 | FramebufferTextureInfo info{}; |
| 760 | screen_info.texture.height = image_view->size.height; | 757 | info.display_texture = image_view->Handle(Shader::TextureType::Color2D); |
| 761 | screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); | 758 | info.width = image_view->size.width; |
| 762 | return true; | 759 | info.height = image_view->size.height; |
| 760 | return info; | ||
| 763 | } | 761 | } |
| 764 | 762 | ||
| 765 | void RasterizerOpenGL::SyncState() { | 763 | void RasterizerOpenGL::SyncState() { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 34aa73526..ee82d9f3a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -37,7 +37,7 @@ class MemoryManager; | |||
| 37 | 37 | ||
| 38 | namespace OpenGL { | 38 | namespace OpenGL { |
| 39 | 39 | ||
| 40 | struct ScreenInfo; | 40 | struct FramebufferTextureInfo; |
| 41 | struct ShaderEntries; | 41 | struct ShaderEntries; |
| 42 | 42 | ||
| 43 | struct BindlessSSBO { | 43 | struct BindlessSSBO { |
| @@ -76,8 +76,8 @@ class RasterizerOpenGL : public VideoCore::RasterizerInterface, | |||
| 76 | public: | 76 | public: |
| 77 | explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 77 | explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 78 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 78 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 79 | const Device& device_, ScreenInfo& screen_info_, | 79 | const Device& device_, ProgramManager& program_manager_, |
| 80 | ProgramManager& program_manager_, StateTracker& state_tracker_); | 80 | StateTracker& state_tracker_); |
| 81 | ~RasterizerOpenGL() override; | 81 | ~RasterizerOpenGL() override; |
| 82 | 82 | ||
| 83 | void Draw(bool is_indexed, u32 instance_count) override; | 83 | void Draw(bool is_indexed, u32 instance_count) override; |
| @@ -122,8 +122,6 @@ public: | |||
| 122 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | 122 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; |
| 123 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 123 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 124 | std::span<const u8> memory) override; | 124 | std::span<const u8> memory) override; |
| 125 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||
| 126 | u32 pixel_stride) override; | ||
| 127 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 125 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 128 | const VideoCore::DiskResourceLoadCallback& callback) override; | 126 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| 129 | 127 | ||
| @@ -144,6 +142,10 @@ public: | |||
| 144 | return true; | 142 | return true; |
| 145 | } | 143 | } |
| 146 | 144 | ||
| 145 | std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 146 | VAddr framebuffer_addr, | ||
| 147 | u32 pixel_stride); | ||
| 148 | |||
| 147 | private: | 149 | private: |
| 148 | static constexpr size_t MAX_TEXTURES = 192; | 150 | static constexpr size_t MAX_TEXTURES = 192; |
| 149 | static constexpr size_t MAX_IMAGES = 48; | 151 | static constexpr size_t MAX_IMAGES = 48; |
| @@ -237,7 +239,6 @@ private: | |||
| 237 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 239 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 238 | 240 | ||
| 239 | const Device& device; | 241 | const Device& device; |
| 240 | ScreenInfo& screen_info; | ||
| 241 | ProgramManager& program_manager; | 242 | ProgramManager& program_manager; |
| 242 | StateTracker& state_tracker; | 243 | StateTracker& state_tracker; |
| 243 | 244 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index b75376fdb..ea5ed3e2f 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -148,8 +148,7 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | |||
| 148 | : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, | 148 | : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, |
| 149 | emu_window{emu_window_}, device_memory{device_memory_}, gpu{gpu_}, device{emu_window_}, | 149 | emu_window{emu_window_}, device_memory{device_memory_}, gpu{gpu_}, device{emu_window_}, |
| 150 | state_tracker{}, program_manager{device}, | 150 | state_tracker{}, program_manager{device}, |
| 151 | rasterizer(emu_window, gpu, device_memory, device, screen_info, program_manager, | 151 | rasterizer(emu_window, gpu, device_memory, device, program_manager, state_tracker) { |
| 152 | state_tracker) { | ||
| 153 | if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { | 152 | if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { |
| 154 | glEnable(GL_DEBUG_OUTPUT); | 153 | glEnable(GL_DEBUG_OUTPUT); |
| 155 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | 154 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); |
| @@ -184,11 +183,11 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 184 | if (!framebuffer) { | 183 | if (!framebuffer) { |
| 185 | return; | 184 | return; |
| 186 | } | 185 | } |
| 187 | PrepareRendertarget(framebuffer); | 186 | |
| 188 | RenderScreenshot(); | 187 | RenderScreenshot(*framebuffer); |
| 189 | 188 | ||
| 190 | state_tracker.BindFramebuffer(0); | 189 | state_tracker.BindFramebuffer(0); |
| 191 | DrawScreen(emu_window.GetFramebufferLayout()); | 190 | DrawScreen(*framebuffer, emu_window.GetFramebufferLayout()); |
| 192 | 191 | ||
| 193 | ++m_current_frame; | 192 | ++m_current_frame; |
| 194 | 193 | ||
| @@ -199,41 +198,37 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 199 | render_window.OnFrameDisplayed(); | 198 | render_window.OnFrameDisplayed(); |
| 200 | } | 199 | } |
| 201 | 200 | ||
| 202 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 201 | FramebufferTextureInfo RendererOpenGL::PrepareRenderTarget( |
| 203 | if (!framebuffer) { | 202 | const Tegra::FramebufferConfig& framebuffer) { |
| 204 | return; | ||
| 205 | } | ||
| 206 | // If framebuffer is provided, reload it from memory to a texture | 203 | // If framebuffer is provided, reload it from memory to a texture |
| 207 | if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | 204 | if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) || |
| 208 | screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || | 205 | framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) || |
| 209 | screen_info.texture.pixel_format != framebuffer->pixel_format || | 206 | framebuffer_texture.pixel_format != framebuffer.pixel_format || |
| 210 | gl_framebuffer_data.empty()) { | 207 | gl_framebuffer_data.empty()) { |
| 211 | // Reallocate texture if the framebuffer size has changed. | 208 | // Reallocate texture if the framebuffer size has changed. |
| 212 | // This is expected to not happen very often and hence should not be a | 209 | // This is expected to not happen very often and hence should not be a |
| 213 | // performance problem. | 210 | // performance problem. |
| 214 | ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | 211 | ConfigureFramebufferTexture(framebuffer); |
| 215 | } | 212 | } |
| 216 | 213 | ||
| 217 | // Load the framebuffer from memory, draw it to the screen, and swap buffers | 214 | // Load the framebuffer from memory if needed |
| 218 | LoadFBToScreenInfo(*framebuffer); | 215 | return LoadFBToScreenInfo(framebuffer); |
| 219 | } | 216 | } |
| 220 | 217 | ||
| 221 | void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | 218 | FramebufferTextureInfo RendererOpenGL::LoadFBToScreenInfo( |
| 222 | // Framebuffer orientation handling | 219 | const Tegra::FramebufferConfig& framebuffer) { |
| 223 | framebuffer_transform_flags = framebuffer.transform_flags; | ||
| 224 | framebuffer_crop_rect = framebuffer.crop_rect; | ||
| 225 | framebuffer_width = framebuffer.width; | ||
| 226 | framebuffer_height = framebuffer.height; | ||
| 227 | |||
| 228 | const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; | 220 | const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; |
| 229 | screen_info.was_accelerated = | 221 | const auto accelerated_info = |
| 230 | rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); | 222 | rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); |
| 231 | if (screen_info.was_accelerated) { | 223 | if (accelerated_info) { |
| 232 | return; | 224 | return *accelerated_info; |
| 233 | } | 225 | } |
| 234 | 226 | ||
| 235 | // Reset the screen info's display texture to its own permanent texture | 227 | // Reset the screen info's display texture to its own permanent texture |
| 236 | screen_info.display_texture = screen_info.texture.resource.handle; | 228 | FramebufferTextureInfo info{}; |
| 229 | info.display_texture = framebuffer_texture.resource.handle; | ||
| 230 | info.width = framebuffer.width; | ||
| 231 | info.height = framebuffer.height; | ||
| 237 | 232 | ||
| 238 | // TODO(Rodrigo): Read this from HLE | 233 | // TODO(Rodrigo): Read this from HLE |
| 239 | constexpr u32 block_height_log2 = 4; | 234 | constexpr u32 block_height_log2 = 4; |
| @@ -256,17 +251,13 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||
| 256 | // they differ from the LCD resolution. | 251 | // they differ from the LCD resolution. |
| 257 | // TODO: Applications could theoretically crash yuzu here by specifying too large | 252 | // TODO: Applications could theoretically crash yuzu here by specifying too large |
| 258 | // framebuffer sizes. We should make sure that this cannot happen. | 253 | // framebuffer sizes. We should make sure that this cannot happen. |
| 259 | glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width, | 254 | glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width, |
| 260 | framebuffer.height, screen_info.texture.gl_format, | 255 | framebuffer.height, framebuffer_texture.gl_format, |
| 261 | screen_info.texture.gl_type, gl_framebuffer_data.data()); | 256 | framebuffer_texture.gl_type, gl_framebuffer_data.data()); |
| 262 | 257 | ||
| 263 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 258 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 264 | } | ||
| 265 | 259 | ||
| 266 | void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | 260 | return info; |
| 267 | const TextureInfo& texture) { | ||
| 268 | const u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r}; | ||
| 269 | glClearTexImage(texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); | ||
| 270 | } | 261 | } |
| 271 | 262 | ||
| 272 | void RendererOpenGL::InitOpenGLObjects() { | 263 | void RendererOpenGL::InitOpenGLObjects() { |
| @@ -343,15 +334,15 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 343 | glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | 334 | glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); |
| 344 | 335 | ||
| 345 | // Allocate textures for the screen | 336 | // Allocate textures for the screen |
| 346 | screen_info.texture.resource.Create(GL_TEXTURE_2D); | 337 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); |
| 347 | 338 | ||
| 348 | const GLuint texture = screen_info.texture.resource.handle; | 339 | const GLuint texture = framebuffer_texture.resource.handle; |
| 349 | glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); | 340 | glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); |
| 350 | 341 | ||
| 351 | screen_info.display_texture = screen_info.texture.resource.handle; | ||
| 352 | |||
| 353 | // Clear screen to black | 342 | // Clear screen to black |
| 354 | LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture); | 343 | const u8 framebuffer_data[4] = {0, 0, 0, 0}; |
| 344 | glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, | ||
| 345 | framebuffer_data); | ||
| 355 | 346 | ||
| 356 | aa_framebuffer.Create(); | 347 | aa_framebuffer.Create(); |
| 357 | 348 | ||
| @@ -380,60 +371,65 @@ void RendererOpenGL::AddTelemetryFields() { | |||
| 380 | telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); | 371 | telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); |
| 381 | } | 372 | } |
| 382 | 373 | ||
| 383 | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | 374 | void RendererOpenGL::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) { |
| 384 | const Tegra::FramebufferConfig& framebuffer) { | 375 | framebuffer_texture.width = framebuffer.width; |
| 385 | texture.width = framebuffer.width; | 376 | framebuffer_texture.height = framebuffer.height; |
| 386 | texture.height = framebuffer.height; | 377 | framebuffer_texture.pixel_format = framebuffer.pixel_format; |
| 387 | texture.pixel_format = framebuffer.pixel_format; | ||
| 388 | 378 | ||
| 389 | const auto pixel_format{ | 379 | const auto pixel_format{ |
| 390 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | 380 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; |
| 391 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | 381 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; |
| 392 | gl_framebuffer_data.resize(texture.width * texture.height * bytes_per_pixel); | 382 | gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height * |
| 383 | bytes_per_pixel); | ||
| 393 | 384 | ||
| 394 | GLint internal_format; | 385 | GLint internal_format; |
| 395 | switch (framebuffer.pixel_format) { | 386 | switch (framebuffer.pixel_format) { |
| 396 | case Service::android::PixelFormat::Rgba8888: | 387 | case Service::android::PixelFormat::Rgba8888: |
| 397 | internal_format = GL_RGBA8; | 388 | internal_format = GL_RGBA8; |
| 398 | texture.gl_format = GL_RGBA; | 389 | framebuffer_texture.gl_format = GL_RGBA; |
| 399 | texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | 390 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
| 400 | break; | 391 | break; |
| 401 | case Service::android::PixelFormat::Rgb565: | 392 | case Service::android::PixelFormat::Rgb565: |
| 402 | internal_format = GL_RGB565; | 393 | internal_format = GL_RGB565; |
| 403 | texture.gl_format = GL_RGB; | 394 | framebuffer_texture.gl_format = GL_RGB; |
| 404 | texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; | 395 | framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; |
| 405 | break; | 396 | break; |
| 406 | default: | 397 | default: |
| 407 | internal_format = GL_RGBA8; | 398 | internal_format = GL_RGBA8; |
| 408 | texture.gl_format = GL_RGBA; | 399 | framebuffer_texture.gl_format = GL_RGBA; |
| 409 | texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | 400 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
| 410 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | 401 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", |
| 411 | // static_cast<u32>(framebuffer.pixel_format)); | 402 | // static_cast<u32>(framebuffer.pixel_format)); |
| 412 | break; | 403 | break; |
| 413 | } | 404 | } |
| 414 | 405 | ||
| 415 | texture.resource.Release(); | 406 | framebuffer_texture.resource.Release(); |
| 416 | texture.resource.Create(GL_TEXTURE_2D); | 407 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); |
| 417 | glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height); | 408 | glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, |
| 409 | framebuffer_texture.width, framebuffer_texture.height); | ||
| 418 | aa_texture.Release(); | 410 | aa_texture.Release(); |
| 419 | aa_texture.Create(GL_TEXTURE_2D); | 411 | aa_texture.Create(GL_TEXTURE_2D); |
| 420 | glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F, | 412 | glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F, |
| 421 | Settings::values.resolution_info.ScaleUp(screen_info.texture.width), | 413 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), |
| 422 | Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | 414 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); |
| 423 | glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0); | 415 | glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0); |
| 424 | smaa_edges_tex.Release(); | 416 | smaa_edges_tex.Release(); |
| 425 | smaa_edges_tex.Create(GL_TEXTURE_2D); | 417 | smaa_edges_tex.Create(GL_TEXTURE_2D); |
| 426 | glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F, | 418 | glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F, |
| 427 | Settings::values.resolution_info.ScaleUp(screen_info.texture.width), | 419 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), |
| 428 | Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | 420 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); |
| 429 | smaa_blend_tex.Release(); | 421 | smaa_blend_tex.Release(); |
| 430 | smaa_blend_tex.Create(GL_TEXTURE_2D); | 422 | smaa_blend_tex.Create(GL_TEXTURE_2D); |
| 431 | glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F, | 423 | glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F, |
| 432 | Settings::values.resolution_info.ScaleUp(screen_info.texture.width), | 424 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), |
| 433 | Settings::values.resolution_info.ScaleUp(screen_info.texture.height)); | 425 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); |
| 434 | } | 426 | } |
| 435 | 427 | ||
| 436 | void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | 428 | void RendererOpenGL::DrawScreen(const Tegra::FramebufferConfig& framebuffer, |
| 429 | const Layout::FramebufferLayout& layout) { | ||
| 430 | FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); | ||
| 431 | const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); | ||
| 432 | |||
| 437 | // TODO: Signal state tracker about these changes | 433 | // TODO: Signal state tracker about these changes |
| 438 | state_tracker.NotifyScreenDrawVertexArray(); | 434 | state_tracker.NotifyScreenDrawVertexArray(); |
| 439 | state_tracker.NotifyPolygonModes(); | 435 | state_tracker.NotifyPolygonModes(); |
| @@ -469,7 +465,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 469 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 465 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 470 | glDepthRangeIndexed(0, 0.0, 0.0); | 466 | glDepthRangeIndexed(0, 0.0, 0.0); |
| 471 | 467 | ||
| 472 | glBindTextureUnit(0, screen_info.display_texture); | 468 | glBindTextureUnit(0, info.display_texture); |
| 473 | 469 | ||
| 474 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | 470 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); |
| 475 | if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { | 471 | if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { |
| @@ -480,22 +476,22 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 480 | 476 | ||
| 481 | if (anti_aliasing != Settings::AntiAliasing::None) { | 477 | if (anti_aliasing != Settings::AntiAliasing::None) { |
| 482 | glEnablei(GL_SCISSOR_TEST, 0); | 478 | glEnablei(GL_SCISSOR_TEST, 0); |
| 483 | auto viewport_width = screen_info.texture.width; | 479 | auto viewport_width = info.width; |
| 484 | auto scissor_width = framebuffer_crop_rect.GetWidth(); | 480 | auto scissor_width = static_cast<u32>(crop.GetWidth()); |
| 485 | if (scissor_width <= 0) { | 481 | if (scissor_width <= 0) { |
| 486 | scissor_width = viewport_width; | 482 | scissor_width = viewport_width; |
| 487 | } | 483 | } |
| 488 | auto viewport_height = screen_info.texture.height; | 484 | auto viewport_height = info.height; |
| 489 | auto scissor_height = framebuffer_crop_rect.GetHeight(); | 485 | auto scissor_height = static_cast<u32>(crop.GetHeight()); |
| 490 | if (scissor_height <= 0) { | 486 | if (scissor_height <= 0) { |
| 491 | scissor_height = viewport_height; | 487 | scissor_height = viewport_height; |
| 492 | } | 488 | } |
| 493 | if (screen_info.was_accelerated) { | 489 | |
| 494 | viewport_width = Settings::values.resolution_info.ScaleUp(viewport_width); | 490 | viewport_width = Settings::values.resolution_info.ScaleUp(viewport_width); |
| 495 | scissor_width = Settings::values.resolution_info.ScaleUp(scissor_width); | 491 | scissor_width = Settings::values.resolution_info.ScaleUp(scissor_width); |
| 496 | viewport_height = Settings::values.resolution_info.ScaleUp(viewport_height); | 492 | viewport_height = Settings::values.resolution_info.ScaleUp(viewport_height); |
| 497 | scissor_height = Settings::values.resolution_info.ScaleUp(scissor_height); | 493 | scissor_height = Settings::values.resolution_info.ScaleUp(scissor_height); |
| 498 | } | 494 | |
| 499 | glScissorIndexed(0, 0, 0, scissor_width, scissor_height); | 495 | glScissorIndexed(0, 0, 0, scissor_width, scissor_height); |
| 500 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width), | 496 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width), |
| 501 | static_cast<GLfloat>(viewport_height)); | 497 | static_cast<GLfloat>(viewport_height)); |
| @@ -536,7 +532,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 536 | smaa_blending_weight_calculation_frag.handle); | 532 | smaa_blending_weight_calculation_frag.handle); |
| 537 | glDrawArrays(GL_TRIANGLES, 0, 3); | 533 | glDrawArrays(GL_TRIANGLES, 0, 3); |
| 538 | 534 | ||
| 539 | glBindTextureUnit(0, screen_info.display_texture); | 535 | glBindTextureUnit(0, info.display_texture); |
| 540 | glBindTextureUnit(1, smaa_blend_tex.handle); | 536 | glBindTextureUnit(1, smaa_blend_tex.handle); |
| 541 | glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, | 537 | glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, |
| 542 | aa_texture.handle, 0); | 538 | aa_texture.handle, 0); |
| @@ -561,18 +557,10 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 561 | fsr->InitBuffers(); | 557 | fsr->InitBuffers(); |
| 562 | } | 558 | } |
| 563 | 559 | ||
| 564 | auto crop_rect = framebuffer_crop_rect; | 560 | const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(info.width); |
| 565 | if (crop_rect.GetWidth() == 0) { | 561 | const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(info.height); |
| 566 | crop_rect.right = framebuffer_width; | ||
| 567 | } | ||
| 568 | if (crop_rect.GetHeight() == 0) { | ||
| 569 | crop_rect.bottom = framebuffer_height; | ||
| 570 | } | ||
| 571 | crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); | ||
| 572 | const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(framebuffer_width); | ||
| 573 | const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(framebuffer_height); | ||
| 574 | glBindSampler(0, present_sampler.handle); | 562 | glBindSampler(0, present_sampler.handle); |
| 575 | fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop_rect); | 563 | fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop); |
| 576 | } else { | 564 | } else { |
| 577 | if (fsr->AreBuffersInitialized()) { | 565 | if (fsr->AreBuffersInitialized()) { |
| 578 | fsr->ReleaseBuffers(); | 566 | fsr->ReleaseBuffers(); |
| @@ -603,61 +591,34 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 603 | glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, | 591 | glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, |
| 604 | ortho_matrix.data()); | 592 | ortho_matrix.data()); |
| 605 | 593 | ||
| 606 | const auto& texcoords = screen_info.display_texcoords; | 594 | f32 left, top, right, bottom; |
| 607 | auto left = texcoords.left; | 595 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { |
| 608 | auto right = texcoords.right; | 596 | // FSR has already applied the crop, so we just want to render the image |
| 609 | if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) { | 597 | // it has produced. |
| 610 | if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) { | 598 | left = 0; |
| 611 | // Flip the framebuffer vertically | 599 | top = 0; |
| 612 | left = texcoords.right; | 600 | right = 1; |
| 613 | right = texcoords.left; | 601 | bottom = 1; |
| 614 | } else { | 602 | } else { |
| 615 | // Other transformations are unsupported | 603 | // Apply the precomputed crop. |
| 616 | LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}", | 604 | left = crop.left; |
| 617 | framebuffer_transform_flags); | 605 | top = crop.top; |
| 618 | UNIMPLEMENTED(); | 606 | right = crop.right; |
| 619 | } | 607 | bottom = crop.bottom; |
| 620 | } | ||
| 621 | |||
| 622 | ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented"); | ||
| 623 | |||
| 624 | f32 left_start{}; | ||
| 625 | if (framebuffer_crop_rect.Top() > 0) { | ||
| 626 | left_start = static_cast<f32>(framebuffer_crop_rect.Top()) / | ||
| 627 | static_cast<f32>(framebuffer_crop_rect.Bottom()); | ||
| 628 | } | ||
| 629 | f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); | ||
| 630 | f32 scale_v = | ||
| 631 | static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); | ||
| 632 | |||
| 633 | if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::Fsr) { | ||
| 634 | // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering | ||
| 635 | // (e.g. handheld mode) on a 1920x1080 framebuffer. | ||
| 636 | if (framebuffer_crop_rect.GetWidth() > 0) { | ||
| 637 | scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / | ||
| 638 | static_cast<f32>(screen_info.texture.width); | ||
| 639 | } | ||
| 640 | if (framebuffer_crop_rect.GetHeight() > 0) { | ||
| 641 | scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | ||
| 642 | static_cast<f32>(screen_info.texture.height); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa && | ||
| 646 | !screen_info.was_accelerated) { | ||
| 647 | scale_u /= Settings::values.resolution_info.up_factor; | ||
| 648 | scale_v /= Settings::values.resolution_info.up_factor; | ||
| 649 | } | 608 | } |
| 650 | 609 | ||
| 610 | // Map the coordinates to the screen. | ||
| 651 | const auto& screen = layout.screen; | 611 | const auto& screen = layout.screen; |
| 612 | const auto x = screen.left; | ||
| 613 | const auto y = screen.top; | ||
| 614 | const auto w = screen.GetWidth(); | ||
| 615 | const auto h = screen.GetHeight(); | ||
| 616 | |||
| 652 | const std::array vertices = { | 617 | const std::array vertices = { |
| 653 | ScreenRectVertex(screen.left, screen.top, texcoords.top * scale_u, | 618 | ScreenRectVertex(x, y, left, top), |
| 654 | left_start + left * scale_v), | 619 | ScreenRectVertex(x + w, y, right, top), |
| 655 | ScreenRectVertex(screen.right, screen.top, texcoords.bottom * scale_u, | 620 | ScreenRectVertex(x, y + h, left, bottom), |
| 656 | left_start + left * scale_v), | 621 | ScreenRectVertex(x + w, y + h, right, bottom), |
| 657 | ScreenRectVertex(screen.left, screen.bottom, texcoords.top * scale_u, | ||
| 658 | left_start + right * scale_v), | ||
| 659 | ScreenRectVertex(screen.right, screen.bottom, texcoords.bottom * scale_u, | ||
| 660 | left_start + right * scale_v), | ||
| 661 | }; | 622 | }; |
| 662 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | 623 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); |
| 663 | 624 | ||
| @@ -701,7 +662,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 701 | // program_manager.RestoreGuestPipeline(); | 662 | // program_manager.RestoreGuestPipeline(); |
| 702 | } | 663 | } |
| 703 | 664 | ||
| 704 | void RendererOpenGL::RenderScreenshot() { | 665 | void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { |
| 705 | if (!renderer_settings.screenshot_requested) { | 666 | if (!renderer_settings.screenshot_requested) { |
| 706 | return; | 667 | return; |
| 707 | } | 668 | } |
| @@ -723,7 +684,7 @@ void RendererOpenGL::RenderScreenshot() { | |||
| 723 | glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); | 684 | glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); |
| 724 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); | 685 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); |
| 725 | 686 | ||
| 726 | DrawScreen(layout); | 687 | DrawScreen(framebuffer, layout); |
| 727 | 688 | ||
| 728 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | 689 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); |
| 729 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 690 | 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 18699610a..cde8c5702 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -50,11 +50,10 @@ struct TextureInfo { | |||
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | /// Structure used for storing information about the display target for the Switch screen | 52 | /// Structure used for storing information about the display target for the Switch screen |
| 53 | struct ScreenInfo { | 53 | struct FramebufferTextureInfo { |
| 54 | GLuint display_texture{}; | 54 | GLuint display_texture{}; |
| 55 | bool was_accelerated = false; | 55 | u32 width; |
| 56 | const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; | 56 | u32 height; |
| 57 | TextureInfo texture; | ||
| 58 | }; | 57 | }; |
| 59 | 58 | ||
| 60 | class RendererOpenGL final : public VideoCore::RendererBase { | 59 | class RendererOpenGL final : public VideoCore::RendererBase { |
| @@ -81,23 +80,18 @@ private: | |||
| 81 | 80 | ||
| 82 | void AddTelemetryFields(); | 81 | void AddTelemetryFields(); |
| 83 | 82 | ||
| 84 | void ConfigureFramebufferTexture(TextureInfo& texture, | 83 | void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); |
| 85 | const Tegra::FramebufferConfig& framebuffer); | ||
| 86 | 84 | ||
| 87 | /// Draws the emulated screens to the emulator window. | 85 | /// Draws the emulated screens to the emulator window. |
| 88 | void DrawScreen(const Layout::FramebufferLayout& layout); | 86 | void DrawScreen(const Tegra::FramebufferConfig& framebuffer, |
| 87 | const Layout::FramebufferLayout& layout); | ||
| 89 | 88 | ||
| 90 | void RenderScreenshot(); | 89 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); |
| 91 | 90 | ||
| 92 | /// Loads framebuffer from emulated memory into the active OpenGL texture. | 91 | /// Loads framebuffer from emulated memory into the active OpenGL texture. |
| 93 | void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | 92 | FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); |
| 94 | 93 | ||
| 95 | /// Fills active OpenGL texture with the given RGB color.Since the color is solid, the texture | 94 | FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); |
| 96 | /// can be 1x1 but will stretch across whatever it's rendered on. | ||
| 97 | void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | ||
| 98 | const TextureInfo& texture); | ||
| 99 | |||
| 100 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | ||
| 101 | 95 | ||
| 102 | Core::TelemetrySession& telemetry_session; | 96 | Core::TelemetrySession& telemetry_session; |
| 103 | Core::Frontend::EmuWindow& emu_window; | 97 | Core::Frontend::EmuWindow& emu_window; |
| @@ -126,7 +120,7 @@ private: | |||
| 126 | GLuint64EXT vertex_buffer_address = 0; | 120 | GLuint64EXT vertex_buffer_address = 0; |
| 127 | 121 | ||
| 128 | /// Display information for Switch screen | 122 | /// Display information for Switch screen |
| 129 | ScreenInfo screen_info; | 123 | TextureInfo framebuffer_texture; |
| 130 | OGLTexture aa_texture; | 124 | OGLTexture aa_texture; |
| 131 | OGLFramebuffer aa_framebuffer; | 125 | OGLFramebuffer aa_framebuffer; |
| 132 | 126 | ||
| @@ -145,12 +139,6 @@ private: | |||
| 145 | 139 | ||
| 146 | /// OpenGL framebuffer data | 140 | /// OpenGL framebuffer data |
| 147 | std::vector<u8> gl_framebuffer_data; | 141 | std::vector<u8> gl_framebuffer_data; |
| 148 | |||
| 149 | /// Used for transforming the framebuffer orientation | ||
| 150 | Service::android::BufferTransformFlags framebuffer_transform_flags{}; | ||
| 151 | Common::Rectangle<int> framebuffer_crop_rect; | ||
| 152 | u32 framebuffer_width; | ||
| 153 | u32 framebuffer_height; | ||
| 154 | }; | 142 | }; |
| 155 | 143 | ||
| 156 | } // namespace OpenGL | 144 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 1631276c6..e1fe53bbd 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -98,9 +98,9 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| 99 | surface), | 99 | surface), |
| 100 | blit_screen(device_memory, render_window, device, memory_allocator, swapchain, | 100 | blit_screen(device_memory, render_window, device, memory_allocator, swapchain, |
| 101 | present_manager, scheduler, screen_info), | 101 | present_manager, scheduler), |
| 102 | rasterizer(render_window, gpu, device_memory, screen_info, device, memory_allocator, | 102 | rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, |
| 103 | state_tracker, scheduler) { | 103 | scheduler) { |
| 104 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { | 104 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { |
| 105 | turbo_mode.emplace(instance, dld); | 105 | turbo_mode.emplace(instance, dld); |
| 106 | scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); | 106 | scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); |
| @@ -124,17 +124,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 124 | if (!render_window.IsShown()) { | 124 | if (!render_window.IsShown()) { |
| 125 | return; | 125 | return; |
| 126 | } | 126 | } |
| 127 | // Update screen info if the framebuffer size has changed. | ||
| 128 | screen_info.width = framebuffer->width; | ||
| 129 | screen_info.height = framebuffer->height; | ||
| 130 | |||
| 131 | const DAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | ||
| 132 | const bool use_accelerated = | ||
| 133 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); | ||
| 134 | RenderScreenshot(*framebuffer, use_accelerated); | ||
| 135 | 127 | ||
| 128 | RenderScreenshot(*framebuffer); | ||
| 136 | Frame* frame = present_manager.GetRenderFrame(); | 129 | Frame* frame = present_manager.GetRenderFrame(); |
| 137 | blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated); | 130 | blit_screen.DrawToSwapchain(rasterizer, frame, *framebuffer); |
| 138 | scheduler.Flush(*frame->render_ready); | 131 | scheduler.Flush(*frame->render_ready); |
| 139 | present_manager.Present(frame); | 132 | present_manager.Present(frame); |
| 140 | 133 | ||
| @@ -168,8 +161,7 @@ void RendererVulkan::Report() const { | |||
| 168 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | 161 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); |
| 169 | } | 162 | } |
| 170 | 163 | ||
| 171 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, | 164 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { |
| 172 | bool use_accelerated) { | ||
| 173 | if (!renderer_settings.screenshot_requested) { | 165 | if (!renderer_settings.screenshot_requested) { |
| 174 | return; | 166 | return; |
| 175 | } | 167 | } |
| @@ -221,7 +213,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 221 | }); | 213 | }); |
| 222 | const VkExtent2D render_area{.width = layout.width, .height = layout.height}; | 214 | const VkExtent2D render_area{.width = layout.width, .height = layout.height}; |
| 223 | const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); | 215 | const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); |
| 224 | blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated); | 216 | blit_screen.Draw(rasterizer, framebuffer, *screenshot_fb, layout, render_area); |
| 225 | 217 | ||
| 226 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | 218 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); |
| 227 | const VkBufferCreateInfo dst_buffer_info{ | 219 | const VkBufferCreateInfo dst_buffer_info{ |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 11c52287a..d7d006b20 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -59,7 +59,7 @@ public: | |||
| 59 | private: | 59 | private: |
| 60 | void Report() const; | 60 | void Report() const; |
| 61 | 61 | ||
| 62 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated); | 62 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); |
| 63 | 63 | ||
| 64 | Core::TelemetrySession& telemetry_session; | 64 | Core::TelemetrySession& telemetry_session; |
| 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| @@ -72,8 +72,6 @@ private: | |||
| 72 | vk::DebugUtilsMessenger debug_messenger; | 72 | vk::DebugUtilsMessenger debug_messenger; |
| 73 | vk::SurfaceKHR surface; | 73 | vk::SurfaceKHR surface; |
| 74 | 74 | ||
| 75 | ScreenInfo screen_info; | ||
| 76 | |||
| 77 | Device device; | 75 | Device device; |
| 78 | MemoryAllocator memory_allocator; | 76 | MemoryAllocator memory_allocator; |
| 79 | StateTracker state_tracker; | 77 | StateTracker state_tracker; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 610f27c84..c21a9c8fe 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -124,11 +124,10 @@ struct BlitScreen::BufferData { | |||
| 124 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | 124 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 125 | Core::Frontend::EmuWindow& render_window_, const Device& device_, | 125 | Core::Frontend::EmuWindow& render_window_, const Device& device_, |
| 126 | MemoryAllocator& memory_allocator_, Swapchain& swapchain_, | 126 | MemoryAllocator& memory_allocator_, Swapchain& swapchain_, |
| 127 | PresentManager& present_manager_, Scheduler& scheduler_, | 127 | PresentManager& present_manager_, Scheduler& scheduler_) |
| 128 | const ScreenInfo& screen_info_) | ||
| 129 | : device_memory{device_memory_}, render_window{render_window_}, device{device_}, | 128 | : device_memory{device_memory_}, render_window{render_window_}, device{device_}, |
| 130 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, | 129 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, |
| 131 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | 130 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()} { |
| 132 | resource_ticks.resize(image_count); | 131 | resource_ticks.resize(image_count); |
| 133 | swapchain_view_format = swapchain.GetImageViewFormat(); | 132 | swapchain_view_format = swapchain.GetImageViewFormat(); |
| 134 | 133 | ||
| @@ -138,56 +137,6 @@ BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | |||
| 138 | 137 | ||
| 139 | BlitScreen::~BlitScreen() = default; | 138 | BlitScreen::~BlitScreen() = default; |
| 140 | 139 | ||
| 141 | static Common::Rectangle<f32> NormalizeCrop(const Tegra::FramebufferConfig& framebuffer, | ||
| 142 | const ScreenInfo& screen_info) { | ||
| 143 | f32 left, top, right, bottom; | ||
| 144 | |||
| 145 | if (!framebuffer.crop_rect.IsEmpty()) { | ||
| 146 | // If crop rectangle is not empty, apply properties from rectangle. | ||
| 147 | left = static_cast<f32>(framebuffer.crop_rect.left); | ||
| 148 | top = static_cast<f32>(framebuffer.crop_rect.top); | ||
| 149 | right = static_cast<f32>(framebuffer.crop_rect.right); | ||
| 150 | bottom = static_cast<f32>(framebuffer.crop_rect.bottom); | ||
| 151 | } else { | ||
| 152 | // Otherwise, fall back to framebuffer dimensions. | ||
| 153 | left = 0; | ||
| 154 | top = 0; | ||
| 155 | right = static_cast<f32>(framebuffer.width); | ||
| 156 | bottom = static_cast<f32>(framebuffer.height); | ||
| 157 | } | ||
| 158 | |||
| 159 | // Apply transformation flags. | ||
| 160 | auto framebuffer_transform_flags = framebuffer.transform_flags; | ||
| 161 | |||
| 162 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { | ||
| 163 | // Switch left and right. | ||
| 164 | std::swap(left, right); | ||
| 165 | } | ||
| 166 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { | ||
| 167 | // Switch top and bottom. | ||
| 168 | std::swap(top, bottom); | ||
| 169 | } | ||
| 170 | |||
| 171 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; | ||
| 172 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; | ||
| 173 | if (True(framebuffer_transform_flags)) { | ||
| 174 | UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", | ||
| 175 | static_cast<u32>(framebuffer_transform_flags)); | ||
| 176 | } | ||
| 177 | |||
| 178 | // Get the screen properties. | ||
| 179 | const f32 screen_width = static_cast<f32>(screen_info.width); | ||
| 180 | const f32 screen_height = static_cast<f32>(screen_info.height); | ||
| 181 | |||
| 182 | // Normalize coordinate space. | ||
| 183 | left /= screen_width; | ||
| 184 | top /= screen_height; | ||
| 185 | right /= screen_width; | ||
| 186 | bottom /= screen_height; | ||
| 187 | |||
| 188 | return Common::Rectangle<f32>(left, top, right, bottom); | ||
| 189 | } | ||
| 190 | |||
| 191 | void BlitScreen::Recreate() { | 140 | void BlitScreen::Recreate() { |
| 192 | present_manager.WaitPresent(); | 141 | present_manager.WaitPresent(); |
| 193 | scheduler.Finish(); | 142 | scheduler.Finish(); |
| @@ -195,9 +144,16 @@ void BlitScreen::Recreate() { | |||
| 195 | CreateDynamicResources(); | 144 | CreateDynamicResources(); |
| 196 | } | 145 | } |
| 197 | 146 | ||
| 198 | void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | 147 | void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, |
| 199 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | 148 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, |
| 200 | VkExtent2D render_area, bool use_accelerated) { | 149 | VkExtent2D render_area) { |
| 150 | |||
| 151 | const auto texture_info = rasterizer.AccelerateDisplay( | ||
| 152 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | ||
| 153 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | ||
| 154 | const u32 texture_height = texture_info ? texture_info->height : framebuffer.height; | ||
| 155 | const bool use_accelerated = texture_info.has_value(); | ||
| 156 | |||
| 201 | RefreshResources(framebuffer); | 157 | RefreshResources(framebuffer); |
| 202 | 158 | ||
| 203 | // Finish any pending renderpass | 159 | // Finish any pending renderpass |
| @@ -206,13 +162,13 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 206 | scheduler.Wait(resource_ticks[image_index]); | 162 | scheduler.Wait(resource_ticks[image_index]); |
| 207 | resource_ticks[image_index] = scheduler.CurrentTick(); | 163 | resource_ticks[image_index] = scheduler.CurrentTick(); |
| 208 | 164 | ||
| 209 | VkImage source_image = use_accelerated ? screen_info.image : *raw_images[image_index]; | 165 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; |
| 210 | VkImageView source_image_view = | 166 | VkImageView source_image_view = |
| 211 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]; | 167 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; |
| 212 | 168 | ||
| 213 | BufferData data; | 169 | BufferData data; |
| 214 | SetUniformData(data, layout); | 170 | SetUniformData(data, layout); |
| 215 | SetVertexData(data, framebuffer, layout); | 171 | SetVertexData(data, framebuffer, layout, texture_width, texture_height); |
| 216 | 172 | ||
| 217 | const std::span<u8> mapped_span = buffer.Mapped(); | 173 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 218 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | 174 | std::memcpy(mapped_span.data(), &data, sizeof(data)); |
| @@ -405,10 +361,10 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 405 | source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); | 361 | source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); |
| 406 | } | 362 | } |
| 407 | if (fsr) { | 363 | if (fsr) { |
| 408 | const auto crop_rect = NormalizeCrop(framebuffer, screen_info); | 364 | const auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); |
| 409 | const VkExtent2D fsr_input_size{ | 365 | const VkExtent2D fsr_input_size{ |
| 410 | .width = Settings::values.resolution_info.ScaleUp(screen_info.width), | 366 | .width = Settings::values.resolution_info.ScaleUp(texture_width), |
| 411 | .height = Settings::values.resolution_info.ScaleUp(screen_info.height), | 367 | .height = Settings::values.resolution_info.ScaleUp(texture_height), |
| 412 | }; | 368 | }; |
| 413 | VkImageView fsr_image_view = | 369 | VkImageView fsr_image_view = |
| 414 | fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); | 370 | fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); |
| @@ -480,8 +436,8 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 480 | }); | 436 | }); |
| 481 | } | 437 | } |
| 482 | 438 | ||
| 483 | void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | 439 | void BlitScreen::DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, |
| 484 | bool use_accelerated) { | 440 | const Tegra::FramebufferConfig& framebuffer) { |
| 485 | // Recreate dynamic resources if the the image count or input format changed | 441 | // Recreate dynamic resources if the the image count or input format changed |
| 486 | const VkFormat current_framebuffer_format = | 442 | const VkFormat current_framebuffer_format = |
| 487 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | 443 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); |
| @@ -500,7 +456,7 @@ void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& f | |||
| 500 | } | 456 | } |
| 501 | 457 | ||
| 502 | const VkExtent2D render_area{frame->width, frame->height}; | 458 | const VkExtent2D render_area{frame->width, frame->height}; |
| 503 | Draw(framebuffer, *frame->framebuffer, layout, render_area, use_accelerated); | 459 | Draw(rasterizer, framebuffer, *frame->framebuffer, layout, render_area); |
| 504 | if (++image_index >= image_count) { | 460 | if (++image_index >= image_count) { |
| 505 | image_index = 0; | 461 | image_index = 0; |
| 506 | } | 462 | } |
| @@ -1434,7 +1390,8 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou | |||
| 1434 | } | 1390 | } |
| 1435 | 1391 | ||
| 1436 | void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | 1392 | void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, |
| 1437 | const Layout::FramebufferLayout layout) const { | 1393 | const Layout::FramebufferLayout layout, u32 texture_width, |
| 1394 | u32 texture_height) const { | ||
| 1438 | f32 left, top, right, bottom; | 1395 | f32 left, top, right, bottom; |
| 1439 | 1396 | ||
| 1440 | if (fsr) { | 1397 | if (fsr) { |
| @@ -1446,7 +1403,7 @@ void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& | |||
| 1446 | bottom = 1; | 1403 | bottom = 1; |
| 1447 | } else { | 1404 | } else { |
| 1448 | // Get the normalized crop rectangle. | 1405 | // Get the normalized crop rectangle. |
| 1449 | const auto crop = NormalizeCrop(framebuffer, screen_info); | 1406 | const auto crop = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); |
| 1450 | 1407 | ||
| 1451 | // Apply the crop. | 1408 | // Apply the crop. |
| 1452 | left = crop.left; | 1409 | left = crop.left; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 3eff76009..40338886a 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -32,8 +32,6 @@ enum class PixelFormat : u32; | |||
| 32 | 32 | ||
| 33 | namespace Vulkan { | 33 | namespace Vulkan { |
| 34 | 34 | ||
| 35 | struct ScreenInfo; | ||
| 36 | |||
| 37 | class Device; | 35 | class Device; |
| 38 | class FSR; | 36 | class FSR; |
| 39 | class RasterizerVulkan; | 37 | class RasterizerVulkan; |
| @@ -44,7 +42,7 @@ class PresentManager; | |||
| 44 | 42 | ||
| 45 | struct Frame; | 43 | struct Frame; |
| 46 | 44 | ||
| 47 | struct ScreenInfo { | 45 | struct FramebufferTextureInfo { |
| 48 | VkImage image{}; | 46 | VkImage image{}; |
| 49 | VkImageView image_view{}; | 47 | VkImageView image_view{}; |
| 50 | u32 width{}; | 48 | u32 width{}; |
| @@ -56,17 +54,17 @@ public: | |||
| 56 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, | 54 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, |
| 57 | Core::Frontend::EmuWindow& render_window, const Device& device, | 55 | Core::Frontend::EmuWindow& render_window, const Device& device, |
| 58 | MemoryAllocator& memory_manager, Swapchain& swapchain, | 56 | MemoryAllocator& memory_manager, Swapchain& swapchain, |
| 59 | PresentManager& present_manager, Scheduler& scheduler, | 57 | PresentManager& present_manager, Scheduler& scheduler); |
| 60 | const ScreenInfo& screen_info); | ||
| 61 | ~BlitScreen(); | 58 | ~BlitScreen(); |
| 62 | 59 | ||
| 63 | void Recreate(); | 60 | void Recreate(); |
| 64 | 61 | ||
| 65 | void Draw(const Tegra::FramebufferConfig& framebuffer, const VkFramebuffer& host_framebuffer, | 62 | void Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, |
| 66 | const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); | 63 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, |
| 64 | VkExtent2D render_area); | ||
| 67 | 65 | ||
| 68 | void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | 66 | void DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, |
| 69 | bool use_accelerated); | 67 | const Tegra::FramebufferConfig& framebuffer); |
| 70 | 68 | ||
| 71 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | 69 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, |
| 72 | VkExtent2D extent); | 70 | VkExtent2D extent); |
| @@ -99,7 +97,8 @@ private: | |||
| 99 | void UpdateAADescriptorSet(VkImageView image_view, bool nn) const; | 97 | void UpdateAADescriptorSet(VkImageView image_view, bool nn) const; |
| 100 | void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; | 98 | void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; |
| 101 | void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | 99 | void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, |
| 102 | const Layout::FramebufferLayout layout) const; | 100 | const Layout::FramebufferLayout layout, u32 texture_width, |
| 101 | u32 texture_height) const; | ||
| 103 | 102 | ||
| 104 | void CreateSMAA(VkExtent2D smaa_size); | 103 | void CreateSMAA(VkExtent2D smaa_size); |
| 105 | void CreateFSR(); | 104 | void CreateFSR(); |
| @@ -116,7 +115,6 @@ private: | |||
| 116 | Scheduler& scheduler; | 115 | Scheduler& scheduler; |
| 117 | std::size_t image_count; | 116 | std::size_t image_count; |
| 118 | std::size_t image_index{}; | 117 | std::size_t image_index{}; |
| 119 | const ScreenInfo& screen_info; | ||
| 120 | 118 | ||
| 121 | vk::ShaderModule vertex_shader; | 119 | vk::ShaderModule vertex_shader; |
| 122 | vk::ShaderModule fxaa_vertex_shader; | 120 | vk::ShaderModule fxaa_vertex_shader; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5bf41b81f..e593d7225 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -165,10 +165,9 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, | |||
| 165 | 165 | ||
| 166 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 166 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 167 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 167 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 168 | ScreenInfo& screen_info_, const Device& device_, | 168 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 169 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | 169 | StateTracker& state_tracker_, Scheduler& scheduler_) |
| 170 | Scheduler& scheduler_) | 170 | : gpu{gpu_}, device_memory{device_memory_}, device{device_}, |
| 171 | : gpu{gpu_}, device_memory{device_memory_}, screen_info{screen_info_}, device{device_}, | ||
| 172 | memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, | 171 | memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, |
| 173 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), | 172 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), |
| 174 | guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), | 173 | guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), |
| @@ -783,23 +782,25 @@ void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si | |||
| 783 | query_cache.InvalidateRegion(*cpu_addr, copy_size); | 782 | query_cache.InvalidateRegion(*cpu_addr, copy_size); |
| 784 | } | 783 | } |
| 785 | 784 | ||
| 786 | bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | 785 | std::optional<FramebufferTextureInfo> RasterizerVulkan::AccelerateDisplay( |
| 787 | DAddr framebuffer_addr, u32 pixel_stride) { | 786 | const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { |
| 788 | if (!framebuffer_addr) { | 787 | if (!framebuffer_addr) { |
| 789 | return false; | 788 | return {}; |
| 790 | } | 789 | } |
| 791 | std::scoped_lock lock{texture_cache.mutex}; | 790 | std::scoped_lock lock{texture_cache.mutex}; |
| 792 | ImageView* const image_view = | 791 | ImageView* const image_view = |
| 793 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); | 792 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); |
| 794 | if (!image_view) { | 793 | if (!image_view) { |
| 795 | return false; | 794 | return {}; |
| 796 | } | 795 | } |
| 797 | query_cache.NotifySegment(false); | 796 | query_cache.NotifySegment(false); |
| 798 | screen_info.image = image_view->ImageHandle(); | 797 | |
| 799 | screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); | 798 | FramebufferTextureInfo info{}; |
| 800 | screen_info.width = image_view->size.width; | 799 | info.image = image_view->ImageHandle(); |
| 801 | screen_info.height = image_view->size.height; | 800 | info.image_view = image_view->Handle(Shader::TextureType::Color2D); |
| 802 | return true; | 801 | info.width = image_view->size.width; |
| 802 | info.height = image_view->size.height; | ||
| 803 | return info; | ||
| 803 | } | 804 | } |
| 804 | 805 | ||
| 805 | void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 806 | void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 881ee0993..0617b37f0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -43,7 +43,7 @@ class Maxwell3D; | |||
| 43 | 43 | ||
| 44 | namespace Vulkan { | 44 | namespace Vulkan { |
| 45 | 45 | ||
| 46 | struct ScreenInfo; | 46 | struct FramebufferTextureInfo; |
| 47 | 47 | ||
| 48 | class StateTracker; | 48 | class StateTracker; |
| 49 | 49 | ||
| @@ -78,9 +78,8 @@ class RasterizerVulkan final : public VideoCore::RasterizerInterface, | |||
| 78 | public: | 78 | public: |
| 79 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 79 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 80 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 80 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 81 | ScreenInfo& screen_info_, const Device& device_, | 81 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 82 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | 82 | StateTracker& state_tracker_, Scheduler& scheduler_); |
| 83 | Scheduler& scheduler_); | ||
| 84 | ~RasterizerVulkan() override; | 83 | ~RasterizerVulkan() override; |
| 85 | 84 | ||
| 86 | void Draw(bool is_indexed, u32 instance_count) override; | 85 | void Draw(bool is_indexed, u32 instance_count) override; |
| @@ -126,8 +125,6 @@ public: | |||
| 126 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | 125 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; |
| 127 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 126 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 128 | std::span<const u8> memory) override; | 127 | std::span<const u8> memory) override; |
| 129 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||
| 130 | u32 pixel_stride) override; | ||
| 131 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 128 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 132 | const VideoCore::DiskResourceLoadCallback& callback) override; | 129 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| 133 | 130 | ||
| @@ -137,6 +134,10 @@ public: | |||
| 137 | 134 | ||
| 138 | void ReleaseChannel(s32 channel_id) override; | 135 | void ReleaseChannel(s32 channel_id) override; |
| 139 | 136 | ||
| 137 | std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 138 | VAddr framebuffer_addr, | ||
| 139 | u32 pixel_stride); | ||
| 140 | |||
| 140 | private: | 141 | private: |
| 141 | static constexpr size_t MAX_TEXTURES = 192; | 142 | static constexpr size_t MAX_TEXTURES = 192; |
| 142 | static constexpr size_t MAX_IMAGES = 48; | 143 | static constexpr size_t MAX_IMAGES = 48; |
| @@ -182,7 +183,6 @@ private: | |||
| 182 | Tegra::GPU& gpu; | 183 | Tegra::GPU& gpu; |
| 183 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 184 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 184 | 185 | ||
| 185 | ScreenInfo& screen_info; | ||
| 186 | const Device& device; | 186 | const Device& device; |
| 187 | MemoryAllocator& memory_allocator; | 187 | MemoryAllocator& memory_allocator; |
| 188 | StateTracker& state_tracker; | 188 | StateTracker& state_tracker; |