summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h2
-rw-r--r--src/video_core/capture.h36
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/fence_manager.h4
-rw-r--r--src/video_core/framebuffer_config.h7
-rw-r--r--src/video_core/gpu.cpp15
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/gpu_thread.cpp4
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp4
-rw-r--r--src/video_core/host_shaders/fidelityfx_fsr.frag21
-rw-r--r--src/video_core/host_shaders/fxaa.frag2
-rw-r--r--src/video_core/host_shaders/opengl_fidelityfx_fsr.frag19
-rw-r--r--src/video_core/host_shaders/opengl_present.frag2
-rw-r--r--src/video_core/host_shaders/present_bicubic.frag2
-rw-r--r--src/video_core/host_shaders/present_gaussian.frag14
-rw-r--r--src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16.frag1
-rw-r--r--src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32.frag1
-rw-r--r--src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16.frag1
-rw-r--r--src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32.frag1
-rw-r--r--src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag2
-rw-r--r--src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag2
-rw-r--r--src/video_core/macro/macro_hle.cpp8
-rw-r--r--src/video_core/present.h37
-rw-r--r--src/video_core/renderer_base.h3
-rw-r--r--src/video_core/renderer_null/renderer_null.cpp5
-rw-r--r--src/video_core/renderer_null/renderer_null.h2
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_opengl/present/layer.cpp35
-rw-r--r--src/video_core/renderer_opengl/present/layer.h8
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.cpp19
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp89
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h9
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp23
-rw-r--r--src/video_core/renderer_vulkan/present/layer.h6
-rw-r--r--src/video_core/renderer_vulkan/present/util.cpp92
-rw-r--r--src/video_core/renderer_vulkan/present/util.h9
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.cpp29
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.h6
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp118
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp8
-rw-r--r--src/video_core/texture_cache/image_info.cpp1
-rw-r--r--src/video_core/texture_cache/image_info.h1
-rw-r--r--src/video_core/texture_cache/texture_cache.h23
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.cpp4
51 files changed, 566 insertions, 179 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 55180f4b5..2de2beb6e 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -18,6 +18,7 @@ add_library(video_core STATIC
18 buffer_cache/usage_tracker.h 18 buffer_cache/usage_tracker.h
19 buffer_cache/word_manager.h 19 buffer_cache/word_manager.h
20 cache_types.h 20 cache_types.h
21 capture.h
21 cdma_pusher.cpp 22 cdma_pusher.cpp
22 cdma_pusher.h 23 cdma_pusher.h
23 compatible_formats.cpp 24 compatible_formats.cpp
@@ -101,6 +102,7 @@ add_library(video_core STATIC
101 memory_manager.cpp 102 memory_manager.cpp
102 memory_manager.h 103 memory_manager.h
103 precompiled_headers.h 104 precompiled_headers.h
105 present.h
104 pte_kind.h 106 pte_kind.h
105 query_cache/bank_base.h 107 query_cache/bank_base.h
106 query_cache/query_base.h 108 query_cache/query_base.h
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 3818e00f4..ed7a5b27e 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1130,7 +1130,7 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
1130 channel_state->vertex_buffers[index] = NULL_BINDING; 1130 channel_state->vertex_buffers[index] = NULL_BINDING;
1131 return; 1131 return;
1132 } 1132 }
1133 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { 1133 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
1134 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); 1134 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
1135 } 1135 }
1136 const BufferId buffer_id = FindBuffer(*device_addr, size); 1136 const BufferId buffer_id = FindBuffer(*device_addr, size);
diff --git a/src/video_core/capture.h b/src/video_core/capture.h
new file mode 100644
index 000000000..8db14a8ec
--- /dev/null
+++ b/src/video_core/capture.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/alignment.h"
7#include "common/bit_util.h"
8#include "common/common_types.h"
9#include "core/frontend/framebuffer_layout.h"
10#include "video_core/surface.h"
11
12namespace VideoCore::Capture {
13
14constexpr u32 BlockHeight = 4;
15constexpr u32 BlockDepth = 0;
16constexpr u32 BppLog2 = 2;
17
18constexpr auto PixelFormat = Surface::PixelFormat::B8G8R8A8_UNORM;
19
20constexpr auto LinearWidth = Layout::ScreenUndocked::Width;
21constexpr auto LinearHeight = Layout::ScreenUndocked::Height;
22constexpr auto LinearDepth = 1U;
23constexpr auto BytesPerPixel = 4U;
24
25constexpr auto TiledWidth = LinearWidth;
26constexpr auto TiledHeight = Common::AlignUpLog2(LinearHeight, BlockHeight + BlockDepth + BppLog2);
27constexpr auto TiledSize = TiledWidth * TiledHeight * (1 << BppLog2);
28
29constexpr Layout::FramebufferLayout Layout{
30 .width = LinearWidth,
31 .height = LinearHeight,
32 .screen = {0, 0, LinearWidth, LinearHeight},
33 .is_srgb = false,
34};
35
36} // namespace VideoCore::Capture
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index a94e1f043..0d47b032c 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -291,7 +291,9 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
291} 291}
292 292
293void Maxwell3D::ConsumeSinkImpl() { 293void Maxwell3D::ConsumeSinkImpl() {
294 SCOPE_EXIT({ method_sink.clear(); }); 294 SCOPE_EXIT {
295 method_sink.clear();
296 };
295 const auto control = shadow_state.shadow_ram_control; 297 const auto control = shadow_state.shadow_ram_control;
296 if (control == Regs::ShadowRamControl::Track || 298 if (control == Regs::ShadowRamControl::Track ||
297 control == Regs::ShadowRamControl::TrackWithFilter) { 299 control == Regs::ShadowRamControl::TrackWithFilter) {
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index c3eda6893..2135f1f2d 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -197,7 +197,9 @@ private:
197 MicroProfileOnThreadCreate(name.c_str()); 197 MicroProfileOnThreadCreate(name.c_str());
198 198
199 // Cleanup 199 // Cleanup
200 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 200 SCOPE_EXIT {
201 MicroProfileOnThreadExit();
202 };
201 203
202 Common::SetCurrentThreadName(name.c_str()); 204 Common::SetCurrentThreadName(name.c_str());
203 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 205 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h
index 6a18b76fb..8b2a49de5 100644
--- a/src/video_core/framebuffer_config.h
+++ b/src/video_core/framebuffer_config.h
@@ -11,6 +11,12 @@
11 11
12namespace Tegra { 12namespace Tegra {
13 13
14enum class BlendMode {
15 Opaque,
16 Premultiplied,
17 Coverage,
18};
19
14/** 20/**
15 * Struct describing framebuffer configuration 21 * Struct describing framebuffer configuration
16 */ 22 */
@@ -23,6 +29,7 @@ struct FramebufferConfig {
23 Service::android::PixelFormat pixel_format{}; 29 Service::android::PixelFormat pixel_format{};
24 Service::android::BufferTransformFlags transform_flags{}; 30 Service::android::BufferTransformFlags transform_flags{};
25 Common::Rectangle<int> crop_rect{}; 31 Common::Rectangle<int> crop_rect{};
32 BlendMode blending{};
26}; 33};
27 34
28Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width, 35Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width,
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index f4a5d831c..8e663f2a8 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -347,6 +347,17 @@ struct GPU::Impl {
347 WaitForSyncOperation(wait_fence); 347 WaitForSyncOperation(wait_fence);
348 } 348 }
349 349
350 std::vector<u8> GetAppletCaptureBuffer() {
351 std::vector<u8> out;
352
353 const auto wait_fence =
354 RequestSyncOperation([&] { out = renderer->GetAppletCaptureBuffer(); });
355 gpu_thread.TickGPU();
356 WaitForSyncOperation(wait_fence);
357
358 return out;
359 }
360
350 GPU& gpu; 361 GPU& gpu;
351 Core::System& system; 362 Core::System& system;
352 Host1x::Host1x& host1x; 363 Host1x::Host1x& host1x;
@@ -505,6 +516,10 @@ void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
505 impl->RequestComposite(std::move(layers), std::move(fences)); 516 impl->RequestComposite(std::move(layers), std::move(fences));
506} 517}
507 518
519std::vector<u8> GPU::GetAppletCaptureBuffer() {
520 return impl->GetAppletCaptureBuffer();
521}
522
508u64 GPU::GetTicks() const { 523u64 GPU::GetTicks() const {
509 return impl->GetTicks(); 524 return impl->GetTicks();
510} 525}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index c4602ca37..ad535512c 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -215,6 +215,8 @@ public:
215 void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, 215 void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
216 std::vector<Service::Nvidia::NvFence>&& fences); 216 std::vector<Service::Nvidia::NvFence>&& fences);
217 217
218 std::vector<u8> GetAppletCaptureBuffer();
219
218 /// Performs any additional setup necessary in order to begin GPU emulation. 220 /// Performs any additional setup necessary in order to begin GPU emulation.
219 /// This can be used to launch any necessary threads and register any necessary 221 /// This can be used to launch any necessary threads and register any necessary
220 /// core timing events. 222 /// core timing events.
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 58d8110b8..477e11457 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -22,7 +22,9 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
22 Tegra::Control::Scheduler& scheduler, SynchState& state) { 22 Tegra::Control::Scheduler& scheduler, SynchState& state) {
23 std::string name = "GPU"; 23 std::string name = "GPU";
24 MicroProfileOnThreadCreate(name.c_str()); 24 MicroProfileOnThreadCreate(name.c_str());
25 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 25 SCOPE_EXIT {
26 MicroProfileOnThreadExit();
27 };
26 28
27 Common::SetCurrentThreadName(name.c_str()); 29 Common::SetCurrentThreadName(name.c_str());
28 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); 30 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
index 96686da59..1003cd38d 100644
--- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp
+++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
@@ -273,10 +273,10 @@ DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) {
273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); 273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
274 AVFilterInOut* inputs = avfilter_inout_alloc(); 274 AVFilterInOut* inputs = avfilter_inout_alloc();
275 AVFilterInOut* outputs = avfilter_inout_alloc(); 275 AVFilterInOut* outputs = avfilter_inout_alloc();
276 SCOPE_EXIT({ 276 SCOPE_EXIT {
277 avfilter_inout_free(&inputs); 277 avfilter_inout_free(&inputs);
278 avfilter_inout_free(&outputs); 278 avfilter_inout_free(&outputs);
279 }); 279 };
280 280
281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter 281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter
282 // so just use 1/1 to make buffer filter happy 282 // so just use 1/1 to make buffer filter happy
diff --git a/src/video_core/host_shaders/fidelityfx_fsr.frag b/src/video_core/host_shaders/fidelityfx_fsr.frag
index a266e1c4e..54eedb450 100644
--- a/src/video_core/host_shaders/fidelityfx_fsr.frag
+++ b/src/video_core/host_shaders/fidelityfx_fsr.frag
@@ -37,6 +37,7 @@ layout(set=0,binding=0) uniform sampler2D InputTexture;
37 37
38#define A_GPU 1 38#define A_GPU 1
39#define A_GLSL 1 39#define A_GLSL 1
40#define FSR_RCAS_PASSTHROUGH_ALPHA 1
40 41
41#ifndef YUZU_USE_FP16 42#ifndef YUZU_USE_FP16
42 #include "ffx_a.h" 43 #include "ffx_a.h"
@@ -71,9 +72,7 @@ layout(set=0,binding=0) uniform sampler2D InputTexture;
71 72
72#include "ffx_fsr1.h" 73#include "ffx_fsr1.h"
73 74
74#if USE_RCAS 75layout (location = 0) in vec2 frag_texcoord;
75 layout(location = 0) in vec2 frag_texcoord;
76#endif
77layout (location = 0) out vec4 frag_color; 76layout (location = 0) out vec4 frag_color;
78 77
79void CurrFilter(AU2 pos) { 78void CurrFilter(AU2 pos) {
@@ -81,22 +80,22 @@ void CurrFilter(AU2 pos) {
81 #ifndef YUZU_USE_FP16 80 #ifndef YUZU_USE_FP16
82 AF3 c; 81 AF3 c;
83 FsrEasuF(c, pos, Const0, Const1, Const2, Const3); 82 FsrEasuF(c, pos, Const0, Const1, Const2, Const3);
84 frag_color = AF4(c, 1.0); 83 frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
85 #else 84 #else
86 AH3 c; 85 AH3 c;
87 FsrEasuH(c, pos, Const0, Const1, Const2, Const3); 86 FsrEasuH(c, pos, Const0, Const1, Const2, Const3);
88 frag_color = AH4(c, 1.0); 87 frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
89 #endif 88 #endif
90#endif 89#endif
91#if USE_RCAS 90#if USE_RCAS
92 #ifndef YUZU_USE_FP16 91 #ifndef YUZU_USE_FP16
93 AF3 c; 92 AF4 c;
94 FsrRcasF(c.r, c.g, c.b, pos, Const0); 93 FsrRcasF(c.r, c.g, c.b, c.a, pos, Const0);
95 frag_color = AF4(c, 1.0); 94 frag_color = c;
96 #else 95 #else
97 AH3 c; 96 AH4 c;
98 FsrRcasH(c.r, c.g, c.b, pos, Const0); 97 FsrRcasH(c.r, c.g, c.b, c.a, pos, Const0);
99 frag_color = AH4(c, 1.0); 98 frag_color = c;
100 #endif 99 #endif
101#endif 100#endif
102} 101}
diff --git a/src/video_core/host_shaders/fxaa.frag b/src/video_core/host_shaders/fxaa.frag
index 9bffc20d5..192a602c1 100644
--- a/src/video_core/host_shaders/fxaa.frag
+++ b/src/video_core/host_shaders/fxaa.frag
@@ -71,5 +71,5 @@ vec3 FxaaPixelShader(vec4 posPos, sampler2D tex) {
71} 71}
72 72
73void main() { 73void main() {
74 frag_color = vec4(FxaaPixelShader(posPos, input_texture), 1.0); 74 frag_color = vec4(FxaaPixelShader(posPos, input_texture), texture(input_texture, posPos.xy).a);
75} 75}
diff --git a/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag b/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag
index 16d22f58e..fc47d3810 100644
--- a/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag
+++ b/src/video_core/host_shaders/opengl_fidelityfx_fsr.frag
@@ -31,6 +31,7 @@ layout (location = 0) uniform uvec4 constants[4];
31 31
32#define A_GPU 1 32#define A_GPU 1
33#define A_GLSL 1 33#define A_GLSL 1
34#define FSR_RCAS_PASSTHROUGH_ALPHA 1
34 35
35#ifdef YUZU_USE_FP16 36#ifdef YUZU_USE_FP16
36 #define A_HALF 37 #define A_HALF
@@ -67,9 +68,7 @@ layout (location = 0) uniform uvec4 constants[4];
67 68
68#include "ffx_fsr1.h" 69#include "ffx_fsr1.h"
69 70
70#if USE_RCAS 71layout (location = 0) in vec2 frag_texcoord;
71 layout(location = 0) in vec2 frag_texcoord;
72#endif
73layout (location = 0) out vec4 frag_color; 72layout (location = 0) out vec4 frag_color;
74 73
75void CurrFilter(AU2 pos) 74void CurrFilter(AU2 pos)
@@ -78,22 +77,22 @@ void CurrFilter(AU2 pos)
78 #ifndef YUZU_USE_FP16 77 #ifndef YUZU_USE_FP16
79 AF3 c; 78 AF3 c;
80 FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]); 79 FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]);
81 frag_color = AF4(c, 1.0); 80 frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
82 #else 81 #else
83 AH3 c; 82 AH3 c;
84 FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]); 83 FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]);
85 frag_color = AH4(c, 1.0); 84 frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
86 #endif 85 #endif
87#endif 86#endif
88#if USE_RCAS 87#if USE_RCAS
89 #ifndef YUZU_USE_FP16 88 #ifndef YUZU_USE_FP16
90 AF3 c; 89 AF4 c;
91 FsrRcasF(c.r, c.g, c.b, pos, constants[0]); 90 FsrRcasF(c.r, c.g, c.b, c.a, pos, constants[0]);
92 frag_color = AF4(c, 1.0); 91 frag_color = c;
93 #else 92 #else
94 AH3 c; 93 AH3 c;
95 FsrRcasH(c.r, c.g, c.b, pos, constants[0]); 94 FsrRcasH(c.r, c.g, c.b, c.a, pos, constants[0]);
96 frag_color = AH4(c, 1.0); 95 frag_color = c;
97 #endif 96 #endif
98#endif 97#endif
99} 98}
diff --git a/src/video_core/host_shaders/opengl_present.frag b/src/video_core/host_shaders/opengl_present.frag
index 5fd7ad297..096b4e4db 100644
--- a/src/video_core/host_shaders/opengl_present.frag
+++ b/src/video_core/host_shaders/opengl_present.frag
@@ -9,5 +9,5 @@ layout (location = 0) out vec4 color;
9layout (binding = 0) uniform sampler2D color_texture; 9layout (binding = 0) uniform sampler2D color_texture;
10 10
11void main() { 11void main() {
12 color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f); 12 color = vec4(texture(color_texture, frag_tex_coord));
13} 13}
diff --git a/src/video_core/host_shaders/present_bicubic.frag b/src/video_core/host_shaders/present_bicubic.frag
index c814629cf..a9d9d40a3 100644
--- a/src/video_core/host_shaders/present_bicubic.frag
+++ b/src/video_core/host_shaders/present_bicubic.frag
@@ -52,5 +52,5 @@ vec4 textureBicubic( sampler2D textureSampler, vec2 texCoords ) {
52} 52}
53 53
54void main() { 54void main() {
55 color = vec4(textureBicubic(color_texture, frag_tex_coord).rgb, 1.0f); 55 color = textureBicubic(color_texture, frag_tex_coord);
56} 56}
diff --git a/src/video_core/host_shaders/present_gaussian.frag b/src/video_core/host_shaders/present_gaussian.frag
index ad9bb76a4..78edeb9b4 100644
--- a/src/video_core/host_shaders/present_gaussian.frag
+++ b/src/video_core/host_shaders/present_gaussian.frag
@@ -46,14 +46,14 @@ vec4 blurDiagonal(sampler2D textureSampler, vec2 coord, vec2 norm) {
46} 46}
47 47
48void main() { 48void main() {
49 vec3 base = texture(color_texture, vec2(frag_tex_coord)).rgb * weight[0]; 49 vec4 base = texture(color_texture, vec2(frag_tex_coord)) * weight[0];
50 vec2 tex_offset = 1.0f / textureSize(color_texture, 0); 50 vec2 tex_offset = 1.0f / textureSize(color_texture, 0);
51 51
52 // TODO(Blinkhawk): This code can be optimized through shader group instructions. 52 // TODO(Blinkhawk): This code can be optimized through shader group instructions.
53 vec3 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset).rgb; 53 vec4 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset);
54 vec3 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset).rgb; 54 vec4 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset);
55 vec3 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset).rgb; 55 vec4 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset);
56 vec3 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0)).rgb; 56 vec4 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0));
57 vec3 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f); 57 vec4 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
58 color = vec4(combination + base, 1.0f); 58 color = combination + base;
59} 59}
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16.frag b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16.frag
index d369bef06..05d033310 100644
--- a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16.frag
+++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16.frag
@@ -6,5 +6,6 @@
6 6
7#define YUZU_USE_FP16 7#define YUZU_USE_FP16
8#define USE_EASU 1 8#define USE_EASU 1
9#define VERSION 1
9 10
10#include "fidelityfx_fsr.frag" 11#include "fidelityfx_fsr.frag"
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32.frag b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32.frag
index 6f25ef00f..7ae11dd66 100644
--- a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32.frag
+++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32.frag
@@ -5,5 +5,6 @@
5#extension GL_GOOGLE_include_directive : enable 5#extension GL_GOOGLE_include_directive : enable
6 6
7#define USE_EASU 1 7#define USE_EASU 1
8#define VERSION 1
8 9
9#include "fidelityfx_fsr.frag" 10#include "fidelityfx_fsr.frag"
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16.frag b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16.frag
index 0c953a900..c017214a5 100644
--- a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16.frag
+++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16.frag
@@ -6,5 +6,6 @@
6 6
7#define YUZU_USE_FP16 7#define YUZU_USE_FP16
8#define USE_RCAS 1 8#define USE_RCAS 1
9#define VERSION 1
9 10
10#include "fidelityfx_fsr.frag" 11#include "fidelityfx_fsr.frag"
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32.frag b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32.frag
index 02e9a27c6..976825f4b 100644
--- a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32.frag
+++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32.frag
@@ -5,5 +5,6 @@
5#extension GL_GOOGLE_include_directive : enable 5#extension GL_GOOGLE_include_directive : enable
6 6
7#define USE_RCAS 1 7#define USE_RCAS 1
8#define VERSION 1
8 9
9#include "fidelityfx_fsr.frag" 10#include "fidelityfx_fsr.frag"
diff --git a/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag b/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag
index 79ea817c2..cea5dac9d 100644
--- a/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag
+++ b/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag
@@ -5,7 +5,7 @@
5 5
6#extension GL_GOOGLE_include_directive : enable 6#extension GL_GOOGLE_include_directive : enable
7 7
8#define VERSION 1 8#define VERSION 2
9#define YUZU_USE_FP16 9#define YUZU_USE_FP16
10 10
11#include "opengl_present_scaleforce.frag" 11#include "opengl_present_scaleforce.frag"
diff --git a/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag b/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag
index 9605bb58b..10ddf0401 100644
--- a/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag
+++ b/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag
@@ -5,6 +5,6 @@
5 5
6#extension GL_GOOGLE_include_directive : enable 6#extension GL_GOOGLE_include_directive : enable
7 7
8#define VERSION 1 8#define VERSION 2
9 9
10#include "opengl_present_scaleforce.frag" 10#include "opengl_present_scaleforce.frag"
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 46e853e04..fb529f88b 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -92,12 +92,12 @@ public:
92 92
93private: 93private:
94 void Fallback(const std::vector<u32>& parameters) { 94 void Fallback(const std::vector<u32>& parameters) {
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (extended) { 96 if (extended) {
97 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 97 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
98 maxwell3d.replace_table.clear(); 98 maxwell3d.replace_table.clear();
99 } 99 }
100 }); 100 };
101 maxwell3d.RefreshParameters(); 101 maxwell3d.RefreshParameters();
102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
103 103
@@ -281,12 +281,12 @@ public:
281 281
282private: 282private:
283 void Fallback(const std::vector<u32>& parameters) { 283 void Fallback(const std::vector<u32>& parameters) {
284 SCOPE_EXIT({ 284 SCOPE_EXIT {
285 // Clean everything. 285 // Clean everything.
286 maxwell3d.regs.vertex_id_base = 0x0; 286 maxwell3d.regs.vertex_id_base = 0x0;
287 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 287 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
288 maxwell3d.replace_table.clear(); 288 maxwell3d.replace_table.clear();
289 }); 289 };
290 maxwell3d.RefreshParameters(); 290 maxwell3d.RefreshParameters();
291 const u32 start_indirect = parameters[0]; 291 const u32 start_indirect = parameters[0];
292 const u32 end_indirect = parameters[1]; 292 const u32 end_indirect = parameters[1];
diff --git a/src/video_core/present.h b/src/video_core/present.h
new file mode 100644
index 000000000..4fdfcca68
--- /dev/null
+++ b/src/video_core/present.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/settings.h"
7
8static inline Settings::ScalingFilter GetScalingFilter() {
9 return Settings::values.scaling_filter.GetValue();
10}
11
12static inline Settings::AntiAliasing GetAntiAliasing() {
13 return Settings::values.anti_aliasing.GetValue();
14}
15
16static inline Settings::ScalingFilter GetScalingFilterForAppletCapture() {
17 return Settings::ScalingFilter::Bilinear;
18}
19
20static inline Settings::AntiAliasing GetAntiAliasingForAppletCapture() {
21 return Settings::AntiAliasing::None;
22}
23
24struct PresentFilters {
25 Settings::ScalingFilter (*get_scaling_filter)();
26 Settings::AntiAliasing (*get_anti_aliasing)();
27};
28
29constexpr PresentFilters PresentFiltersForDisplay{
30 .get_scaling_filter = &GetScalingFilter,
31 .get_anti_aliasing = &GetAntiAliasing,
32};
33
34constexpr PresentFilters PresentFiltersForAppletCapture{
35 .get_scaling_filter = &GetScalingFilterForAppletCapture,
36 .get_anti_aliasing = &GetAntiAliasingForAppletCapture,
37};
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 3ad180f67..67427f937 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -40,6 +40,9 @@ public:
40 /// Finalize rendering the guest frame and draw into the presentation texture 40 /// Finalize rendering the guest frame and draw into the presentation texture
41 virtual void Composite(std::span<const Tegra::FramebufferConfig> layers) = 0; 41 virtual void Composite(std::span<const Tegra::FramebufferConfig> layers) = 0;
42 42
43 /// Get the tiled applet layer capture buffer
44 virtual std::vector<u8> GetAppletCaptureBuffer() = 0;
45
43 [[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0; 46 [[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0;
44 47
45 [[nodiscard]] virtual std::string GetDeviceVendor() const = 0; 48 [[nodiscard]] virtual std::string GetDeviceVendor() const = 0;
diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp
index c89daff53..e6147d66c 100644
--- a/src/video_core/renderer_null/renderer_null.cpp
+++ b/src/video_core/renderer_null/renderer_null.cpp
@@ -3,6 +3,7 @@
3 3
4#include "core/frontend/emu_window.h" 4#include "core/frontend/emu_window.h"
5#include "core/frontend/graphics_context.h" 5#include "core/frontend/graphics_context.h"
6#include "video_core/capture.h"
6#include "video_core/renderer_null/renderer_null.h" 7#include "video_core/renderer_null/renderer_null.h"
7 8
8namespace Null { 9namespace Null {
@@ -22,4 +23,8 @@ void RendererNull::Composite(std::span<const Tegra::FramebufferConfig> framebuff
22 render_window.OnFrameDisplayed(); 23 render_window.OnFrameDisplayed();
23} 24}
24 25
26std::vector<u8> RendererNull::GetAppletCaptureBuffer() {
27 return std::vector<u8>(VideoCore::Capture::TiledSize);
28}
29
25} // namespace Null 30} // namespace Null
diff --git a/src/video_core/renderer_null/renderer_null.h b/src/video_core/renderer_null/renderer_null.h
index 063b476bb..34dbe1e4f 100644
--- a/src/video_core/renderer_null/renderer_null.h
+++ b/src/video_core/renderer_null/renderer_null.h
@@ -19,6 +19,8 @@ public:
19 19
20 void Composite(std::span<const Tegra::FramebufferConfig> framebuffer) override; 20 void Composite(std::span<const Tegra::FramebufferConfig> framebuffer) override;
21 21
22 std::vector<u8> GetAppletCaptureBuffer() override;
23
22 VideoCore::RasterizerInterface* ReadRasterizer() override { 24 VideoCore::RasterizerInterface* ReadRasterizer() override {
23 return &m_rasterizer; 25 return &m_rasterizer;
24 } 26 }
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp
index 6ba8b214b..9260a4dc4 100644
--- a/src/video_core/renderer_opengl/gl_blit_screen.cpp
+++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/settings.h" 4#include "common/settings.h"
5#include "video_core/present.h"
5#include "video_core/renderer_opengl/gl_blit_screen.h" 6#include "video_core/renderer_opengl/gl_blit_screen.h"
6#include "video_core/renderer_opengl/gl_state_tracker.h" 7#include "video_core/renderer_opengl/gl_state_tracker.h"
7#include "video_core/renderer_opengl/present/filters.h" 8#include "video_core/renderer_opengl/present/filters.h"
@@ -13,14 +14,14 @@ namespace OpenGL {
13BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, 14BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_,
14 Tegra::MaxwellDeviceMemoryManager& device_memory_, 15 Tegra::MaxwellDeviceMemoryManager& device_memory_,
15 StateTracker& state_tracker_, ProgramManager& program_manager_, 16 StateTracker& state_tracker_, ProgramManager& program_manager_,
16 Device& device_) 17 Device& device_, const PresentFilters& filters_)
17 : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), 18 : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_),
18 program_manager(program_manager_), device(device_) {} 19 program_manager(program_manager_), device(device_), filters(filters_) {}
19 20
20BlitScreen::~BlitScreen() = default; 21BlitScreen::~BlitScreen() = default;
21 22
22void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, 23void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers,
23 const Layout::FramebufferLayout& layout) { 24 const Layout::FramebufferLayout& layout, bool invert_y) {
24 // TODO: Signal state tracker about these changes 25 // TODO: Signal state tracker about these changes
25 state_tracker.NotifyScreenDrawVertexArray(); 26 state_tracker.NotifyScreenDrawVertexArray();
26 state_tracker.NotifyPolygonModes(); 27 state_tracker.NotifyPolygonModes();
@@ -56,22 +57,22 @@ void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffe
56 glDepthRangeIndexed(0, 0.0, 0.0); 57 glDepthRangeIndexed(0, 0.0, 0.0);
57 58
58 while (layers.size() < framebuffers.size()) { 59 while (layers.size() < framebuffers.size()) {
59 layers.emplace_back(rasterizer, device_memory); 60 layers.emplace_back(rasterizer, device_memory, filters);
60 } 61 }
61 62
62 CreateWindowAdapt(); 63 CreateWindowAdapt();
63 window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout); 64 window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout, invert_y);
64 65
65 // TODO 66 // TODO
66 // program_manager.RestoreGuestPipeline(); 67 // program_manager.RestoreGuestPipeline();
67} 68}
68 69
69void BlitScreen::CreateWindowAdapt() { 70void BlitScreen::CreateWindowAdapt() {
70 if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { 71 if (window_adapt && filters.get_scaling_filter() == current_window_adapt) {
71 return; 72 return;
72 } 73 }
73 74
74 current_window_adapt = Settings::values.scaling_filter.GetValue(); 75 current_window_adapt = filters.get_scaling_filter();
75 switch (current_window_adapt) { 76 switch (current_window_adapt) {
76 case Settings::ScalingFilter::NearestNeighbor: 77 case Settings::ScalingFilter::NearestNeighbor:
77 window_adapt = MakeNearestNeighbor(device); 78 window_adapt = MakeNearestNeighbor(device);
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h
index 0c3d838f1..df2da9424 100644
--- a/src/video_core/renderer_opengl/gl_blit_screen.h
+++ b/src/video_core/renderer_opengl/gl_blit_screen.h
@@ -15,6 +15,8 @@ namespace Layout {
15struct FramebufferLayout; 15struct FramebufferLayout;
16} 16}
17 17
18struct PresentFilters;
19
18namespace Tegra { 20namespace Tegra {
19struct FramebufferConfig; 21struct FramebufferConfig;
20} 22}
@@ -46,12 +48,12 @@ public:
46 explicit BlitScreen(RasterizerOpenGL& rasterizer, 48 explicit BlitScreen(RasterizerOpenGL& rasterizer,
47 Tegra::MaxwellDeviceMemoryManager& device_memory, 49 Tegra::MaxwellDeviceMemoryManager& device_memory,
48 StateTracker& state_tracker, ProgramManager& program_manager, 50 StateTracker& state_tracker, ProgramManager& program_manager,
49 Device& device); 51 Device& device, const PresentFilters& filters);
50 ~BlitScreen(); 52 ~BlitScreen();
51 53
52 /// Draws the emulated screens to the emulator window. 54 /// Draws the emulated screens to the emulator window.
53 void DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, 55 void DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers,
54 const Layout::FramebufferLayout& layout); 56 const Layout::FramebufferLayout& layout, bool invert_y);
55 57
56private: 58private:
57 void CreateWindowAdapt(); 59 void CreateWindowAdapt();
@@ -61,6 +63,7 @@ private:
61 StateTracker& state_tracker; 63 StateTracker& state_tracker;
62 ProgramManager& program_manager; 64 ProgramManager& program_manager;
63 Device& device; 65 Device& device;
66 const PresentFilters& filters;
64 67
65 Settings::ScalingFilter current_window_adapt{}; 68 Settings::ScalingFilter current_window_adapt{};
66 std::unique_ptr<WindowAdaptPass> window_adapt; 69 std::unique_ptr<WindowAdaptPass> window_adapt;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b42fb110c..16af8e6bd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -230,7 +230,9 @@ template <typename Func>
230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { 230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
231 MICROPROFILE_SCOPE(OpenGL_Drawing); 231 MICROPROFILE_SCOPE(OpenGL_Drawing);
232 232
233 SCOPE_EXIT({ gpu.TickWork(); }); 233 SCOPE_EXIT {
234 gpu.TickWork();
235 };
234 gpu_memory->FlushCaching(); 236 gpu_memory->FlushCaching();
235 237
236 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; 238 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
@@ -355,7 +357,9 @@ void RasterizerOpenGL::DrawIndirect() {
355void RasterizerOpenGL::DrawTexture() { 357void RasterizerOpenGL::DrawTexture() {
356 MICROPROFILE_SCOPE(OpenGL_Drawing); 358 MICROPROFILE_SCOPE(OpenGL_Drawing);
357 359
358 SCOPE_EXIT({ gpu.TickWork(); }); 360 SCOPE_EXIT {
361 gpu.TickWork();
362 };
359 363
360 texture_cache.SynchronizeGraphicsDescriptors(); 364 texture_cache.SynchronizeGraphicsDescriptors();
361 texture_cache.UpdateRenderTargets(false); 365 texture_cache.UpdateRenderTargets(false);
diff --git a/src/video_core/renderer_opengl/present/layer.cpp b/src/video_core/renderer_opengl/present/layer.cpp
index 8643e07c6..6c7092d22 100644
--- a/src/video_core/renderer_opengl/present/layer.cpp
+++ b/src/video_core/renderer_opengl/present/layer.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "video_core/framebuffer_config.h" 4#include "video_core/framebuffer_config.h"
5#include "video_core/present.h"
5#include "video_core/renderer_opengl/gl_blit_screen.h" 6#include "video_core/renderer_opengl/gl_blit_screen.h"
6#include "video_core/renderer_opengl/gl_rasterizer.h" 7#include "video_core/renderer_opengl/gl_rasterizer.h"
7#include "video_core/renderer_opengl/present/fsr.h" 8#include "video_core/renderer_opengl/present/fsr.h"
@@ -14,8 +15,9 @@
14 15
15namespace OpenGL { 16namespace OpenGL {
16 17
17Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_) 18Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_,
18 : rasterizer(rasterizer_), device_memory(device_memory_) { 19 const PresentFilters& filters_)
20 : rasterizer(rasterizer_), device_memory(device_memory_), filters(filters_) {
19 // Allocate textures for the screen 21 // Allocate textures for the screen
20 framebuffer_texture.resource.Create(GL_TEXTURE_2D); 22 framebuffer_texture.resource.Create(GL_TEXTURE_2D);
21 23
@@ -34,12 +36,12 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
34 std::array<ScreenRectVertex, 4>& out_vertices, 36 std::array<ScreenRectVertex, 4>& out_vertices,
35 ProgramManager& program_manager, 37 ProgramManager& program_manager,
36 const Tegra::FramebufferConfig& framebuffer, 38 const Tegra::FramebufferConfig& framebuffer,
37 const Layout::FramebufferLayout& layout) { 39 const Layout::FramebufferLayout& layout, bool invert_y) {
38 FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); 40 FramebufferTextureInfo info = PrepareRenderTarget(framebuffer);
39 auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); 41 auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height);
40 GLuint texture = info.display_texture; 42 GLuint texture = info.display_texture;
41 43
42 auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); 44 auto anti_aliasing = filters.get_anti_aliasing();
43 if (anti_aliasing != Settings::AntiAliasing::None) { 45 if (anti_aliasing != Settings::AntiAliasing::None) {
44 glEnablei(GL_SCISSOR_TEST, 0); 46 glEnablei(GL_SCISSOR_TEST, 0);
45 auto viewport_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); 47 auto viewport_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width);
@@ -64,7 +66,7 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
64 66
65 glDisablei(GL_SCISSOR_TEST, 0); 67 glDisablei(GL_SCISSOR_TEST, 0);
66 68
67 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { 69 if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
68 if (!fsr || fsr->NeedsRecreation(layout.screen)) { 70 if (!fsr || fsr->NeedsRecreation(layout.screen)) {
69 fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); 71 fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight());
70 } 72 }
@@ -83,10 +85,15 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
83 const auto w = screen.GetWidth(); 85 const auto w = screen.GetWidth();
84 const auto h = screen.GetHeight(); 86 const auto h = screen.GetHeight();
85 87
86 out_vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); 88 const auto left = crop.left;
87 out_vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); 89 const auto right = crop.right;
88 out_vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); 90 const auto top = invert_y ? crop.bottom : crop.top;
89 out_vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); 91 const auto bottom = invert_y ? crop.top : crop.bottom;
92
93 out_vertices[0] = ScreenRectVertex(x, y, left, top);
94 out_vertices[1] = ScreenRectVertex(x + w, y, right, top);
95 out_vertices[2] = ScreenRectVertex(x, y + h, left, bottom);
96 out_vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom);
90 97
91 return texture; 98 return texture;
92} 99}
@@ -131,10 +138,12 @@ FramebufferTextureInfo Layer::LoadFBToScreenInfo(const Tegra::FramebufferConfig&
131 const u64 size_in_bytes{Tegra::Texture::CalculateSize( 138 const u64 size_in_bytes{Tegra::Texture::CalculateSize(
132 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; 139 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
133 const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; 140 const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
134 const std::span<const u8> input_data(host_ptr, size_in_bytes); 141 if (host_ptr) {
135 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, 142 const std::span<const u8> input_data(host_ptr, size_in_bytes);
136 framebuffer.width, framebuffer.height, 1, block_height_log2, 143 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
137 0); 144 framebuffer.width, framebuffer.height, 1,
145 block_height_log2, 0);
146 }
138 147
139 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 148 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
140 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); 149 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
diff --git a/src/video_core/renderer_opengl/present/layer.h b/src/video_core/renderer_opengl/present/layer.h
index ef1055abf..5b15b730f 100644
--- a/src/video_core/renderer_opengl/present/layer.h
+++ b/src/video_core/renderer_opengl/present/layer.h
@@ -13,6 +13,8 @@ namespace Layout {
13struct FramebufferLayout; 13struct FramebufferLayout;
14} 14}
15 15
16struct PresentFilters;
17
16namespace Service::android { 18namespace Service::android {
17enum class PixelFormat : u32; 19enum class PixelFormat : u32;
18}; 20};
@@ -44,14 +46,15 @@ struct ScreenRectVertex;
44 46
45class Layer { 47class Layer {
46public: 48public:
47 explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory); 49 explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory,
50 const PresentFilters& filters);
48 ~Layer(); 51 ~Layer();
49 52
50 GLuint ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, 53 GLuint ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
51 std::array<ScreenRectVertex, 4>& out_vertices, 54 std::array<ScreenRectVertex, 4>& out_vertices,
52 ProgramManager& program_manager, 55 ProgramManager& program_manager,
53 const Tegra::FramebufferConfig& framebuffer, 56 const Tegra::FramebufferConfig& framebuffer,
54 const Layout::FramebufferLayout& layout); 57 const Layout::FramebufferLayout& layout, bool invert_y);
55 58
56private: 59private:
57 /// Loads framebuffer from emulated memory into the active OpenGL texture. 60 /// Loads framebuffer from emulated memory into the active OpenGL texture.
@@ -65,6 +68,7 @@ private:
65private: 68private:
66 RasterizerOpenGL& rasterizer; 69 RasterizerOpenGL& rasterizer;
67 Tegra::MaxwellDeviceMemoryManager& device_memory; 70 Tegra::MaxwellDeviceMemoryManager& device_memory;
71 const PresentFilters& filters;
68 72
69 /// OpenGL framebuffer data 73 /// OpenGL framebuffer data
70 std::vector<u8> gl_framebuffer_data; 74 std::vector<u8> gl_framebuffer_data;
diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
index 4d681606b..d8b6a11cb 100644
--- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
@@ -37,7 +37,7 @@ WindowAdaptPass::~WindowAdaptPass() = default;
37 37
38void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, 38void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers,
39 std::span<const Tegra::FramebufferConfig> framebuffers, 39 std::span<const Tegra::FramebufferConfig> framebuffers,
40 const Layout::FramebufferLayout& layout) { 40 const Layout::FramebufferLayout& layout, bool invert_y) {
41 GLint old_read_fb; 41 GLint old_read_fb;
42 GLint old_draw_fb; 42 GLint old_draw_fb;
43 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); 43 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
@@ -51,7 +51,7 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li
51 auto layer_it = layers.begin(); 51 auto layer_it = layers.begin();
52 for (size_t i = 0; i < layer_count; i++) { 52 for (size_t i = 0; i < layer_count; i++) {
53 textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager, 53 textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager,
54 framebuffers[i], layout); 54 framebuffers[i], layout, invert_y);
55 layer_it++; 55 layer_it++;
56 } 56 }
57 57
@@ -92,6 +92,21 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li
92 glClear(GL_COLOR_BUFFER_BIT); 92 glClear(GL_COLOR_BUFFER_BIT);
93 93
94 for (size_t i = 0; i < layer_count; i++) { 94 for (size_t i = 0; i < layer_count; i++) {
95 switch (framebuffers[i].blending) {
96 case Tegra::BlendMode::Opaque:
97 default:
98 glDisablei(GL_BLEND, 0);
99 break;
100 case Tegra::BlendMode::Premultiplied:
101 glEnablei(GL_BLEND, 0);
102 glBlendFuncSeparatei(0, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
103 break;
104 case Tegra::BlendMode::Coverage:
105 glEnablei(GL_BLEND, 0);
106 glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
107 break;
108 }
109
95 glBindTextureUnit(0, textures[i]); 110 glBindTextureUnit(0, textures[i]);
96 glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, 111 glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE,
97 matrices[i].data()); 112 matrices[i].data());
diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.h b/src/video_core/renderer_opengl/present/window_adapt_pass.h
index 00975a9c6..0a8bcef2f 100644
--- a/src/video_core/renderer_opengl/present/window_adapt_pass.h
+++ b/src/video_core/renderer_opengl/present/window_adapt_pass.h
@@ -31,7 +31,7 @@ public:
31 31
32 void DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, 32 void DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers,
33 std::span<const Tegra::FramebufferConfig> framebuffers, 33 std::span<const Tegra::FramebufferConfig> framebuffers,
34 const Layout::FramebufferLayout& layout); 34 const Layout::FramebufferLayout& layout, bool invert_y);
35 35
36private: 36private:
37 const Device& device; 37 const Device& device;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index e33a32592..5fb54635d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -16,6 +16,8 @@
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/frontend/emu_window.h" 17#include "core/frontend/emu_window.h"
18#include "core/telemetry_session.h" 18#include "core/telemetry_session.h"
19#include "video_core/capture.h"
20#include "video_core/present.h"
19#include "video_core/renderer_opengl/gl_blit_screen.h" 21#include "video_core/renderer_opengl/gl_blit_screen.h"
20#include "video_core/renderer_opengl/gl_rasterizer.h" 22#include "video_core/renderer_opengl/gl_rasterizer.h"
21#include "video_core/renderer_opengl/gl_shader_manager.h" 23#include "video_core/renderer_opengl/gl_shader_manager.h"
@@ -120,7 +122,15 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
120 glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); 122 glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
121 } 123 }
122 blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, 124 blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker,
123 program_manager, device); 125 program_manager, device, PresentFiltersForDisplay);
126 blit_applet =
127 std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, program_manager,
128 device, PresentFiltersForAppletCapture);
129 capture_framebuffer.Create();
130 capture_renderbuffer.Create();
131 glBindRenderbuffer(GL_RENDERBUFFER, capture_renderbuffer.handle);
132 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, VideoCore::Capture::LinearWidth,
133 VideoCore::Capture::LinearHeight);
124} 134}
125 135
126RendererOpenGL::~RendererOpenGL() = default; 136RendererOpenGL::~RendererOpenGL() = default;
@@ -130,10 +140,11 @@ void RendererOpenGL::Composite(std::span<const Tegra::FramebufferConfig> framebu
130 return; 140 return;
131 } 141 }
132 142
143 RenderAppletCaptureLayer(framebuffers);
133 RenderScreenshot(framebuffers); 144 RenderScreenshot(framebuffers);
134 145
135 state_tracker.BindFramebuffer(0); 146 state_tracker.BindFramebuffer(0);
136 blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout()); 147 blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout(), false);
137 148
138 ++m_current_frame; 149 ++m_current_frame;
139 150
@@ -159,11 +170,8 @@ void RendererOpenGL::AddTelemetryFields() {
159 telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); 170 telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));
160} 171}
161 172
162void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) { 173void RendererOpenGL::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
163 if (!renderer_settings.screenshot_requested) { 174 const Layout::FramebufferLayout& layout, void* dst) {
164 return;
165 }
166
167 GLint old_read_fb; 175 GLint old_read_fb;
168 GLint old_draw_fb; 176 GLint old_draw_fb;
169 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); 177 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
@@ -173,29 +181,86 @@ void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig>
173 screenshot_framebuffer.Create(); 181 screenshot_framebuffer.Create();
174 glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); 182 glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle);
175 183
176 const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
177
178 GLuint renderbuffer; 184 GLuint renderbuffer;
179 glGenRenderbuffers(1, &renderbuffer); 185 glGenRenderbuffers(1, &renderbuffer);
180 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 186 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
181 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); 187 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height);
182 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 188 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
183 189
184 blit_screen->DrawScreen(framebuffers, layout); 190 blit_screen->DrawScreen(framebuffers, layout, false);
185 191
186 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 192 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
187 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 193 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
188 glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 194 glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dst);
189 renderer_settings.screenshot_bits);
190 195
191 screenshot_framebuffer.Release(); 196 screenshot_framebuffer.Release();
192 glDeleteRenderbuffers(1, &renderbuffer); 197 glDeleteRenderbuffers(1, &renderbuffer);
193 198
194 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); 199 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
195 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); 200 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
201}
202
203void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
204 if (!renderer_settings.screenshot_requested) {
205 return;
206 }
207
208 RenderToBuffer(framebuffers, renderer_settings.screenshot_framebuffer_layout,
209 renderer_settings.screenshot_bits);
196 210
197 renderer_settings.screenshot_complete_callback(true); 211 renderer_settings.screenshot_complete_callback(true);
198 renderer_settings.screenshot_requested = false; 212 renderer_settings.screenshot_requested = false;
199} 213}
200 214
215void RendererOpenGL::RenderAppletCaptureLayer(
216 std::span<const Tegra::FramebufferConfig> framebuffers) {
217 GLint old_read_fb;
218 GLint old_draw_fb;
219 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
220 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
221
222 glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle);
223 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
224 capture_renderbuffer.handle);
225
226 blit_applet->DrawScreen(framebuffers, VideoCore::Capture::Layout, true);
227
228 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
229 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
230}
231
232std::vector<u8> RendererOpenGL::GetAppletCaptureBuffer() {
233 using namespace VideoCore::Capture;
234
235 std::vector<u8> linear(TiledSize);
236 std::vector<u8> out(TiledSize);
237
238 GLint old_read_fb;
239 GLint old_draw_fb;
240 GLint old_pixel_pack_buffer;
241 GLint old_pack_row_length;
242 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
243 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
244 glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &old_pixel_pack_buffer);
245 glGetIntegerv(GL_PACK_ROW_LENGTH, &old_pack_row_length);
246
247 glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle);
248 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
249 capture_renderbuffer.handle);
250 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
251 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
252 glReadPixels(0, 0, LinearWidth, LinearHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
253 linear.data());
254
255 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
256 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
257 glBindBuffer(GL_PIXEL_PACK_BUFFER, old_pixel_pack_buffer);
258 glPixelStorei(GL_PACK_ROW_LENGTH, old_pack_row_length);
259
260 Tegra::Texture::SwizzleTexture(out, linear, BytesPerPixel, LinearWidth, LinearHeight,
261 LinearDepth, BlockHeight, BlockDepth);
262
263 return out;
264}
265
201} // namespace OpenGL 266} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index c4625c96e..60d6a1477 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -42,6 +42,8 @@ public:
42 42
43 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override; 43 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override;
44 44
45 std::vector<u8> GetAppletCaptureBuffer() override;
46
45 VideoCore::RasterizerInterface* ReadRasterizer() override { 47 VideoCore::RasterizerInterface* ReadRasterizer() override {
46 return &rasterizer; 48 return &rasterizer;
47 } 49 }
@@ -52,7 +54,11 @@ public:
52 54
53private: 55private:
54 void AddTelemetryFields(); 56 void AddTelemetryFields();
57
58 void RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
59 const Layout::FramebufferLayout& layout, void* dst);
55 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers); 60 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers);
61 void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers);
56 62
57 Core::TelemetrySession& telemetry_session; 63 Core::TelemetrySession& telemetry_session;
58 Core::Frontend::EmuWindow& emu_window; 64 Core::Frontend::EmuWindow& emu_window;
@@ -64,8 +70,11 @@ private:
64 ProgramManager program_manager; 70 ProgramManager program_manager;
65 RasterizerOpenGL rasterizer; 71 RasterizerOpenGL rasterizer;
66 OGLFramebuffer screenshot_framebuffer; 72 OGLFramebuffer screenshot_framebuffer;
73 OGLFramebuffer capture_framebuffer;
74 OGLRenderbuffer capture_renderbuffer;
67 75
68 std::unique_ptr<BlitScreen> blit_screen; 76 std::unique_ptr<BlitScreen> blit_screen;
77 std::unique_ptr<BlitScreen> blit_applet;
69}; 78};
70 79
71} // namespace OpenGL 80} // namespace OpenGL
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp
index cfc04be44..4e41afe5b 100644
--- a/src/video_core/renderer_vulkan/present/layer.cpp
+++ b/src/video_core/renderer_vulkan/present/layer.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "video_core/present.h"
4#include "video_core/renderer_vulkan/vk_rasterizer.h" 5#include "video_core/renderer_vulkan/vk_rasterizer.h"
5 6
6#include "common/settings.h" 7#include "common/settings.h"
@@ -48,12 +49,12 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
48 49
49Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, 50Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
50 Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_, 51 Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_,
51 VkExtent2D output_size, VkDescriptorSetLayout layout) 52 VkExtent2D output_size, VkDescriptorSetLayout layout, const PresentFilters& filters_)
52 : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_), 53 : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_),
53 device_memory(device_memory_), image_count(image_count_) { 54 device_memory(device_memory_), filters(filters_), image_count(image_count_) {
54 CreateDescriptorPool(); 55 CreateDescriptorPool();
55 CreateDescriptorSets(layout); 56 CreateDescriptorSets(layout);
56 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { 57 if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
57 CreateFSR(output_size); 58 CreateFSR(output_size);
58 } 59 }
59} 60}
@@ -81,7 +82,9 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
81 // Finish any pending renderpass 82 // Finish any pending renderpass
82 scheduler.RequestOutsideRenderPassOperationContext(); 83 scheduler.RequestOutsideRenderPassOperationContext();
83 scheduler.Wait(resource_ticks[image_index]); 84 scheduler.Wait(resource_ticks[image_index]);
84 SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); 85 SCOPE_EXIT {
86 resource_ticks[image_index] = scheduler.CurrentTick();
87 };
85 88
86 if (!use_accelerated) { 89 if (!use_accelerated) {
87 UpdateRawImage(framebuffer, image_index); 90 UpdateRawImage(framebuffer, image_index);
@@ -171,11 +174,11 @@ void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
171} 174}
172 175
173void Layer::SetAntiAliasPass() { 176void Layer::SetAntiAliasPass() {
174 if (anti_alias && anti_alias_setting == Settings::values.anti_aliasing.GetValue()) { 177 if (anti_alias && anti_alias_setting == filters.get_anti_aliasing()) {
175 return; 178 return;
176 } 179 }
177 180
178 anti_alias_setting = Settings::values.anti_aliasing.GetValue(); 181 anti_alias_setting = filters.get_anti_aliasing();
179 182
180 const VkExtent2D render_area{ 183 const VkExtent2D render_area{
181 .width = Settings::values.resolution_info.ScaleUp(raw_width), 184 .width = Settings::values.resolution_info.ScaleUp(raw_width),
@@ -270,9 +273,11 @@ void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t i
270 const u64 linear_size{GetSizeInBytes(framebuffer)}; 273 const u64 linear_size{GetSizeInBytes(framebuffer)};
271 const u64 tiled_size{Tegra::Texture::CalculateSize( 274 const u64 tiled_size{Tegra::Texture::CalculateSize(
272 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; 275 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
273 Tegra::Texture::UnswizzleTexture( 276 if (host_ptr) {
274 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), 277 Tegra::Texture::UnswizzleTexture(
275 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); 278 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
279 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
280 }
276 281
277 const VkBufferImageCopy copy{ 282 const VkBufferImageCopy copy{
278 .bufferOffset = image_offset, 283 .bufferOffset = image_offset,
diff --git a/src/video_core/renderer_vulkan/present/layer.h b/src/video_core/renderer_vulkan/present/layer.h
index 88d43fc5f..f5effdcd7 100644
--- a/src/video_core/renderer_vulkan/present/layer.h
+++ b/src/video_core/renderer_vulkan/present/layer.h
@@ -11,6 +11,8 @@ namespace Layout {
11struct FramebufferLayout; 11struct FramebufferLayout;
12} 12}
13 13
14struct PresentFilters;
15
14namespace Tegra { 16namespace Tegra {
15struct FramebufferConfig; 17struct FramebufferConfig;
16} 18}
@@ -37,7 +39,8 @@ class Layer final {
37public: 39public:
38 explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, 40 explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
39 Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count, 41 Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count,
40 VkExtent2D output_size, VkDescriptorSetLayout layout); 42 VkExtent2D output_size, VkDescriptorSetLayout layout,
43 const PresentFilters& filters);
41 ~Layer(); 44 ~Layer();
42 45
43 void ConfigureDraw(PresentPushConstants* out_push_constants, 46 void ConfigureDraw(PresentPushConstants* out_push_constants,
@@ -71,6 +74,7 @@ private:
71 MemoryAllocator& memory_allocator; 74 MemoryAllocator& memory_allocator;
72 Scheduler& scheduler; 75 Scheduler& scheduler;
73 Tegra::MaxwellDeviceMemoryManager& device_memory; 76 Tegra::MaxwellDeviceMemoryManager& device_memory;
77 const PresentFilters& filters;
74 const size_t image_count{}; 78 const size_t image_count{};
75 vk::DescriptorPool descriptor_pool{}; 79 vk::DescriptorPool descriptor_pool{};
76 vk::DescriptorSets descriptor_sets{}; 80 vk::DescriptorSets descriptor_sets{};
diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp
index 6ee16595d..7f27c7c1b 100644
--- a/src/video_core/renderer_vulkan/present/util.cpp
+++ b/src/video_core/renderer_vulkan/present/util.cpp
@@ -362,10 +362,10 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
362 }); 362 });
363} 363}
364 364
365vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 365static vk::Pipeline CreateWrappedPipelineImpl(
366 vk::PipelineLayout& layout, 366 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
367 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, 367 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
368 bool enable_blending) { 368 VkPipelineColorBlendAttachmentState blending) {
369 const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ 369 const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{
370 { 370 {
371 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 371 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@@ -443,30 +443,6 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
443 .alphaToOneEnable = VK_FALSE, 443 .alphaToOneEnable = VK_FALSE,
444 }; 444 };
445 445
446 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
447 .blendEnable = VK_FALSE,
448 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
449 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
450 .colorBlendOp = VK_BLEND_OP_ADD,
451 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
452 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
453 .alphaBlendOp = VK_BLEND_OP_ADD,
454 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
455 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
456 };
457
458 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{
459 .blendEnable = VK_TRUE,
460 .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
461 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
462 .colorBlendOp = VK_BLEND_OP_ADD,
463 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
464 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
465 .alphaBlendOp = VK_BLEND_OP_ADD,
466 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
467 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
468 };
469
470 const VkPipelineColorBlendStateCreateInfo color_blend_ci{ 446 const VkPipelineColorBlendStateCreateInfo color_blend_ci{
471 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 447 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
472 .pNext = nullptr, 448 .pNext = nullptr,
@@ -474,8 +450,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
474 .logicOpEnable = VK_FALSE, 450 .logicOpEnable = VK_FALSE,
475 .logicOp = VK_LOGIC_OP_COPY, 451 .logicOp = VK_LOGIC_OP_COPY,
476 .attachmentCount = 1, 452 .attachmentCount = 1,
477 .pAttachments = 453 .pAttachments = &blending,
478 enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled,
479 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, 454 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
480 }; 455 };
481 456
@@ -515,6 +490,63 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
515 }); 490 });
516} 491}
517 492
493vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
494 vk::PipelineLayout& layout,
495 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
496 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
497 .blendEnable = VK_FALSE,
498 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
499 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
500 .colorBlendOp = VK_BLEND_OP_ADD,
501 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
502 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
503 .alphaBlendOp = VK_BLEND_OP_ADD,
504 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
505 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
506 };
507
508 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
509 color_blend_attachment_disabled);
510}
511
512vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
513 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
514 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
515 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_premultiplied{
516 .blendEnable = VK_TRUE,
517 .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
518 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
519 .colorBlendOp = VK_BLEND_OP_ADD,
520 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
521 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
522 .alphaBlendOp = VK_BLEND_OP_ADD,
523 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
524 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
525 };
526
527 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
528 color_blend_attachment_premultiplied);
529}
530
531vk::Pipeline CreateWrappedCoverageBlendingPipeline(
532 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
533 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
534 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_coverage{
535 .blendEnable = VK_TRUE,
536 .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
537 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
538 .colorBlendOp = VK_BLEND_OP_ADD,
539 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
540 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
541 .alphaBlendOp = VK_BLEND_OP_ADD,
542 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
543 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
544 };
545
546 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
547 color_blend_attachment_coverage);
548}
549
518VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, 550VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
519 VkSampler sampler, VkImageView view, 551 VkSampler sampler, VkImageView view,
520 VkDescriptorSet set, u32 binding) { 552 VkDescriptorSet set, u32 binding) {
diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h
index 1104aaa15..5b22f0fa8 100644
--- a/src/video_core/renderer_vulkan/present/util.h
+++ b/src/video_core/renderer_vulkan/present/util.h
@@ -42,8 +42,13 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
42 vk::DescriptorSetLayout& layout); 42 vk::DescriptorSetLayout& layout);
43vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 43vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
44 vk::PipelineLayout& layout, 44 vk::PipelineLayout& layout,
45 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, 45 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
46 bool enable_blending = false); 46vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
47 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
48 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
49vk::Pipeline CreateWrappedCoverageBlendingPipeline(
50 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
51 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
47VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, 52VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
48 VkSampler sampler, VkImageView view, 53 VkSampler sampler, VkImageView view,
49 VkDescriptorSet set, u32 binding); 54 VkDescriptorSet set, u32 binding);
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
index c5db0230d..22ffacf11 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
@@ -22,7 +22,7 @@ WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format,
22 CreatePipelineLayout(); 22 CreatePipelineLayout();
23 CreateVertexShader(); 23 CreateVertexShader();
24 CreateRenderPass(frame_format); 24 CreateRenderPass(frame_format);
25 CreatePipeline(); 25 CreatePipelines();
26} 26}
27 27
28WindowAdaptPass::~WindowAdaptPass() = default; 28WindowAdaptPass::~WindowAdaptPass() = default;
@@ -34,7 +34,6 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
34 34
35 const VkFramebuffer host_framebuffer{*dst->framebuffer}; 35 const VkFramebuffer host_framebuffer{*dst->framebuffer};
36 const VkRenderPass renderpass{*render_pass}; 36 const VkRenderPass renderpass{*render_pass};
37 const VkPipeline graphics_pipeline{*pipeline};
38 const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; 37 const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout};
39 const VkExtent2D render_area{ 38 const VkExtent2D render_area{
40 .width = dst->width, 39 .width = dst->width,
@@ -44,9 +43,23 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
44 const size_t layer_count = configs.size(); 43 const size_t layer_count = configs.size();
45 std::vector<PresentPushConstants> push_constants(layer_count); 44 std::vector<PresentPushConstants> push_constants(layer_count);
46 std::vector<VkDescriptorSet> descriptor_sets(layer_count); 45 std::vector<VkDescriptorSet> descriptor_sets(layer_count);
46 std::vector<VkPipeline> graphics_pipelines(layer_count);
47 47
48 auto layer_it = layers.begin(); 48 auto layer_it = layers.begin();
49 for (size_t i = 0; i < layer_count; i++) { 49 for (size_t i = 0; i < layer_count; i++) {
50 switch (configs[i].blending) {
51 case Tegra::BlendMode::Opaque:
52 default:
53 graphics_pipelines[i] = *opaque_pipeline;
54 break;
55 case Tegra::BlendMode::Premultiplied:
56 graphics_pipelines[i] = *premultiplied_pipeline;
57 break;
58 case Tegra::BlendMode::Coverage:
59 graphics_pipelines[i] = *coverage_pipeline;
60 break;
61 }
62
50 layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler, 63 layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
51 image_index, configs[i], layout); 64 image_index, configs[i], layout);
52 layer_it++; 65 layer_it++;
@@ -77,8 +90,8 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
77 BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); 90 BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area);
78 cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); 91 cmdbuf.ClearAttachments({clear_attachment}, {clear_rect});
79 92
80 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
81 for (size_t i = 0; i < layer_count; i++) { 93 for (size_t i = 0; i < layer_count; i++) {
94 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]);
82 cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 95 cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
83 push_constants[i]); 96 push_constants[i]);
84 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, 97 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0,
@@ -129,9 +142,13 @@ void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) {
129 render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED); 142 render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED);
130} 143}
131 144
132void WindowAdaptPass::CreatePipeline() { 145void WindowAdaptPass::CreatePipelines() {
133 pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout, 146 opaque_pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
134 std::tie(vertex_shader, fragment_shader), false); 147 std::tie(vertex_shader, fragment_shader));
148 premultiplied_pipeline = CreateWrappedPremultipliedBlendingPipeline(
149 device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
150 coverage_pipeline = CreateWrappedCoverageBlendingPipeline(
151 device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
135} 152}
136 153
137} // namespace Vulkan 154} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.h b/src/video_core/renderer_vulkan/present/window_adapt_pass.h
index 0e2edfc31..cf667a4fc 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.h
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h
@@ -42,7 +42,7 @@ private:
42 void CreatePipelineLayout(); 42 void CreatePipelineLayout();
43 void CreateVertexShader(); 43 void CreateVertexShader();
44 void CreateRenderPass(VkFormat frame_format); 44 void CreateRenderPass(VkFormat frame_format);
45 void CreatePipeline(); 45 void CreatePipelines();
46 46
47private: 47private:
48 const Device& device; 48 const Device& device;
@@ -52,7 +52,9 @@ private:
52 vk::ShaderModule vertex_shader; 52 vk::ShaderModule vertex_shader;
53 vk::ShaderModule fragment_shader; 53 vk::ShaderModule fragment_shader;
54 vk::RenderPass render_pass; 54 vk::RenderPass render_pass;
55 vk::Pipeline pipeline; 55 vk::Pipeline opaque_pipeline;
56 vk::Pipeline premultiplied_pipeline;
57 vk::Pipeline coverage_pipeline;
56}; 58};
57 59
58} // namespace Vulkan 60} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 48a105327..c553f5b3d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -19,7 +19,9 @@
19#include "core/core_timing.h" 19#include "core/core_timing.h"
20#include "core/frontend/graphics_context.h" 20#include "core/frontend/graphics_context.h"
21#include "core/telemetry_session.h" 21#include "core/telemetry_session.h"
22#include "video_core/capture.h"
22#include "video_core/gpu.h" 23#include "video_core/gpu.h"
24#include "video_core/present.h"
23#include "video_core/renderer_vulkan/present/util.h" 25#include "video_core/renderer_vulkan/present/util.h"
24#include "video_core/renderer_vulkan/renderer_vulkan.h" 26#include "video_core/renderer_vulkan/renderer_vulkan.h"
25#include "video_core/renderer_vulkan/vk_blit_screen.h" 27#include "video_core/renderer_vulkan/vk_blit_screen.h"
@@ -38,6 +40,20 @@
38 40
39namespace Vulkan { 41namespace Vulkan {
40namespace { 42namespace {
43
44constexpr VkExtent2D CaptureImageSize{
45 .width = VideoCore::Capture::LinearWidth,
46 .height = VideoCore::Capture::LinearHeight,
47};
48
49constexpr VkExtent3D CaptureImageExtent{
50 .width = VideoCore::Capture::LinearWidth,
51 .height = VideoCore::Capture::LinearHeight,
52 .depth = VideoCore::Capture::LinearDepth,
53};
54
55constexpr VkFormat CaptureFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
56
41std::string GetReadableVersion(u32 version) { 57std::string GetReadableVersion(u32 version) {
42 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), 58 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
43 VK_VERSION_PATCH(version)); 59 VK_VERSION_PATCH(version));
@@ -99,10 +115,15 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
99 render_window.GetFramebufferLayout().height), 115 render_window.GetFramebufferLayout().height),
100 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, 116 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
101 surface), 117 surface),
102 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), 118 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
103 blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), 119 PresentFiltersForDisplay),
120 blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
121 PresentFiltersForDisplay),
122 blit_applet(device_memory, device, memory_allocator, present_manager, scheduler,
123 PresentFiltersForAppletCapture),
104 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, 124 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
105 scheduler) { 125 scheduler),
126 applet_frame() {
106 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { 127 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
107 turbo_mode.emplace(instance, dld); 128 turbo_mode.emplace(instance, dld);
108 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); 129 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
@@ -123,7 +144,11 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
123 return; 144 return;
124 } 145 }
125 146
126 SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); 147 SCOPE_EXIT {
148 render_window.OnFrameDisplayed();
149 };
150
151 RenderAppletCaptureLayer(framebuffers);
127 152
128 if (!render_window.IsShown()) { 153 if (!render_window.IsShown()) {
129 return; 154 return;
@@ -167,30 +192,20 @@ void RendererVulkan::Report() const {
167 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); 192 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
168} 193}
169 194
170void Vulkan::RendererVulkan::RenderScreenshot( 195vk::Buffer RendererVulkan::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
171 std::span<const Tegra::FramebufferConfig> framebuffers) { 196 const Layout::FramebufferLayout& layout, VkFormat format,
172 if (!renderer_settings.screenshot_requested) { 197 VkDeviceSize buffer_size) {
173 return;
174 }
175
176 constexpr VkFormat ScreenshotFormat{VK_FORMAT_B8G8R8A8_UNORM};
177 const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
178
179 auto frame = [&]() { 198 auto frame = [&]() {
180 Frame f{}; 199 Frame f{};
181 f.image = CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, 200 f.image =
182 ScreenshotFormat); 201 CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, format);
183 f.image_view = CreateWrappedImageView(device, f.image, ScreenshotFormat); 202 f.image_view = CreateWrappedImageView(device, f.image, format);
184 f.framebuffer = blit_screenshot.CreateFramebuffer(layout, *f.image_view, ScreenshotFormat); 203 f.framebuffer = blit_capture.CreateFramebuffer(layout, *f.image_view, format);
185 return f; 204 return f;
186 }(); 205 }();
187 206
188 blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, 207 auto dst_buffer = CreateWrappedBuffer(memory_allocator, buffer_size, MemoryUsage::Download);
189 VK_FORMAT_B8G8R8A8_UNORM); 208 blit_capture.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, format);
190
191 const auto dst_buffer = CreateWrappedBuffer(
192 memory_allocator, static_cast<VkDeviceSize>(layout.width * layout.height * 4),
193 MemoryUsage::Download);
194 209
195 scheduler.RequestOutsideRenderPassOperationContext(); 210 scheduler.RequestOutsideRenderPassOperationContext();
196 scheduler.Record([&](vk::CommandBuffer cmdbuf) { 211 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -198,15 +213,68 @@ void Vulkan::RendererVulkan::RenderScreenshot(
198 VkExtent3D{layout.width, layout.height, 1}); 213 VkExtent3D{layout.width, layout.height, 1});
199 }); 214 });
200 215
201 // Ensure the copy is fully completed before saving the screenshot 216 // Ensure the copy is fully completed before saving the capture
202 scheduler.Finish(); 217 scheduler.Finish();
203 218
204 // Copy backing image data to the QImage screenshot buffer 219 // Copy backing image data to the capture buffer
205 dst_buffer.Invalidate(); 220 dst_buffer.Invalidate();
221 return dst_buffer;
222}
223
224void RendererVulkan::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
225 if (!renderer_settings.screenshot_requested) {
226 return;
227 }
228
229 const auto& layout{renderer_settings.screenshot_framebuffer_layout};
230 const auto dst_buffer = RenderToBuffer(framebuffers, layout, VK_FORMAT_B8G8R8A8_UNORM,
231 layout.width * layout.height * 4);
232
206 std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), 233 std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
207 dst_buffer.Mapped().size()); 234 dst_buffer.Mapped().size());
208 renderer_settings.screenshot_complete_callback(false); 235 renderer_settings.screenshot_complete_callback(false);
209 renderer_settings.screenshot_requested = false; 236 renderer_settings.screenshot_requested = false;
210} 237}
211 238
239std::vector<u8> RendererVulkan::GetAppletCaptureBuffer() {
240 using namespace VideoCore::Capture;
241
242 std::vector<u8> out(VideoCore::Capture::TiledSize);
243
244 if (!applet_frame.image) {
245 return out;
246 }
247
248 const auto dst_buffer =
249 CreateWrappedBuffer(memory_allocator, VideoCore::Capture::TiledSize, MemoryUsage::Download);
250
251 scheduler.RequestOutsideRenderPassOperationContext();
252 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
253 DownloadColorImage(cmdbuf, *applet_frame.image, *dst_buffer, CaptureImageExtent);
254 });
255
256 // Ensure the copy is fully completed before writing the capture
257 scheduler.Finish();
258
259 // Swizzle image data to the capture buffer
260 dst_buffer.Invalidate();
261 Tegra::Texture::SwizzleTexture(out, dst_buffer.Mapped(), BytesPerPixel, LinearWidth,
262 LinearHeight, LinearDepth, BlockHeight, BlockDepth);
263
264 return out;
265}
266
267void RendererVulkan::RenderAppletCaptureLayer(
268 std::span<const Tegra::FramebufferConfig> framebuffers) {
269 if (!applet_frame.image) {
270 applet_frame.image = CreateWrappedImage(memory_allocator, CaptureImageSize, CaptureFormat);
271 applet_frame.image_view = CreateWrappedImageView(device, applet_frame.image, CaptureFormat);
272 applet_frame.framebuffer = blit_applet.CreateFramebuffer(
273 VideoCore::Capture::Layout, *applet_frame.image_view, CaptureFormat);
274 }
275
276 blit_applet.DrawToFrame(rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1,
277 CaptureFormat);
278}
279
212} // namespace Vulkan 280} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index c6d8a0f21..fb9d83412 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -48,6 +48,8 @@ public:
48 48
49 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override; 49 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override;
50 50
51 std::vector<u8> GetAppletCaptureBuffer() override;
52
51 VideoCore::RasterizerInterface* ReadRasterizer() override { 53 VideoCore::RasterizerInterface* ReadRasterizer() override {
52 return &rasterizer; 54 return &rasterizer;
53 } 55 }
@@ -59,7 +61,11 @@ public:
59private: 61private:
60 void Report() const; 62 void Report() const;
61 63
64 vk::Buffer RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
65 const Layout::FramebufferLayout& layout, VkFormat format,
66 VkDeviceSize buffer_size);
62 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers); 67 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers);
68 void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers);
63 69
64 Core::TelemetrySession& telemetry_session; 70 Core::TelemetrySession& telemetry_session;
65 Tegra::MaxwellDeviceMemoryManager& device_memory; 71 Tegra::MaxwellDeviceMemoryManager& device_memory;
@@ -79,9 +85,12 @@ private:
79 Swapchain swapchain; 85 Swapchain swapchain;
80 PresentManager present_manager; 86 PresentManager present_manager;
81 BlitScreen blit_swapchain; 87 BlitScreen blit_swapchain;
82 BlitScreen blit_screenshot; 88 BlitScreen blit_capture;
89 BlitScreen blit_applet;
83 RasterizerVulkan rasterizer; 90 RasterizerVulkan rasterizer;
84 std::optional<TurboMode> turbo_mode; 91 std::optional<TurboMode> turbo_mode;
92
93 Frame applet_frame;
85}; 94};
86 95
87} // namespace Vulkan 96} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 2275fcc46..b7797f833 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "video_core/framebuffer_config.h" 4#include "video_core/framebuffer_config.h"
5#include "video_core/present.h"
5#include "video_core/renderer_vulkan/present/filters.h" 6#include "video_core/renderer_vulkan/present/filters.h"
6#include "video_core/renderer_vulkan/present/layer.h" 7#include "video_core/renderer_vulkan/present/layer.h"
7#include "video_core/renderer_vulkan/vk_blit_screen.h" 8#include "video_core/renderer_vulkan/vk_blit_screen.h"
@@ -12,9 +13,9 @@ namespace Vulkan {
12 13
13BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, 14BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_,
14 MemoryAllocator& memory_allocator_, PresentManager& present_manager_, 15 MemoryAllocator& memory_allocator_, PresentManager& present_manager_,
15 Scheduler& scheduler_) 16 Scheduler& scheduler_, const PresentFilters& filters_)
16 : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_}, 17 : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_},
17 present_manager{present_manager_}, scheduler{scheduler_}, image_count{1}, 18 present_manager{present_manager_}, scheduler{scheduler_}, filters{filters_}, image_count{1},
18 swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {} 19 swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {}
19 20
20BlitScreen::~BlitScreen() = default; 21BlitScreen::~BlitScreen() = default;
@@ -27,7 +28,7 @@ void BlitScreen::WaitIdle() {
27 28
28void BlitScreen::SetWindowAdaptPass() { 29void BlitScreen::SetWindowAdaptPass() {
29 layers.clear(); 30 layers.clear();
30 scaling_filter = Settings::values.scaling_filter.GetValue(); 31 scaling_filter = filters.get_scaling_filter();
31 32
32 switch (scaling_filter) { 33 switch (scaling_filter) {
33 case Settings::ScalingFilter::NearestNeighbor: 34 case Settings::ScalingFilter::NearestNeighbor:
@@ -59,7 +60,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
59 bool presentation_recreate_required = false; 60 bool presentation_recreate_required = false;
60 61
61 // Recreate dynamic resources if the adapting filter changed 62 // Recreate dynamic resources if the adapting filter changed
62 if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue()) { 63 if (!window_adapt || scaling_filter != filters.get_scaling_filter()) {
63 resource_update_required = true; 64 resource_update_required = true;
64 } 65 }
65 66
@@ -102,7 +103,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
102 103
103 while (layers.size() < framebuffers.size()) { 104 while (layers.size() < framebuffers.size()) {
104 layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count, 105 layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count,
105 window_size, window_adapt->GetDescriptorSetLayout()); 106 window_size, window_adapt->GetDescriptorSetLayout(), filters);
106 } 107 }
107 108
108 // Perform the draw 109 // Perform the draw
@@ -119,8 +120,7 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& l
119 VkFormat current_view_format) { 120 VkFormat current_view_format) {
120 const bool format_updated = 121 const bool format_updated =
121 std::exchange(swapchain_view_format, current_view_format) != current_view_format; 122 std::exchange(swapchain_view_format, current_view_format) != current_view_format;
122 if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || 123 if (!window_adapt || scaling_filter != filters.get_scaling_filter() || format_updated) {
123 format_updated) {
124 WaitIdle(); 124 WaitIdle();
125 SetWindowAdaptPass(); 125 SetWindowAdaptPass();
126 } 126 }
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index cbdf2d5d0..531c57fc5 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -16,6 +16,8 @@ namespace Core {
16class System; 16class System;
17} 17}
18 18
19struct PresentFilters;
20
19namespace Tegra { 21namespace Tegra {
20struct FramebufferConfig; 22struct FramebufferConfig;
21} 23}
@@ -47,7 +49,7 @@ class BlitScreen {
47public: 49public:
48 explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device, 50 explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device,
49 MemoryAllocator& memory_allocator, PresentManager& present_manager, 51 MemoryAllocator& memory_allocator, PresentManager& present_manager,
50 Scheduler& scheduler); 52 Scheduler& scheduler, const PresentFilters& filters);
51 ~BlitScreen(); 53 ~BlitScreen();
52 54
53 void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, 55 void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
@@ -70,6 +72,7 @@ private:
70 MemoryAllocator& memory_allocator; 72 MemoryAllocator& memory_allocator;
71 PresentManager& present_manager; 73 PresentManager& present_manager;
72 Scheduler& scheduler; 74 Scheduler& scheduler;
75 const PresentFilters& filters;
73 std::size_t image_count{}; 76 std::size_t image_count{};
74 std::size_t image_index{}; 77 std::size_t image_index{};
75 VkFormat swapchain_view_format{}; 78 VkFormat swapchain_view_format{};
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index aa0a027bb..74f9f099e 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -196,7 +196,9 @@ template <typename Func>
196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { 196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
197 MICROPROFILE_SCOPE(Vulkan_Drawing); 197 MICROPROFILE_SCOPE(Vulkan_Drawing);
198 198
199 SCOPE_EXIT({ gpu.TickWork(); }); 199 SCOPE_EXIT {
200 gpu.TickWork();
201 };
200 FlushWork(); 202 FlushWork();
201 gpu_memory->FlushCaching(); 203 gpu_memory->FlushCaching();
202 204
@@ -288,7 +290,9 @@ void RasterizerVulkan::DrawIndirect() {
288void RasterizerVulkan::DrawTexture() { 290void RasterizerVulkan::DrawTexture() {
289 MICROPROFILE_SCOPE(Vulkan_Drawing); 291 MICROPROFILE_SCOPE(Vulkan_Drawing);
290 292
291 SCOPE_EXIT({ gpu.TickWork(); }); 293 SCOPE_EXIT {
294 gpu.TickWork();
295 };
292 FlushWork(); 296 FlushWork();
293 297
294 query_cache.NotifySegment(true); 298 query_cache.NotifySegment(true);
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index b72788c6d..9444becce 100644
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -42,6 +42,7 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
42 }; 42 };
43 } 43 }
44 rescaleable = false; 44 rescaleable = false;
45 is_sparse = config.is_sparse != 0;
45 tile_width_spacing = config.tile_width_spacing; 46 tile_width_spacing = config.tile_width_spacing;
46 if (config.texture_type != TextureType::Texture2D && 47 if (config.texture_type != TextureType::Texture2D &&
47 config.texture_type != TextureType::Texture2DNoMipmap) { 48 config.texture_type != TextureType::Texture2DNoMipmap) {
diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h
index 8a4cb0cbd..eb490a642 100644
--- a/src/video_core/texture_cache/image_info.h
+++ b/src/video_core/texture_cache/image_info.h
@@ -41,6 +41,7 @@ struct ImageInfo {
41 bool downscaleable = false; 41 bool downscaleable = false;
42 bool forced_flushed = false; 42 bool forced_flushed = false;
43 bool dma_downloaded = false; 43 bool dma_downloaded = false;
44 bool is_sparse = false;
44}; 45};
45 46
46} // namespace VideoCommon 47} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index ca0794214..53b4876f2 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -600,17 +600,17 @@ void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz
600 [&](ImageId id, Image&) { deleted_images.push_back(id); }); 600 [&](ImageId id, Image&) { deleted_images.push_back(id); });
601 for (const ImageId id : deleted_images) { 601 for (const ImageId id : deleted_images) {
602 Image& image = slot_images[id]; 602 Image& image = slot_images[id];
603 if (True(image.flags & ImageFlagBits::CpuModified)) { 603 if (False(image.flags & ImageFlagBits::CpuModified)) {
604 continue; 604 image.flags |= ImageFlagBits::CpuModified;
605 if (True(image.flags & ImageFlagBits::Tracked)) {
606 UntrackImage(image, id);
607 }
605 } 608 }
606 image.flags |= ImageFlagBits::CpuModified; 609
607 if (True(image.flags & ImageFlagBits::Remapped)) { 610 if (True(image.flags & ImageFlagBits::Remapped)) {
608 continue; 611 continue;
609 } 612 }
610 image.flags |= ImageFlagBits::Remapped; 613 image.flags |= ImageFlagBits::Remapped;
611 if (True(image.flags & ImageFlagBits::Tracked)) {
612 UntrackImage(image, id);
613 }
614 } 614 }
615} 615}
616 616
@@ -746,7 +746,13 @@ std::pair<typename P::ImageView*, bool> TextureCache<P>::TryFindFramebufferImage
746 }(); 746 }();
747 747
748 const auto GetImageViewForFramebuffer = [&](ImageId image_id) { 748 const auto GetImageViewForFramebuffer = [&](ImageId image_id) {
749 const ImageViewInfo info{ImageViewType::e2D, view_format}; 749 ImageViewInfo info{ImageViewType::e2D, view_format};
750 if (config.blending == Tegra::BlendMode::Opaque) {
751 info.x_source = static_cast<u8>(SwizzleSource::R);
752 info.y_source = static_cast<u8>(SwizzleSource::G);
753 info.z_source = static_cast<u8>(SwizzleSource::B);
754 info.w_source = static_cast<u8>(SwizzleSource::OneFloat);
755 }
750 return std::make_pair(&slot_image_views[FindOrEmplaceImageView(image_id, info)], 756 return std::make_pair(&slot_image_views[FindOrEmplaceImageView(image_id, info)],
751 slot_images[image_id].IsRescaled()); 757 slot_images[image_id].IsRescaled());
752 }; 758 };
@@ -1463,7 +1469,8 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
1463 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr); 1469 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr);
1464 Image& new_image = slot_images[new_image_id]; 1470 Image& new_image = slot_images[new_image_id];
1465 1471
1466 if (!gpu_memory->IsContinuousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { 1472 if (!gpu_memory->IsContinuousRange(new_image.gpu_addr, new_image.guest_size_bytes) &&
1473 new_info.is_sparse) {
1467 new_image.flags |= ImageFlagBits::Sparse; 1474 new_image.flags |= ImageFlagBits::Sparse;
1468 } 1475 }
1469 1476
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
index 5fa0d9620..f41c3e506 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
@@ -116,7 +116,9 @@ void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
116 LOG_ERROR(Render_Vulkan, "Failed to create decoder"); 116 LOG_ERROR(Render_Vulkan, "Failed to create decoder");
117 return; 117 return;
118 } 118 }
119 SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); 119 SCOPE_EXIT {
120 GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder);
121 };
120 122
121 u32 json_size = 0; 123 u32 json_size = 0;
122 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( 124 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(