summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam <byteslice@airmail.cc>2024-01-22 18:40:50 +0100
committerLiam <byteslice@airmail.cc>2024-02-09 15:20:53 +0100
commit962c82540c304f909957776908aabcd261f2a7ba (patch)
tree707ab34565e8309b5ede21acebf36975da7718e7
parentnvservices: unmap only on last container free (diff)
downloadyuzu-962c82540c304f909957776908aabcd261f2a7ba.tar
yuzu-962c82540c304f909957776908aabcd261f2a7ba.tar.gz
yuzu-962c82540c304f909957776908aabcd261f2a7ba.tar.bz2
yuzu-962c82540c304f909957776908aabcd261f2a7ba.tar.lz
yuzu-962c82540c304f909957776908aabcd261f2a7ba.tar.xz
yuzu-962c82540c304f909957776908aabcd261f2a7ba.tar.zst
yuzu-962c82540c304f909957776908aabcd261f2a7ba.zip
-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 {
enum class LibraryAppletMode : u32 {
AllForeground = 0,
- Background = 1,
- NoUI = 2,
- BackgroundIndirectDisplay = 3,
+ PartialForeground = 1,
+ NoUi = 2,
+ PartialForegroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4,
};
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() {
case LibraryAppletMode::AllForeground:
InitializeForeground();
break;
- case LibraryAppletMode::Background:
- case LibraryAppletMode::BackgroundIndirectDisplay:
- InitializeBackground(applet_mode);
+ case LibraryAppletMode::PartialForeground:
+ case LibraryAppletMode::PartialForegroundIndirectDisplay:
+ InitializePartialForeground(applet_mode);
break;
default:
ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
@@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
InitializeFrontendNormalKeyboard();
}
-void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
+void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_applet_mode) {
LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
is_background = true;
@@ -258,9 +258,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
swkbd_inline_initialize_arg.size());
if (swkbd_initialize_arg.library_applet_mode_flag) {
- ASSERT(library_applet_mode == LibraryAppletMode::Background);
+ ASSERT(library_applet_mode == LibraryAppletMode::PartialForeground);
} else {
- ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
+ ASSERT(library_applet_mode == LibraryAppletMode::PartialForegroundIndirectDisplay);
}
}
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:
void InitializeForeground();
/// Initializes the inline software keyboard.
- void InitializeBackground(LibraryAppletMode library_applet_mode);
+ void InitializePartialForeground(LibraryAppletMode library_applet_mode);
/// Processes the text check sent by the application.
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) {
// Set focus state
switch (mode) {
case LibraryAppletMode::AllForeground:
- case LibraryAppletMode::NoUI:
+ case LibraryAppletMode::NoUi:
applet->focus_state = FocusState::InFocus;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
@@ -99,8 +99,8 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
applet->hid_registration.EnableAppletToGetInput(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
- case LibraryAppletMode::Background:
- case LibraryAppletMode::BackgroundIndirectDisplay:
+ case LibraryAppletMode::PartialForeground:
+ case LibraryAppletMode::PartialForegroundIndirectDisplay:
default:
applet->focus_state = FocusState::Background;
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) {
}
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
- if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
+ if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id,
+ applet->library_applet_mode)) {
return ResultSuccess;
}
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() {
// Clean up shared layers.
if (m_buffer_sharing_enabled) {
+ m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
}
}
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
- AppletId applet_id) {
+ AppletId applet_id, LibraryAppletMode mode) {
if (m_nvnflinger) {
return m_buffer_sharing_enabled;
}
@@ -36,9 +37,14 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
return false;
}
+ Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
+ if (mode == LibraryAppletMode::PartialForeground) {
+ blending = Nvnflinger::LayerBlending::Coverage;
+ }
+
const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
- &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
+ m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
if (res.IsSuccess()) {
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:
SystemBufferManager();
~SystemBufferManager();
- bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
+ bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
+ LibraryAppletMode mode);
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
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 @@
namespace Service::Nvidia::Devices {
+namespace {
+
+Tegra::BlendMode ConvertBlending(Service::Nvnflinger::LayerBlending blending) {
+ switch (blending) {
+ case Service::Nvnflinger::LayerBlending::None:
+ default:
+ return Tegra::BlendMode::Opaque;
+ case Service::Nvnflinger::LayerBlending::Premultiplied:
+ return Tegra::BlendMode::Premultiplied;
+ case Service::Nvnflinger::LayerBlending::Coverage:
+ return Tegra::BlendMode::Coverage;
+ }
+}
+
+} // namespace
+
nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
nvdisp_disp0::~nvdisp_disp0() = default;
@@ -56,6 +72,7 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
.pixel_format = layer.format,
.transform_flags = layer.transform,
.crop_rect = layer.crop_rect,
+ .blending = ConvertBlending(layer.blending),
});
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 @@
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h"
+#include "video_core/gpu.h"
namespace Service::Nvnflinger {
namespace {
-Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
- std::unique_ptr<Kernel::KPageGroup>* out_page_group,
- Core::System& system, u32 size) {
+Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
+ Core::System& system, u32 size) {
using Core::Memory::YUZU_PAGESIZE;
// Allocate memory for the system shared buffer.
- // FIXME: Because the gmmu can only point to cpu addresses, we need
- // to map this in the application space to allow it to be used.
- // FIXME: Add proper smmu emulation.
// FIXME: This memory belongs to vi's .data section.
auto& kernel = system.Kernel();
- auto* process = system.ApplicationProcess();
- auto& page_table = process->GetPageTable();
// Hold a temporary page group reference while we try to map it.
auto pg = std::make_unique<Kernel::KPageGroup>(
@@ -43,6 +38,30 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
Kernel::KMemoryManager::Direction::FromBack)));
+ // Fill the output data with red.
+ for (auto& block : *pg) {
+ u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
+ u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
+
+ for (; start < end; start++) {
+ *start = 0xFF0000FF;
+ }
+ }
+
+ // Return the mapped page group.
+ *out_page_group = std::move(pg);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
+ std::unique_ptr<Kernel::KPageGroup>& pg,
+ Kernel::KProcess* process, Core::System& system) {
+ using Core::Memory::YUZU_PAGESIZE;
+
+ auto& page_table = process->GetPageTable();
+
// Get bounds of where mapping is possible.
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
@@ -64,9 +83,6 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
// Return failure, if necessary
R_UNLESS(i < 64, res);
- // Return the mapped page group.
- *out_page_group = std::move(pg);
-
// We succeeded.
R_SUCCEED();
}
@@ -135,6 +151,13 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
}
+void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
+ auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
+ ASSERT(nvmap != nullptr);
+
+ R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
+}
+
constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
constexpr u32 SharedBufferBlockLinearBpp = 4;
@@ -186,53 +209,97 @@ FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& fli
FbShareBufferManager::~FbShareBufferManager() = default;
-Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
+Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
+ u64* out_layer_handle, u64 display_id,
+ LayerBlending blending) {
std::scoped_lock lk{m_guard};
- // Ensure we have not already created a buffer.
- R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
+ // Ensure we haven't already created.
+ const u64 aruid = owner_process->GetProcessId();
+ R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
+
+ // Allocate memory for the shared buffer if needed.
+ if (!m_buffer_page_group) {
+ R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
+ SharedBufferSize));
- // Allocate memory and space for the shared buffer.
- Common::ProcessAddress map_address;
- R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
- std::addressof(m_buffer_page_group), m_system,
- SharedBufferSize));
+ // Record buffer id.
+ m_buffer_id = m_next_buffer_id++;
+
+ // Record display id.
+ m_display_id = display_id;
+ }
+
+ // Map into process.
+ Common::ProcessAddress map_address{};
+ R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
+ owner_process, m_system));
+
+ // Create new session.
+ auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{});
+ auto& session = it->second;
auto& container = m_nvdrv->GetContainer();
- m_session_id = container.OpenSession(m_system.ApplicationProcess());
- m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id);
+ session.session_id = container.OpenSession(owner_process);
+ session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
// Create an nvmap handle for the buffer and assign the memory to it.
- R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd,
- map_address, SharedBufferSize));
-
- // Record the display id.
- m_display_id = display_id;
+ R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
+ session.nvmap_fd, map_address, SharedBufferSize));
// Create and open a layer for the display.
- m_layer_id = m_flinger.CreateLayer(m_display_id).value();
- m_flinger.OpenLayer(m_layer_id);
-
- // Set up the buffer.
- m_buffer_id = m_next_buffer_id++;
+ session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value();
+ m_flinger.OpenLayer(session.layer_id);
// Get the layer.
- VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
+ VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id);
ASSERT(layer != nullptr);
// Get the producer and set preallocated buffers.
auto& producer = layer->GetBufferQueue();
- MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
- MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
+ MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
+ MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
// Assign outputs.
*out_buffer_id = m_buffer_id;
- *out_layer_id = m_layer_id;
+ *out_layer_handle = session.layer_id;
// We succeeded.
R_SUCCEED();
}
+void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
+ std::scoped_lock lk{m_guard};
+
+ if (m_buffer_id == 0) {
+ return;
+ }
+
+ const u64 aruid = owner_process->GetProcessId();
+ const auto it = m_sessions.find(aruid);
+ if (it == m_sessions.end()) {
+ return;
+ }
+
+ auto& session = it->second;
+
+ // Destroy the layer.
+ m_flinger.DestroyLayer(session.layer_id);
+
+ // Close nvmap handle.
+ FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
+
+ // Close nvmap device.
+ m_nvdrv->Close(session.nvmap_fd);
+
+ // Close session.
+ auto& container = m_nvdrv->GetContainer();
+ container.CloseSession(session.session_id);
+
+ // Erase.
+ m_sessions.erase(it);
+}
+
Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout,
@@ -242,17 +309,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
+ R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
*out_pool_layout = SharedBufferPoolLayout;
*out_buffer_size = SharedBufferSize;
- *out_nvmap_handle = m_buffer_nvmap_handle;
+ *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
R_SUCCEED();
}
Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
// Ensure the layer id is valid.
- R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
+ R_UNLESS(layer_id > 0, VI::ResultNotFound);
// Get the layer.
VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
@@ -309,6 +377,10 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError,
VI::ResultOperationFailed);
+ ON_RESULT_FAILURE {
+ producer.CancelBuffer(static_cast<s32>(slot), fence);
+ };
+
// Queue the buffer to the producer.
android::QueueBufferInput input{};
android::QueueBufferOutput output{};
@@ -342,4 +414,12 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab
R_SUCCEED();
}
+Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
+ s32* out_layer_index) {
+ // TODO
+ *out_was_written = true;
+ *out_layer_index = 1;
+ R_SUCCEED();
+}
+
} // 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 @@
#pragma once
+#include <map>
+
#include "common/math_util.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/nvdata.h"
+#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/ui/fence.h"
@@ -29,13 +32,18 @@ struct SharedMemoryPoolLayout {
};
static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
+struct FbShareSession;
+
class FbShareBufferManager final {
public:
explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
std::shared_ptr<Nvidia::Module> nvdrv);
~FbShareBufferManager();
- Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
+ Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
+ u64 display_id, LayerBlending blending);
+ void Finalize(Kernel::KProcess* owner_process);
+
Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
u64 applet_resource_user_id);
@@ -45,6 +53,8 @@ public:
u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
+ Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
+
private:
Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
@@ -52,11 +62,8 @@ private:
u64 m_next_buffer_id = 1;
u64 m_display_id = 0;
u64 m_buffer_id = 0;
- u64 m_layer_id = 0;
- u32 m_buffer_nvmap_handle = 0;
SharedMemoryPoolLayout m_pool_layout = {};
- Nvidia::DeviceFD m_nvmap_fd = {};
- Nvidia::NvCore::SessionId m_session_id = {};
+ std::map<u64, FbShareSession> m_sessions;
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
std::mutex m_guard;
@@ -65,4 +72,11 @@ private:
std::shared_ptr<Nvidia::Module> m_nvdrv;
};
+struct FbShareSession {
+ Nvidia::DeviceFD nvmap_fd = {};
+ Nvidia::NvCore::SessionId session_id = {};
+ u64 layer_id = {};
+ u32 buffer_nvmap_handle = 0;
+};
+
} // 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,
.height = igbp_buffer.Height(),
.stride = igbp_buffer.Stride(),
.z_index = 0,
+ .blending = layer.GetBlending(),
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
.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 @@
namespace Service::Nvnflinger {
+// hwc_layer_t::blending values
+enum class LayerBlending : u32 {
+ // No blending
+ None = 0x100,
+
+ // ONE / ONE_MINUS_SRC_ALPHA
+ Premultiplied = 0x105,
+
+ // SRC_ALPHA / ONE_MINUS_SRC_ALPHA
+ Coverage = 0x405,
+};
+
struct HwcLayer {
u32 buffer_handle;
u32 offset;
@@ -19,6 +31,7 @@ struct HwcLayer {
u32 height;
u32 stride;
s32 z_index;
+ LayerBlending blending;
android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect;
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) {
return true;
}
-std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
+std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@@ -166,13 +166,14 @@ std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
}
const u64 layer_id = next_layer_id++;
- CreateLayerAtId(*display, layer_id);
+ CreateLayerAtId(*display, layer_id, blending);
return layer_id;
}
-void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
+void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
const auto buffer_id = next_buffer_queue_id++;
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
+ display.FindLayer(layer_id)->SetBlending(blending);
}
bool 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 @@
#include "common/thread.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nvnflinger/hwc_layer.h"
namespace Common {
class Event;
@@ -72,7 +73,8 @@ public:
/// Creates a layer on the specified display and returns the layer ID.
///
/// If an invalid display ID is specified, then an empty optional is returned.
- [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
+ [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
+ LayerBlending blending = LayerBlending::None);
/// Opens a layer on all displays for the given layer ID.
bool OpenLayer(u64 layer_id);
@@ -128,7 +130,7 @@ private:
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Creates a layer with the specified layer ID in the desired display.
- void CreateLayerAtId(VI::Display& display, u64 layer_id);
+ void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
void SplitVSync(std::stop_token stop_token);
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 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/vi/layer/vi_layer.h"
namespace Service::VI {
@@ -8,8 +9,9 @@ namespace Service::VI {
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
- : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
- consumer{std::move(consumer_)}, open{false}, visible{true} {}
+ : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
+ consumer_)},
+ blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
Layer::~Layer() = default;
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;
class BufferQueueProducer;
} // namespace Service::android
+namespace Service::Nvnflinger {
+enum class LayerBlending : u32;
+}
+
namespace Service::VI {
/// Represents a single display layer.
@@ -92,12 +96,21 @@ public:
return !std::exchange(open, true);
}
+ Nvnflinger::LayerBlending GetBlending() {
+ return blending;
+ }
+
+ void SetBlending(Nvnflinger::LayerBlending b) {
+ blending = b;
+ }
+
private:
const u64 layer_id;
const u32 binder_id;
android::BufferQueueCore& core;
android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer;
+ Service::Nvnflinger::LayerBlending blending;
bool open;
bool visible;
};
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 @@
namespace Tegra {
+enum class BlendMode {
+ Opaque,
+ Premultiplied,
+ Coverage,
+};
+
/**
* Struct describing framebuffer configuration
*/
@@ -23,6 +29,7 @@ struct FramebufferConfig {
Service::android::PixelFormat pixel_format{};
Service::android::BufferTransformFlags transform_flags{};
Common::Rectangle<int> crop_rect{};
+ BlendMode blending{};
};
Common::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;
#define A_GPU 1
#define A_GLSL 1
+#define FSR_RCAS_PASSTHROUGH_ALPHA 1
#ifndef YUZU_USE_FP16
#include "ffx_a.h"
@@ -71,9 +72,7 @@ layout(set=0,binding=0) uniform sampler2D InputTexture;
#include "ffx_fsr1.h"
-#if USE_RCAS
- layout(location = 0) in vec2 frag_texcoord;
-#endif
+layout (location = 0) in vec2 frag_texcoord;
layout (location = 0) out vec4 frag_color;
void CurrFilter(AU2 pos) {
@@ -81,22 +80,22 @@ void CurrFilter(AU2 pos) {
#ifndef YUZU_USE_FP16
AF3 c;
FsrEasuF(c, pos, Const0, Const1, Const2, Const3);
- frag_color = AF4(c, 1.0);
+ frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
#else
AH3 c;
FsrEasuH(c, pos, Const0, Const1, Const2, Const3);
- frag_color = AH4(c, 1.0);
+ frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
#endif
#endif
#if USE_RCAS
#ifndef YUZU_USE_FP16
- AF3 c;
- FsrRcasF(c.r, c.g, c.b, pos, Const0);
- frag_color = AF4(c, 1.0);
+ AF4 c;
+ FsrRcasF(c.r, c.g, c.b, c.a, pos, Const0);
+ frag_color = c;
#else
- AH3 c;
- FsrRcasH(c.r, c.g, c.b, pos, Const0);
- frag_color = AH4(c, 1.0);
+ AH4 c;
+ FsrRcasH(c.r, c.g, c.b, c.a, pos, Const0);
+ frag_color = c;
#endif
#endif
}
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) {
}
void main() {
- frag_color = vec4(FxaaPixelShader(posPos, input_texture), 1.0);
+ frag_color = vec4(FxaaPixelShader(posPos, input_texture), texture(input_texture, posPos.xy).a);
}
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];
#define A_GPU 1
#define A_GLSL 1
+#define FSR_RCAS_PASSTHROUGH_ALPHA 1
#ifdef YUZU_USE_FP16
#define A_HALF
@@ -67,9 +68,7 @@ layout (location = 0) uniform uvec4 constants[4];
#include "ffx_fsr1.h"
-#if USE_RCAS
- layout(location = 0) in vec2 frag_texcoord;
-#endif
+layout (location = 0) in vec2 frag_texcoord;
layout (location = 0) out vec4 frag_color;
void CurrFilter(AU2 pos)
@@ -78,22 +77,22 @@ void CurrFilter(AU2 pos)
#ifndef YUZU_USE_FP16
AF3 c;
FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]);
- frag_color = AF4(c, 1.0);
+ frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
#else
AH3 c;
FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]);
- frag_color = AH4(c, 1.0);
+ frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
#endif
#endif
#if USE_RCAS
#ifndef YUZU_USE_FP16
- AF3 c;
- FsrRcasF(c.r, c.g, c.b, pos, constants[0]);
- frag_color = AF4(c, 1.0);
+ AF4 c;
+ FsrRcasF(c.r, c.g, c.b, c.a, pos, constants[0]);
+ frag_color = c;
#else
AH3 c;
- FsrRcasH(c.r, c.g, c.b, pos, constants[0]);
- frag_color = AH4(c, 1.0);
+ FsrRcasH(c.r, c.g, c.b, c.a, pos, constants[0]);
+ frag_color = c;
#endif
#endif
}
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;
layout (binding = 0) uniform sampler2D color_texture;
void main() {
- color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
+ color = vec4(texture(color_texture, frag_tex_coord));
}
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 ) {
}
void main() {
- color = vec4(textureBicubic(color_texture, frag_tex_coord).rgb, 1.0f);
+ color = textureBicubic(color_texture, frag_tex_coord);
}
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) {
}
void main() {
- vec3 base = texture(color_texture, vec2(frag_tex_coord)).rgb * weight[0];
+ vec4 base = texture(color_texture, vec2(frag_tex_coord)) * weight[0];
vec2 tex_offset = 1.0f / textureSize(color_texture, 0);
// TODO(Blinkhawk): This code can be optimized through shader group instructions.
- vec3 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset).rgb;
- vec3 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset).rgb;
- vec3 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset).rgb;
- vec3 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0)).rgb;
- vec3 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
- color = vec4(combination + base, 1.0f);
+ vec4 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset);
+ vec4 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset);
+ vec4 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset);
+ vec4 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0));
+ vec4 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
+ color = combination + base;
}
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 @@
#define YUZU_USE_FP16
#define USE_EASU 1
+#define VERSION 1
#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 @@
#extension GL_GOOGLE_include_directive : enable
#define USE_EASU 1
+#define VERSION 1
#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 @@
#define YUZU_USE_FP16
#define USE_RCAS 1
+#define VERSION 1
#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 @@
#extension GL_GOOGLE_include_directive : enable
#define USE_RCAS 1
+#define VERSION 1
#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 @@
#extension GL_GOOGLE_include_directive : enable
-#define VERSION 1
+#define VERSION 2
#define YUZU_USE_FP16
#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 @@
#extension GL_GOOGLE_include_directive : enable
-#define VERSION 1
+#define VERSION 2
#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
glClear(GL_COLOR_BUFFER_BIT);
for (size_t i = 0; i < layer_count; i++) {
+ switch (framebuffers[i].blending) {
+ case Tegra::BlendMode::Opaque:
+ default:
+ glDisablei(GL_BLEND, 0);
+ break;
+ case Tegra::BlendMode::Premultiplied:
+ glEnablei(GL_BLEND, 0);
+ glBlendFuncSeparatei(0, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
+ break;
+ case Tegra::BlendMode::Coverage:
+ glEnablei(GL_BLEND, 0);
+ glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
+ break;
+ }
+
glBindTextureUnit(0, textures[i]);
glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE,
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,
});
}
-vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
- vk::PipelineLayout& layout,
- std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
- bool enable_blending) {
+static vk::Pipeline CreateWrappedPipelineImpl(
+ const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
+ VkPipelineColorBlendAttachmentState blending) {
const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@@ -443,30 +443,6 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
.alphaToOneEnable = VK_FALSE,
};
- constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
- .blendEnable = VK_FALSE,
- .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
- .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
- .colorBlendOp = VK_BLEND_OP_ADD,
- .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
- .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
- .alphaBlendOp = VK_BLEND_OP_ADD,
- .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
- VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
- };
-
- constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{
- .blendEnable = VK_TRUE,
- .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
- .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
- .colorBlendOp = VK_BLEND_OP_ADD,
- .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
- .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
- .alphaBlendOp = VK_BLEND_OP_ADD,
- .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
- VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
- };
-
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = nullptr,
@@ -474,8 +450,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
- .pAttachments =
- enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled,
+ .pAttachments = &blending,
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
};
@@ -515,6 +490,63 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
});
}
+vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
+ vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
+ constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
+ .blendEnable = VK_FALSE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+ };
+
+ return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
+ color_blend_attachment_disabled);
+}
+
+vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
+ const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
+ constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_premultiplied{
+ .blendEnable = VK_TRUE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+ };
+
+ return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
+ color_blend_attachment_premultiplied);
+}
+
+vk::Pipeline CreateWrappedCoverageBlendingPipeline(
+ const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
+ constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_coverage{
+ .blendEnable = VK_TRUE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+ };
+
+ return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
+ color_blend_attachment_coverage);
+}
+
VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
VkSampler sampler, VkImageView view,
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,
vk::DescriptorSetLayout& layout);
vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
vk::PipelineLayout& layout,
- std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
- bool enable_blending = false);
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
+vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
+ const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
+vk::Pipeline CreateWrappedCoverageBlendingPipeline(
+ const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
+ std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
VkSampler sampler, VkImageView view,
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,
CreatePipelineLayout();
CreateVertexShader();
CreateRenderPass(frame_format);
- CreatePipeline();
+ CreatePipelines();
}
WindowAdaptPass::~WindowAdaptPass() = default;
@@ -34,7 +34,6 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
const VkFramebuffer host_framebuffer{*dst->framebuffer};
const VkRenderPass renderpass{*render_pass};
- const VkPipeline graphics_pipeline{*pipeline};
const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout};
const VkExtent2D render_area{
.width = dst->width,
@@ -44,9 +43,23 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
const size_t layer_count = configs.size();
std::vector<PresentPushConstants> push_constants(layer_count);
std::vector<VkDescriptorSet> descriptor_sets(layer_count);
+ std::vector<VkPipeline> graphics_pipelines(layer_count);
auto layer_it = layers.begin();
for (size_t i = 0; i < layer_count; i++) {
+ switch (configs[i].blending) {
+ case Tegra::BlendMode::Opaque:
+ default:
+ graphics_pipelines[i] = *opaque_pipeline;
+ break;
+ case Tegra::BlendMode::Premultiplied:
+ graphics_pipelines[i] = *premultiplied_pipeline;
+ break;
+ case Tegra::BlendMode::Coverage:
+ graphics_pipelines[i] = *coverage_pipeline;
+ break;
+ }
+
layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
image_index, configs[i], layout);
layer_it++;
@@ -77,8 +90,8 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area);
cmdbuf.ClearAttachments({clear_attachment}, {clear_rect});
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
for (size_t i = 0; i < layer_count; i++) {
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]);
cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
push_constants[i]);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0,
@@ -129,9 +142,13 @@ void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) {
render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED);
}
-void WindowAdaptPass::CreatePipeline() {
- pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
- std::tie(vertex_shader, fragment_shader), false);
+void WindowAdaptPass::CreatePipelines() {
+ opaque_pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
+ std::tie(vertex_shader, fragment_shader));
+ premultiplied_pipeline = CreateWrappedPremultipliedBlendingPipeline(
+ device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
+ coverage_pipeline = CreateWrappedCoverageBlendingPipeline(
+ device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
}
} // 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:
void CreatePipelineLayout();
void CreateVertexShader();
void CreateRenderPass(VkFormat frame_format);
- void CreatePipeline();
+ void CreatePipelines();
private:
const Device& device;
@@ -52,7 +52,9 @@ private:
vk::ShaderModule vertex_shader;
vk::ShaderModule fragment_shader;
vk::RenderPass render_pass;
- vk::Pipeline pipeline;
+ vk::Pipeline opaque_pipeline;
+ vk::Pipeline premultiplied_pipeline;
+ vk::Pipeline coverage_pipeline;
};
} // 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_,
surface),
blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler),
blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler),
+ blit_application_layer(device_memory, device, memory_allocator, present_manager, scheduler),
rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
- scheduler) {
+ scheduler),
+ application_frame() {
if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
turbo_mode.emplace(instance, dld);
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:
PresentManager present_manager;
BlitScreen blit_swapchain;
BlitScreen blit_screenshot;
+ BlitScreen blit_application_layer;
RasterizerVulkan rasterizer;
std::optional<TurboMode> turbo_mode;
+
+ Frame application_frame;
};
} // 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
}();
const auto GetImageViewForFramebuffer = [&](ImageId image_id) {
- const ImageViewInfo info{ImageViewType::e2D, view_format};
+ ImageViewInfo info{ImageViewType::e2D, view_format};
+ if (config.blending == Tegra::BlendMode::Opaque) {
+ info.x_source = static_cast<u8>(SwizzleSource::R);
+ info.y_source = static_cast<u8>(SwizzleSource::G);
+ info.z_source = static_cast<u8>(SwizzleSource::B);
+ info.w_source = static_cast<u8>(SwizzleSource::OneFloat);
+ }
return std::make_pair(&slot_image_views[FindOrEmplaceImageView(image_id, info)],
slot_images[image_id].IsRescaled());
};