summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/am/am_types.h6
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.cpp12
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.h2
-rw-r--r--src/core/hle/service/am/library_applet_creator.cpp6
-rw-r--r--src/core/hle/service/am/self_controller.cpp3
-rw-r--r--src/core/hle/service/am/system_buffer_manager.cpp10
-rw-r--r--src/core/hle/service/am/system_buffer_manager.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp17
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp154
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.h24
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp1
-rw-r--r--src/core/hle/service/nvnflinger/hwc_layer.h13
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp7
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h6
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp6
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h13
-rw-r--r--src/video_core/framebuffer_config.h7
-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/renderer_opengl/present/window_adapt_pass.cpp15
-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.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h3
-rw-r--r--src/video_core/texture_cache/texture_cache.h8
37 files changed, 383 insertions, 141 deletions
diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h
index a2b852b12..8c33feb15 100644
--- a/src/core/hle/service/am/am_types.h
+++ b/src/core/hle/service/am/am_types.h
@@ -130,9 +130,9 @@ enum class AppletProgramId : u64 {
130 130
131enum class LibraryAppletMode : u32 { 131enum class LibraryAppletMode : u32 {
132 AllForeground = 0, 132 AllForeground = 0,
133 Background = 1, 133 PartialForeground = 1,
134 NoUI = 2, 134 NoUi = 2,
135 BackgroundIndirectDisplay = 3, 135 PartialForegroundIndirectDisplay = 3,
136 AllForegroundInitiallyHidden = 4, 136 AllForegroundInitiallyHidden = 4,
137}; 137};
138 138
diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp
index fbf75d379..034c62f32 100644
--- a/src/core/hle/service/am/frontend/applet_software_keyboard.cpp
+++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp
@@ -68,9 +68,9 @@ void SoftwareKeyboard::Initialize() {
68 case LibraryAppletMode::AllForeground: 68 case LibraryAppletMode::AllForeground:
69 InitializeForeground(); 69 InitializeForeground();
70 break; 70 break;
71 case LibraryAppletMode::Background: 71 case LibraryAppletMode::PartialForeground:
72 case LibraryAppletMode::BackgroundIndirectDisplay: 72 case LibraryAppletMode::PartialForegroundIndirectDisplay:
73 InitializeBackground(applet_mode); 73 InitializePartialForeground(applet_mode);
74 break; 74 break;
75 default: 75 default:
76 ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode); 76 ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
@@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
243 InitializeFrontendNormalKeyboard(); 243 InitializeFrontendNormalKeyboard();
244} 244}
245 245
246void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) { 246void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_applet_mode) {
247 LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); 247 LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
248 248
249 is_background = true; 249 is_background = true;
@@ -258,9 +258,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
258 swkbd_inline_initialize_arg.size()); 258 swkbd_inline_initialize_arg.size());
259 259
260 if (swkbd_initialize_arg.library_applet_mode_flag) { 260 if (swkbd_initialize_arg.library_applet_mode_flag) {
261 ASSERT(library_applet_mode == LibraryAppletMode::Background); 261 ASSERT(library_applet_mode == LibraryAppletMode::PartialForeground);
262 } else { 262 } else {
263 ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay); 263 ASSERT(library_applet_mode == LibraryAppletMode::PartialForegroundIndirectDisplay);
264 } 264 }
265} 265}
266 266
diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h
index f464b7e15..2a7d01b96 100644
--- a/src/core/hle/service/am/frontend/applet_software_keyboard.h
+++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h
@@ -62,7 +62,7 @@ private:
62 void InitializeForeground(); 62 void InitializeForeground();
63 63
64 /// Initializes the inline software keyboard. 64 /// Initializes the inline software keyboard.
65 void InitializeBackground(LibraryAppletMode library_applet_mode); 65 void InitializePartialForeground(LibraryAppletMode library_applet_mode);
66 66
67 /// Processes the text check sent by the application. 67 /// Processes the text check sent by the application.
68 void ProcessTextCheck(); 68 void ProcessTextCheck();
diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp
index 47bab7528..ee646bea5 100644
--- a/src/core/hle/service/am/library_applet_creator.cpp
+++ b/src/core/hle/service/am/library_applet_creator.cpp
@@ -87,7 +87,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
87 // Set focus state 87 // Set focus state
88 switch (mode) { 88 switch (mode) {
89 case LibraryAppletMode::AllForeground: 89 case LibraryAppletMode::AllForeground:
90 case LibraryAppletMode::NoUI: 90 case LibraryAppletMode::NoUi:
91 applet->focus_state = FocusState::InFocus; 91 applet->focus_state = FocusState::InFocus;
92 applet->hid_registration.EnableAppletToGetInput(true); 92 applet->hid_registration.EnableAppletToGetInput(true);
93 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); 93 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
@@ -99,8 +99,8 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
99 applet->hid_registration.EnableAppletToGetInput(false); 99 applet->hid_registration.EnableAppletToGetInput(false);
100 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); 100 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
101 break; 101 break;
102 case LibraryAppletMode::Background: 102 case LibraryAppletMode::PartialForeground:
103 case LibraryAppletMode::BackgroundIndirectDisplay: 103 case LibraryAppletMode::PartialForegroundIndirectDisplay:
104 default: 104 default:
105 applet->focus_state = FocusState::Background; 105 applet->focus_state = FocusState::Background;
106 applet->hid_registration.EnableAppletToGetInput(true); 106 applet->hid_registration.EnableAppletToGetInput(true);
diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp
index 0289f5cf1..b92663b2b 100644
--- a/src/core/hle/service/am/self_controller.cpp
+++ b/src/core/hle/service/am/self_controller.cpp
@@ -288,7 +288,8 @@ void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
288} 288}
289 289
290Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { 290Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
291 if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) { 291 if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id,
292 applet->library_applet_mode)) {
292 return ResultSuccess; 293 return ResultSuccess;
293 } 294 }
294 295
diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp
index 60a9afc9d..3cccc5388 100644
--- a/src/core/hle/service/am/system_buffer_manager.cpp
+++ b/src/core/hle/service/am/system_buffer_manager.cpp
@@ -17,11 +17,12 @@ SystemBufferManager::~SystemBufferManager() {
17 17
18 // Clean up shared layers. 18 // Clean up shared layers.
19 if (m_buffer_sharing_enabled) { 19 if (m_buffer_sharing_enabled) {
20 m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
20 } 21 }
21} 22}
22 23
23bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, 24bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
24 AppletId applet_id) { 25 AppletId applet_id, LibraryAppletMode mode) {
25 if (m_nvnflinger) { 26 if (m_nvnflinger) {
26 return m_buffer_sharing_enabled; 27 return m_buffer_sharing_enabled;
27 } 28 }
@@ -36,9 +37,14 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
36 return false; 37 return false;
37 } 38 }
38 39
40 Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
41 if (mode == LibraryAppletMode::PartialForeground) {
42 blending = Nvnflinger::LayerBlending::Coverage;
43 }
44
39 const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); 45 const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
40 const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( 46 const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
41 &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id); 47 m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
42 48
43 if (res.IsSuccess()) { 49 if (res.IsSuccess()) {
44 m_buffer_sharing_enabled = true; 50 m_buffer_sharing_enabled = true;
diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h
index 98c3cf055..0690f68b6 100644
--- a/src/core/hle/service/am/system_buffer_manager.h
+++ b/src/core/hle/service/am/system_buffer_manager.h
@@ -27,7 +27,8 @@ public:
27 SystemBufferManager(); 27 SystemBufferManager();
28 ~SystemBufferManager(); 28 ~SystemBufferManager();
29 29
30 bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id); 30 bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
31 LibraryAppletMode mode);
31 32
32 void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, 33 void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
33 u64* out_system_shared_layer_id) { 34 u64* out_system_shared_layer_id) {
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index abe95303e..995646e25 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -15,6 +15,22 @@
15 15
16namespace Service::Nvidia::Devices { 16namespace Service::Nvidia::Devices {
17 17
18namespace {
19
20Tegra::BlendMode ConvertBlending(Service::Nvnflinger::LayerBlending blending) {
21 switch (blending) {
22 case Service::Nvnflinger::LayerBlending::None:
23 default:
24 return Tegra::BlendMode::Opaque;
25 case Service::Nvnflinger::LayerBlending::Premultiplied:
26 return Tegra::BlendMode::Premultiplied;
27 case Service::Nvnflinger::LayerBlending::Coverage:
28 return Tegra::BlendMode::Coverage;
29 }
30}
31
32} // namespace
33
18nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) 34nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
19 : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} 35 : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
20nvdisp_disp0::~nvdisp_disp0() = default; 36nvdisp_disp0::~nvdisp_disp0() = default;
@@ -56,6 +72,7 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
56 .pixel_format = layer.format, 72 .pixel_format = layer.format,
57 .transform_flags = layer.transform, 73 .transform_flags = layer.transform,
58 .crop_rect = layer.crop_rect, 74 .crop_rect = layer.crop_rect,
75 .blending = ConvertBlending(layer.blending),
59 }); 76 });
60 77
61 for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) { 78 for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index e71652cdf..6a7da0cae 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -14,24 +14,19 @@
14#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 14#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
15#include "core/hle/service/vi/layer/vi_layer.h" 15#include "core/hle/service/vi/layer/vi_layer.h"
16#include "core/hle/service/vi/vi_results.h" 16#include "core/hle/service/vi/vi_results.h"
17#include "video_core/gpu.h"
17 18
18namespace Service::Nvnflinger { 19namespace Service::Nvnflinger {
19 20
20namespace { 21namespace {
21 22
22Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address, 23Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
23 std::unique_ptr<Kernel::KPageGroup>* out_page_group, 24 Core::System& system, u32 size) {
24 Core::System& system, u32 size) {
25 using Core::Memory::YUZU_PAGESIZE; 25 using Core::Memory::YUZU_PAGESIZE;
26 26
27 // Allocate memory for the system shared buffer. 27 // Allocate memory for the system shared buffer.
28 // FIXME: Because the gmmu can only point to cpu addresses, we need
29 // to map this in the application space to allow it to be used.
30 // FIXME: Add proper smmu emulation.
31 // FIXME: This memory belongs to vi's .data section. 28 // FIXME: This memory belongs to vi's .data section.
32 auto& kernel = system.Kernel(); 29 auto& kernel = system.Kernel();
33 auto* process = system.ApplicationProcess();
34 auto& page_table = process->GetPageTable();
35 30
36 // Hold a temporary page group reference while we try to map it. 31 // Hold a temporary page group reference while we try to map it.
37 auto pg = std::make_unique<Kernel::KPageGroup>( 32 auto pg = std::make_unique<Kernel::KPageGroup>(
@@ -43,6 +38,30 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
43 Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure, 38 Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
44 Kernel::KMemoryManager::Direction::FromBack))); 39 Kernel::KMemoryManager::Direction::FromBack)));
45 40
41 // Fill the output data with red.
42 for (auto& block : *pg) {
43 u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
44 u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
45
46 for (; start < end; start++) {
47 *start = 0xFF0000FF;
48 }
49 }
50
51 // Return the mapped page group.
52 *out_page_group = std::move(pg);
53
54 // We succeeded.
55 R_SUCCEED();
56}
57
58Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
59 std::unique_ptr<Kernel::KPageGroup>& pg,
60 Kernel::KProcess* process, Core::System& system) {
61 using Core::Memory::YUZU_PAGESIZE;
62
63 auto& page_table = process->GetPageTable();
64
46 // Get bounds of where mapping is possible. 65 // Get bounds of where mapping is possible.
47 const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart()); 66 const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
48 const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE; 67 const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
@@ -64,9 +83,6 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
64 // Return failure, if necessary 83 // Return failure, if necessary
65 R_UNLESS(i < 64, res); 84 R_UNLESS(i < 64, res);
66 85
67 // Return the mapped page group.
68 *out_page_group = std::move(pg);
69
70 // We succeeded. 86 // We succeeded.
71 R_SUCCEED(); 87 R_SUCCEED();
72} 88}
@@ -135,6 +151,13 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
135 R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); 151 R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
136} 152}
137 153
154void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
155 auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
156 ASSERT(nvmap != nullptr);
157
158 R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
159}
160
138constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; 161constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
139constexpr u32 SharedBufferBlockLinearBpp = 4; 162constexpr u32 SharedBufferBlockLinearBpp = 4;
140 163
@@ -186,53 +209,97 @@ FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& fli
186 209
187FbShareBufferManager::~FbShareBufferManager() = default; 210FbShareBufferManager::~FbShareBufferManager() = default;
188 211
189Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) { 212Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
213 u64* out_layer_handle, u64 display_id,
214 LayerBlending blending) {
190 std::scoped_lock lk{m_guard}; 215 std::scoped_lock lk{m_guard};
191 216
192 // Ensure we have not already created a buffer. 217 // Ensure we haven't already created.
193 R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed); 218 const u64 aruid = owner_process->GetProcessId();
219 R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
220
221 // Allocate memory for the shared buffer if needed.
222 if (!m_buffer_page_group) {
223 R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
224 SharedBufferSize));
194 225
195 // Allocate memory and space for the shared buffer. 226 // Record buffer id.
196 Common::ProcessAddress map_address; 227 m_buffer_id = m_next_buffer_id++;
197 R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address), 228
198 std::addressof(m_buffer_page_group), m_system, 229 // Record display id.
199 SharedBufferSize)); 230 m_display_id = display_id;
231 }
232
233 // Map into process.
234 Common::ProcessAddress map_address{};
235 R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
236 owner_process, m_system));
237
238 // Create new session.
239 auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{});
240 auto& session = it->second;
200 241
201 auto& container = m_nvdrv->GetContainer(); 242 auto& container = m_nvdrv->GetContainer();
202 m_session_id = container.OpenSession(m_system.ApplicationProcess()); 243 session.session_id = container.OpenSession(owner_process);
203 m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id); 244 session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
204 245
205 // Create an nvmap handle for the buffer and assign the memory to it. 246 // Create an nvmap handle for the buffer and assign the memory to it.
206 R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, 247 R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
207 map_address, SharedBufferSize)); 248 session.nvmap_fd, map_address, SharedBufferSize));
208
209 // Record the display id.
210 m_display_id = display_id;
211 249
212 // Create and open a layer for the display. 250 // Create and open a layer for the display.
213 m_layer_id = m_flinger.CreateLayer(m_display_id).value(); 251 session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value();
214 m_flinger.OpenLayer(m_layer_id); 252 m_flinger.OpenLayer(session.layer_id);
215
216 // Set up the buffer.
217 m_buffer_id = m_next_buffer_id++;
218 253
219 // Get the layer. 254 // Get the layer.
220 VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id); 255 VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id);
221 ASSERT(layer != nullptr); 256 ASSERT(layer != nullptr);
222 257
223 // Get the producer and set preallocated buffers. 258 // Get the producer and set preallocated buffers.
224 auto& producer = layer->GetBufferQueue(); 259 auto& producer = layer->GetBufferQueue();
225 MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle); 260 MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
226 MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle); 261 MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
227 262
228 // Assign outputs. 263 // Assign outputs.
229 *out_buffer_id = m_buffer_id; 264 *out_buffer_id = m_buffer_id;
230 *out_layer_id = m_layer_id; 265 *out_layer_handle = session.layer_id;
231 266
232 // We succeeded. 267 // We succeeded.
233 R_SUCCEED(); 268 R_SUCCEED();
234} 269}
235 270
271void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
272 std::scoped_lock lk{m_guard};
273
274 if (m_buffer_id == 0) {
275 return;
276 }
277
278 const u64 aruid = owner_process->GetProcessId();
279 const auto it = m_sessions.find(aruid);
280 if (it == m_sessions.end()) {
281 return;
282 }
283
284 auto& session = it->second;
285
286 // Destroy the layer.
287 m_flinger.DestroyLayer(session.layer_id);
288
289 // Close nvmap handle.
290 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
291
292 // Close nvmap device.
293 m_nvdrv->Close(session.nvmap_fd);
294
295 // Close session.
296 auto& container = m_nvdrv->GetContainer();
297 container.CloseSession(session.session_id);
298
299 // Erase.
300 m_sessions.erase(it);
301}
302
236Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, 303Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
237 s32* out_nvmap_handle, 304 s32* out_nvmap_handle,
238 SharedMemoryPoolLayout* out_pool_layout, 305 SharedMemoryPoolLayout* out_pool_layout,
@@ -242,17 +309,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
242 309
243 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); 310 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
244 R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound); 311 R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
312 R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
245 313
246 *out_pool_layout = SharedBufferPoolLayout; 314 *out_pool_layout = SharedBufferPoolLayout;
247 *out_buffer_size = SharedBufferSize; 315 *out_buffer_size = SharedBufferSize;
248 *out_nvmap_handle = m_buffer_nvmap_handle; 316 *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
249 317
250 R_SUCCEED(); 318 R_SUCCEED();
251} 319}
252 320
253Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { 321Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
254 // Ensure the layer id is valid. 322 // Ensure the layer id is valid.
255 R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound); 323 R_UNLESS(layer_id > 0, VI::ResultNotFound);
256 324
257 // Get the layer. 325 // Get the layer.
258 VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id); 326 VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
@@ -309,6 +377,10 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
309 android::Status::NoError, 377 android::Status::NoError,
310 VI::ResultOperationFailed); 378 VI::ResultOperationFailed);
311 379
380 ON_RESULT_FAILURE {
381 producer.CancelBuffer(static_cast<s32>(slot), fence);
382 };
383
312 // Queue the buffer to the producer. 384 // Queue the buffer to the producer.
313 android::QueueBufferInput input{}; 385 android::QueueBufferInput input{};
314 android::QueueBufferOutput output{}; 386 android::QueueBufferOutput output{};
@@ -342,4 +414,12 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab
342 R_SUCCEED(); 414 R_SUCCEED();
343} 415}
344 416
417Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
418 s32* out_layer_index) {
419 // TODO
420 *out_was_written = true;
421 *out_layer_index = 1;
422 R_SUCCEED();
423}
424
345} // namespace Service::Nvnflinger 425} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
index 033bf4bbe..b79a7d23a 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
@@ -3,9 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <map>
7
6#include "common/math_util.h" 8#include "common/math_util.h"
7#include "core/hle/service/nvdrv/core/container.h" 9#include "core/hle/service/nvdrv/core/container.h"
8#include "core/hle/service/nvdrv/nvdata.h" 10#include "core/hle/service/nvdrv/nvdata.h"
11#include "core/hle/service/nvnflinger/hwc_layer.h"
9#include "core/hle/service/nvnflinger/nvnflinger.h" 12#include "core/hle/service/nvnflinger/nvnflinger.h"
10#include "core/hle/service/nvnflinger/ui/fence.h" 13#include "core/hle/service/nvnflinger/ui/fence.h"
11 14
@@ -29,13 +32,18 @@ struct SharedMemoryPoolLayout {
29}; 32};
30static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); 33static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
31 34
35struct FbShareSession;
36
32class FbShareBufferManager final { 37class FbShareBufferManager final {
33public: 38public:
34 explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger, 39 explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
35 std::shared_ptr<Nvidia::Module> nvdrv); 40 std::shared_ptr<Nvidia::Module> nvdrv);
36 ~FbShareBufferManager(); 41 ~FbShareBufferManager();
37 42
38 Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id); 43 Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
44 u64 display_id, LayerBlending blending);
45 void Finalize(Kernel::KProcess* owner_process);
46
39 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, 47 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
40 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, 48 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
41 u64 applet_resource_user_id); 49 u64 applet_resource_user_id);
@@ -45,6 +53,8 @@ public:
45 u32 transform, s32 swap_interval, u64 layer_id, s64 slot); 53 u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
46 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); 54 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
47 55
56 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
57
48private: 58private:
49 Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); 59 Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
50 60
@@ -52,11 +62,8 @@ private:
52 u64 m_next_buffer_id = 1; 62 u64 m_next_buffer_id = 1;
53 u64 m_display_id = 0; 63 u64 m_display_id = 0;
54 u64 m_buffer_id = 0; 64 u64 m_buffer_id = 0;
55 u64 m_layer_id = 0;
56 u32 m_buffer_nvmap_handle = 0;
57 SharedMemoryPoolLayout m_pool_layout = {}; 65 SharedMemoryPoolLayout m_pool_layout = {};
58 Nvidia::DeviceFD m_nvmap_fd = {}; 66 std::map<u64, FbShareSession> m_sessions;
59 Nvidia::NvCore::SessionId m_session_id = {};
60 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; 67 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
61 68
62 std::mutex m_guard; 69 std::mutex m_guard;
@@ -65,4 +72,11 @@ private:
65 std::shared_ptr<Nvidia::Module> m_nvdrv; 72 std::shared_ptr<Nvidia::Module> m_nvdrv;
66}; 73};
67 74
75struct FbShareSession {
76 Nvidia::DeviceFD nvmap_fd = {};
77 Nvidia::NvCore::SessionId session_id = {};
78 u64 layer_id = {};
79 u32 buffer_nvmap_handle = 0;
80};
81
68} // namespace Service::Nvnflinger 82} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index ba2b5c28c..be7eb97a3 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -86,6 +86,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
86 .height = igbp_buffer.Height(), 86 .height = igbp_buffer.Height(),
87 .stride = igbp_buffer.Stride(), 87 .stride = igbp_buffer.Stride(),
88 .z_index = 0, 88 .z_index = 0,
89 .blending = layer.GetBlending(),
89 .transform = static_cast<android::BufferTransformFlags>(item.transform), 90 .transform = static_cast<android::BufferTransformFlags>(item.transform),
90 .crop_rect = item.crop, 91 .crop_rect = item.crop,
91 .acquire_fence = item.fence, 92 .acquire_fence = item.fence,
diff --git a/src/core/hle/service/nvnflinger/hwc_layer.h b/src/core/hle/service/nvnflinger/hwc_layer.h
index 3af668a25..f71a5d822 100644
--- a/src/core/hle/service/nvnflinger/hwc_layer.h
+++ b/src/core/hle/service/nvnflinger/hwc_layer.h
@@ -11,6 +11,18 @@
11 11
12namespace Service::Nvnflinger { 12namespace Service::Nvnflinger {
13 13
14// hwc_layer_t::blending values
15enum class LayerBlending : u32 {
16 // No blending
17 None = 0x100,
18
19 // ONE / ONE_MINUS_SRC_ALPHA
20 Premultiplied = 0x105,
21
22 // SRC_ALPHA / ONE_MINUS_SRC_ALPHA
23 Coverage = 0x405,
24};
25
14struct HwcLayer { 26struct HwcLayer {
15 u32 buffer_handle; 27 u32 buffer_handle;
16 u32 offset; 28 u32 offset;
@@ -19,6 +31,7 @@ struct HwcLayer {
19 u32 height; 31 u32 height;
20 u32 stride; 32 u32 stride;
21 s32 z_index; 33 s32 z_index;
34 LayerBlending blending;
22 android::BufferTransformFlags transform; 35 android::BufferTransformFlags transform;
23 Common::Rectangle<int> crop_rect; 36 Common::Rectangle<int> crop_rect;
24 android::Fence acquire_fence; 37 android::Fence acquire_fence;
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index d8ba89d43..687ccc9f9 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -157,7 +157,7 @@ bool Nvnflinger::CloseDisplay(u64 display_id) {
157 return true; 157 return true;
158} 158}
159 159
160std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) { 160std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
161 const auto lock_guard = Lock(); 161 const auto lock_guard = Lock();
162 auto* const display = FindDisplay(display_id); 162 auto* const display = FindDisplay(display_id);
163 163
@@ -166,13 +166,14 @@ std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
166 } 166 }
167 167
168 const u64 layer_id = next_layer_id++; 168 const u64 layer_id = next_layer_id++;
169 CreateLayerAtId(*display, layer_id); 169 CreateLayerAtId(*display, layer_id, blending);
170 return layer_id; 170 return layer_id;
171} 171}
172 172
173void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { 173void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
174 const auto buffer_id = next_buffer_queue_id++; 174 const auto buffer_id = next_buffer_queue_id++;
175 display.CreateLayer(layer_id, buffer_id, nvdrv->container); 175 display.CreateLayer(layer_id, buffer_id, nvdrv->container);
176 display.FindLayer(layer_id)->SetBlending(blending);
176} 177}
177 178
178bool Nvnflinger::OpenLayer(u64 layer_id) { 179bool Nvnflinger::OpenLayer(u64 layer_id) {
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index c984d55a0..4cf4f069d 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -15,6 +15,7 @@
15#include "common/thread.h" 15#include "common/thread.h"
16#include "core/hle/result.h" 16#include "core/hle/result.h"
17#include "core/hle/service/kernel_helpers.h" 17#include "core/hle/service/kernel_helpers.h"
18#include "core/hle/service/nvnflinger/hwc_layer.h"
18 19
19namespace Common { 20namespace Common {
20class Event; 21class Event;
@@ -72,7 +73,8 @@ public:
72 /// Creates a layer on the specified display and returns the layer ID. 73 /// Creates a layer on the specified display and returns the layer ID.
73 /// 74 ///
74 /// If an invalid display ID is specified, then an empty optional is returned. 75 /// If an invalid display ID is specified, then an empty optional is returned.
75 [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id); 76 [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
77 LayerBlending blending = LayerBlending::None);
76 78
77 /// Opens a layer on all displays for the given layer ID. 79 /// Opens a layer on all displays for the given layer ID.
78 bool OpenLayer(u64 layer_id); 80 bool OpenLayer(u64 layer_id);
@@ -128,7 +130,7 @@ private:
128 [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); 130 [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
129 131
130 /// Creates a layer with the specified layer ID in the desired display. 132 /// Creates a layer with the specified layer ID in the desired display.
131 void CreateLayerAtId(VI::Display& display, u64 layer_id); 133 void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
132 134
133 void SplitVSync(std::stop_token stop_token); 135 void SplitVSync(std::stop_token stop_token);
134 136
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 493bd6e9e..eca35d82a 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2019 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 "core/hle/service/nvnflinger/hwc_layer.h"
4#include "core/hle/service/vi/layer/vi_layer.h" 5#include "core/hle/service/vi/layer/vi_layer.h"
5 6
6namespace Service::VI { 7namespace Service::VI {
@@ -8,8 +9,9 @@ namespace Service::VI {
8Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, 9Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
9 android::BufferQueueProducer& binder_, 10 android::BufferQueueProducer& binder_,
10 std::shared_ptr<android::BufferItemConsumer>&& consumer_) 11 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
11 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, 12 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
12 consumer{std::move(consumer_)}, open{false}, visible{true} {} 13 consumer_)},
14 blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
13 15
14Layer::~Layer() = default; 16Layer::~Layer() = default;
15 17
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index b4b031ee7..14e229903 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -14,6 +14,10 @@ class BufferQueueCore;
14class BufferQueueProducer; 14class BufferQueueProducer;
15} // namespace Service::android 15} // namespace Service::android
16 16
17namespace Service::Nvnflinger {
18enum class LayerBlending : u32;
19}
20
17namespace Service::VI { 21namespace Service::VI {
18 22
19/// Represents a single display layer. 23/// Represents a single display layer.
@@ -92,12 +96,21 @@ public:
92 return !std::exchange(open, true); 96 return !std::exchange(open, true);
93 } 97 }
94 98
99 Nvnflinger::LayerBlending GetBlending() {
100 return blending;
101 }
102
103 void SetBlending(Nvnflinger::LayerBlending b) {
104 blending = b;
105 }
106
95private: 107private:
96 const u64 layer_id; 108 const u64 layer_id;
97 const u32 binder_id; 109 const u32 binder_id;
98 android::BufferQueueCore& core; 110 android::BufferQueueCore& core;
99 android::BufferQueueProducer& binder; 111 android::BufferQueueProducer& binder;
100 std::shared_ptr<android::BufferItemConsumer> consumer; 112 std::shared_ptr<android::BufferItemConsumer> consumer;
113 Service::Nvnflinger::LayerBlending blending;
101 bool open; 114 bool open;
102 bool visible; 115 bool visible;
103}; 116};
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/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/renderer_opengl/present/window_adapt_pass.cpp b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
index 4d681606b..0328abd70 100644
--- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp
@@ -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_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..c7c234fd8 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -101,8 +101,10 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
101 surface), 101 surface),
102 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), 102 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler),
103 blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), 103 blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler),
104 blit_application_layer(device_memory, device, memory_allocator, present_manager, scheduler),
104 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, 105 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
105 scheduler) { 106 scheduler),
107 application_frame() {
106 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { 108 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
107 turbo_mode.emplace(instance, dld); 109 turbo_mode.emplace(instance, dld);
108 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); 110 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index c6d8a0f21..ed9c7af7f 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -80,8 +80,11 @@ private:
80 PresentManager present_manager; 80 PresentManager present_manager;
81 BlitScreen blit_swapchain; 81 BlitScreen blit_swapchain;
82 BlitScreen blit_screenshot; 82 BlitScreen blit_screenshot;
83 BlitScreen blit_application_layer;
83 RasterizerVulkan rasterizer; 84 RasterizerVulkan rasterizer;
84 std::optional<TurboMode> turbo_mode; 85 std::optional<TurboMode> turbo_mode;
86
87 Frame application_frame;
85}; 88};
86 89
87} // namespace Vulkan 90} // namespace Vulkan
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index a20c956ff..3a1cc060e 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -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 };