Compare commits

..

2 Commits

Author SHA1 Message Date
Caio Oliveira
0490529a01 adapt to upstream changes
Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-12-18 22:52:50 +01:00
lizzie
c7a7fe15e5 do not register handlers for fastmem if fastmem is disabled
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-12-18 22:52:50 +01:00
22 changed files with 353 additions and 148 deletions

View File

@@ -10,7 +10,6 @@
#include <mutex>
#include <span>
#include <thread>
#include <type_traits>
#include <vector>
#include "common/assert.h"
@@ -682,17 +681,22 @@ struct Memory::Impl {
}
}
template<typename F, typename G>
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const {
// AARCH64 masks the upper 16 bit of all memory accesses
vaddr &= 0xffffffffffffULL;
if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] {
vaddr = vaddr & 0xffffffffffffULL;
if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] {
on_unmapped();
return nullptr;
} else {
// Avoid adding any extra logic to this fast-path block
const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) [[likely]] {
if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
return reinterpret_cast<u8*>(pointer + vaddr);
} else {
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
case Common::PageType::Unmapped:
on_unmapped();
return nullptr;
case Common::PageType::Memory:
ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr);
return nullptr;
@@ -703,18 +707,11 @@ struct Memory::Impl {
on_rasterizer();
return host_ptr;
}
case Common::PageType::Unmapped: [[unlikely]] {
on_unmapped();
return nullptr;
}
default:
UNREACHABLE();
}
return nullptr;
}
} else {
on_unmapped();
return nullptr;
}
}
@@ -732,38 +729,172 @@ struct Memory::Impl {
GetInteger(vaddr), []() {}, []() {});
}
/// @brief Reads a particular data type out of memory at the given virtual address.
/// @param vaddr The virtual address to read the data type from.
/// @tparam T The data type to read out of memory.
/// @returns The instance of T read from the specified virtual address.
/**
* Reads a particular data type out of memory at the given virtual address.
*
* @param vaddr The virtual address to read the data type from.
*
* @tparam T The data type to read out of memory. This type *must* be
* trivially copyable, otherwise the behavior of this function
* is undefined.
*
* @returns The instance of T read from the specified virtual address.
*/
template <typename T>
inline T Read(Common::ProcessAddress vaddr) noexcept requires(std::is_trivially_copyable_v<T>) {
T Read(Common::ProcessAddress vaddr) {
// Fast path for aligned reads of common sizes
const u64 addr = GetInteger(vaddr);
if (auto const ptr = GetPointerImpl(addr, [addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr);
}, [&]() {
HandleRasterizerDownload(addr, sizeof(T));
}); ptr) [[likely]] {
// It may be tempting to rewrite this particular section to use "reinterpret_cast";
// afterall, it's trivially copyable so surely it can be copied ov- Alignment.
// Remember, alignment. memcpy() will deal with all the alignment extremely fast.
T result{};
std::memcpy(&result, ptr, sizeof(T));
return result;
if constexpr (std::is_same_v<T, u8> || std::is_same_v<T, s8>) {
// 8-bit reads are always aligned
const u8* const ptr = GetPointerImpl(
addr,
[addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read8 @ 0x{:016X}", addr);
},
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
if (ptr) {
return static_cast<T>(*ptr);
}
return 0;
} else if constexpr (std::is_same_v<T, u16_le> || std::is_same_v<T, s16_le>) {
// Check alignment for 16-bit reads
if ((addr & 1) == 0) {
const u8* const ptr = GetPointerImpl(
addr,
[addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read16 @ 0x{:016X}", addr);
},
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
if (ptr) {
return static_cast<T>(*reinterpret_cast<const u16*>(ptr));
}
}
} else if constexpr (std::is_same_v<T, u32_le> || std::is_same_v<T, s32_le>) {
// Check alignment for 32-bit reads
if ((addr & 3) == 0) {
const u8* const ptr = GetPointerImpl(
addr,
[addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read32 @ 0x{:016X}", addr);
},
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
if (ptr) {
return static_cast<T>(*reinterpret_cast<const u32*>(ptr));
}
}
} else if constexpr (std::is_same_v<T, u64_le> || std::is_same_v<T, s64_le>) {
// Check alignment for 64-bit reads
if ((addr & 7) == 0) {
const u8* const ptr = GetPointerImpl(
addr,
[addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read64 @ 0x{:016X}", addr);
},
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
if (ptr) {
return static_cast<T>(*reinterpret_cast<const u64*>(ptr));
}
}
}
return T{};
// Fall back to the general case for other types or unaligned access
T result = 0;
const u8* const ptr = GetPointerImpl(
addr,
[addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr);
},
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
if (ptr) {
std::memcpy(&result, ptr, sizeof(T));
}
return result;
}
/// @brief Writes a particular data type to memory at the given virtual address.
/// @param vaddr The virtual address to write the data type to.
/// @tparam T The data type to write to memory.
/**
* Writes a particular data type to memory at the given virtual address.
*
* @param vaddr The virtual address to write the data type to.
*
* @tparam T The data type to write to memory. This type *must* be
* trivially copyable, otherwise the behavior of this function
* is undefined.
*/
template <typename T>
inline void Write(Common::ProcessAddress vaddr, const T data) noexcept requires(std::is_trivially_copyable_v<T>) {
void Write(Common::ProcessAddress vaddr, const T data) {
// Fast path for aligned writes of common sizes
const u64 addr = GetInteger(vaddr);
if (auto const ptr = GetPointerImpl(addr, [addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data));
}, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]]
if constexpr (std::is_same_v<T, u8> || std::is_same_v<T, s8>) {
// 8-bit writes are always aligned
u8* const ptr = GetPointerImpl(
addr,
[addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write8 @ 0x{:016X} = 0x{:02X}", addr,
static_cast<u8>(data));
},
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
if (ptr) {
*ptr = static_cast<u8>(data);
}
return;
} else if constexpr (std::is_same_v<T, u16_le> || std::is_same_v<T, s16_le>) {
// Check alignment for 16-bit writes
if ((addr & 1) == 0) {
u8* const ptr = GetPointerImpl(
addr,
[addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write16 @ 0x{:016X} = 0x{:04X}", addr,
static_cast<u16>(data));
},
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
if (ptr) {
*reinterpret_cast<u16*>(ptr) = static_cast<u16>(data);
return;
}
}
} else if constexpr (std::is_same_v<T, u32_le> || std::is_same_v<T, s32_le>) {
// Check alignment for 32-bit writes
if ((addr & 3) == 0) {
u8* const ptr = GetPointerImpl(
addr,
[addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write32 @ 0x{:016X} = 0x{:08X}", addr,
static_cast<u32>(data));
},
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
if (ptr) {
*reinterpret_cast<u32*>(ptr) = static_cast<u32>(data);
return;
}
}
} else if constexpr (std::is_same_v<T, u64_le> || std::is_same_v<T, s64_le>) {
// Check alignment for 64-bit writes
if ((addr & 7) == 0) {
u8* const ptr = GetPointerImpl(
addr,
[addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write64 @ 0x{:016X} = 0x{:016X}", addr,
static_cast<u64>(data));
},
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
if (ptr) {
*reinterpret_cast<u64*>(ptr) = static_cast<u64>(data);
return;
}
}
}
// Fall back to the general case for other types or unaligned access
u8* const ptr = GetPointerImpl(
addr,
[addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
addr, static_cast<u64>(data));
},
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
if (ptr) {
std::memcpy(ptr, &data, sizeof(T));
}
}
template <typename T>

View File

@@ -57,7 +57,7 @@ class SigHandler {
public:
SigHandler() noexcept {
signal_stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
signal_stack_memory = std::malloc(signal_stack_size);
stack_t signal_stack{};
signal_stack.ss_sp = signal_stack_memory;
@@ -89,7 +89,7 @@ public:
}
~SigHandler() noexcept {
munmap(signal_stack_memory, signal_stack_size);
std::free(signal_stack_memory);
}
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {

View File

@@ -82,7 +82,8 @@ FP::FPCR A32EmitContext::FPCR(bool fpcr_controlled) const {
A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_interface)
: EmitX64(code), conf(std::move(conf)), jit_interface(jit_interface) {
GenFastmemFallbacks();
if (conf.fastmem_pointer.has_value())
GenFastmemFallbacks();
GenTerminalHandlers();
code.PreludeComplete();
ClearFastDispatchTable();

View File

@@ -56,7 +56,8 @@ FP::FPCR A64EmitContext::FPCR(bool fpcr_controlled) const {
A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_interface)
: EmitX64(code), conf(conf), jit_interface{jit_interface} {
GenMemory128Accessors();
GenFastmemFallbacks();
if (conf.fastmem_pointer.has_value())
GenFastmemFallbacks();
GenTerminalHandlers();
code.PreludeComplete();
ClearFastDispatchTable();

View File

@@ -14,7 +14,7 @@
#include "input_common/drivers/mouse.h"
namespace InputCommon {
constexpr int update_time = 10;
constexpr int update_time = 250; // 4 TPS
constexpr float default_panning_sensitivity = 0.0010f;
constexpr float default_stick_sensitivity = 0.0006f;
constexpr float default_deadzone_counterweight = 0.01f;

View File

@@ -1049,7 +1049,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
VkShaderModule frag_shader = *convert_float_to_depth_frag;
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -1079,7 +1079,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
VkShaderModule frag_shader = *convert_depth_to_float_frag;
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -1110,7 +1110,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
}
const std::array stages = MakeStages(*full_screen_vert, *module);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -1152,7 +1152,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,

View File

@@ -137,8 +137,14 @@ try
memory_allocator,
scheduler,
swapchain,
#ifdef ANDROID
surface)
,
#else
*surface)
, blit_swapchain(device_memory,
,
#endif
blit_swapchain(device_memory,
device,
memory_allocator,
present_manager,

View File

@@ -284,7 +284,7 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
.requiredSubgroupSize = optional_subgroup_size ? *optional_subgroup_size : 32U,
};
bool use_setup_size = device.IsExtSubgroupSizeControlSupported() && optional_subgroup_size;
pipeline = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{
pipeline = device.GetLogical().CreateComputePipeline({
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -298,7 +298,7 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
.pSpecializationInfo = nullptr,
},
.layout = *layout,
.basePipelineHandle = {},
.basePipelineHandle = nullptr,
.basePipelineIndex = 0,
});
}
@@ -653,7 +653,7 @@ MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_,
.codeSize = static_cast<u32>(code.size_bytes()),
.pCode = code.data(),
});
pipelines[i] = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{
pipelines[i] = device.GetLogical().CreateComputePipeline({
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -667,7 +667,7 @@ MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_,
.pSpecializationInfo = nullptr,
},
.layout = *layout,
.basePipelineHandle = {},
.basePipelineHandle = nullptr,
.basePipelineIndex = 0,
});
};

View File

@@ -61,24 +61,26 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
}
pipeline = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = flags,
.stage{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.pNext =
device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = *spv_module,
.pName = "main",
.pSpecializationInfo = nullptr,
pipeline = device.GetLogical().CreateComputePipeline(
{
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = flags,
.stage{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.pNext =
device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = *spv_module,
.pName = "main",
.pSpecializationInfo = nullptr,
},
.layout = *pipeline_layout,
.basePipelineHandle = 0,
.basePipelineIndex = 0,
},
.layout = *pipeline_layout,
.basePipelineHandle = 0,
.basePipelineIndex = 0,
}, *pipeline_cache);
*pipeline_cache);
if (pipeline_statistics) {
pipeline_statistics->Collect(*pipeline);

View File

@@ -936,27 +936,29 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
}
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = flags,
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_ci,
.pInputAssemblyState = &input_assembly_ci,
.pTessellationState = &tessellation_ci,
.pViewportState = &viewport_ci,
.pRasterizationState = &rasterization_ci,
.pMultisampleState = &multisample_ci,
.pDepthStencilState = &depth_stencil_ci,
.pColorBlendState = &color_blend_ci,
.pDynamicState = &dynamic_state_ci,
.layout = *pipeline_layout,
.renderPass = render_pass,
.subpass = 0,
.basePipelineHandle = {},
.basePipelineIndex = 0,
}, *pipeline_cache);
pipeline = device.GetLogical().CreateGraphicsPipeline(
{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = flags,
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_ci,
.pInputAssemblyState = &input_assembly_ci,
.pTessellationState = &tessellation_ci,
.pViewportState = &viewport_ci,
.pRasterizationState = &rasterization_ci,
.pMultisampleState = &multisample_ci,
.pDepthStencilState = &depth_stencil_ci,
.pColorBlendState = &color_blend_ci,
.pDynamicState = &dynamic_state_ci,
.layout = *pipeline_layout,
.renderPass = render_pass,
.subpass = 0,
.basePipelineHandle = nullptr,
.basePipelineIndex = 0,
},
*pipeline_cache);
}
void GraphicsPipeline::Validate() {

View File

@@ -101,14 +101,22 @@ PresentManager::PresentManager(const vk::Instance& instance_,
MemoryAllocator& memory_allocator_,
Scheduler& scheduler_,
Swapchain& swapchain_,
VkSurfaceKHR_T* surface_)
#ifdef ANDROID
vk::SurfaceKHR& surface_)
#else
VkSurfaceKHR_T* surface_handle_)
#endif
: instance{instance_}
, render_window{render_window_}
, device{device_}
, memory_allocator{memory_allocator_}
, scheduler{scheduler_}
, swapchain{swapchain_}
#ifdef ANDROID
, surface{surface_}
#else
, surface_handle{surface_handle_}
#endif
, blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}
, use_present_thread{Settings::values.async_presentation.GetValue()}
{
@@ -291,7 +299,11 @@ void PresentManager::PresentThread(std::stop_token token) {
}
void PresentManager::RecreateSwapchain(Frame* frame) {
swapchain.Create(surface, frame->width, frame->height); // Pass raw pointer
#ifndef ANDROID
swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer
#else
swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer
#endif
SetImageCount();
}
@@ -310,7 +322,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
// Recreate surface and swapchain if needed.
if (requires_recreation) {
#ifdef ANDROID
surface = reinterpret_cast<VkSurfaceKHR_T*>(CreateSurface(instance, render_window.GetWindowInfo()).address());
surface = CreateSurface(instance, render_window.GetWindowInfo());
#endif
RecreateSwapchain(frame);
}

View File

@@ -15,6 +15,8 @@
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
struct VkSurfaceKHR_T;
namespace Core::Frontend {
class EmuWindow;
} // namespace Core::Frontend
@@ -44,7 +46,11 @@ public:
MemoryAllocator& memory_allocator,
Scheduler& scheduler,
Swapchain& swapchain,
VkSurfaceKHR_T* surface);
#ifdef ANDROID
vk::SurfaceKHR& surface);
#else
VkSurfaceKHR_T* surface_handle);
#endif
~PresentManager();
/// Returns the last used presentation frame
@@ -78,7 +84,11 @@ private:
MemoryAllocator& memory_allocator;
Scheduler& scheduler;
Swapchain& swapchain;
VkSurfaceKHR_T* surface;
#ifdef ANDROID
vk::SurfaceKHR& surface;
#else
VkSurfaceKHR_T* surface_handle;
#endif
vk::CommandPool cmdpool;
std::vector<Frame> frames;
boost::container::deque<Frame*> present_queue;

View File

@@ -1278,7 +1278,7 @@ void QueryCacheRuntime::EndHostConditionalRendering() {
PauseHostConditionalRendering();
impl->hcr_is_set = false;
impl->is_hcr_running = false;
impl->hcr_buffer = VkBuffer{};
impl->hcr_buffer = nullptr;
impl->hcr_offset = 0;
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -38,7 +35,7 @@ public:
~QueryCacheRuntime();
template <typename SyncValuesType>
void SyncValues(std::span<SyncValuesType> values, VkBuffer base_src_buffer = VkBuffer{});
void SyncValues(std::span<SyncValuesType> values, VkBuffer base_src_buffer = nullptr);
void Barriers(bool is_prebarrier);

View File

@@ -342,7 +342,7 @@ void Scheduler::EndRenderPass()
);
});
state.renderpass = VkRenderPass{};
state.renderpass = nullptr;
num_renderpass_images = 0;
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -43,10 +40,10 @@ public:
~Scheduler();
/// Sends the current execution context to the GPU.
u64 Flush(VkSemaphore signal_semaphore = {}, VkSemaphore wait_semaphore = {});
u64 Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
/// Sends the current execution context to the GPU and waits for it to complete.
void Finish(VkSemaphore signal_semaphore = {}, VkSemaphore wait_semaphore = {});
void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
/// Waits for the worker thread to finish executing everything. After this function returns it's
/// safe to touch worker resources.
@@ -211,8 +208,8 @@ private:
};
struct State {
VkRenderPass renderpass{};
VkFramebuffer framebuffer{};
VkRenderPass renderpass = nullptr;
VkFramebuffer framebuffer = nullptr;
VkExtent2D render_area = {0, 0};
GraphicsPipeline* graphics_pipeline = nullptr;
bool is_rescaling = false;

View File

@@ -109,22 +109,38 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
} // Anonymous namespace
Swapchain::Swapchain(
VkSurfaceKHR_T* surface_,
#ifdef ANDROID
VkSurfaceKHR surface_,
#else
VkSurfaceKHR_T* surface_handle_,
#endif
const Device& device_,
Scheduler& scheduler_,
u32 width_,
u32 height_)
#ifdef ANDROID
: surface(surface_)
#else
: surface_handle{surface_handle_}
#endif
, device{device_}
, scheduler{scheduler_}
{
#ifdef ANDROID
Create(surface, width_, height_);
#else
Create(surface_handle, width_, height_);
#endif
}
Swapchain::~Swapchain() = default;
void Swapchain::Create(
VkSurfaceKHR_T* surface_,
#ifdef ANDROID
VkSurfaceKHR surface_,
#else
VkSurfaceKHR_T* surface_handle_,
#endif
u32 width_,
u32 height_)
{
@@ -132,10 +148,18 @@ void Swapchain::Create(
is_suboptimal = false;
width = width_;
height = height_;
#ifdef ANDROID
surface = surface_;
#else
surface_handle = surface_handle_;
#endif
const auto physical_device = device.GetPhysical();
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(VkSurfaceKHR(surface))};
#ifdef ANDROID
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
#else
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)};
#endif
if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return;
}
@@ -213,8 +237,14 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
const auto physical_device{device.GetPhysical()};
const auto formats{physical_device.GetSurfaceFormatsKHR(VkSurfaceKHR(surface))};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(VkSurfaceKHR(surface));
#ifdef ANDROID
const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
#else
const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle);
#endif
has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR)
!= present_modes.end();
@@ -243,7 +273,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.surface = VkSurfaceKHR(surface),
#ifdef ANDROID
.surface = surface,
#else
.surface = surface_handle,
#endif
.minImageCount = requested_image_count,
.imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace,
@@ -262,7 +296,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
.compositeAlpha = alpha_flags,
.presentMode = present_mode,
.clipped = VK_FALSE,
.oldSwapchain = VkSwapchainKHR{},
.oldSwapchain = nullptr,
};
const u32 graphics_family{device.GetGraphicsFamily()};
const u32 present_family{device.GetPresentFamily()};
@@ -284,7 +318,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
}
// Request the size again to reduce the possibility of a TOCTOU race condition.
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(VkSurfaceKHR(surface));
#ifdef ANDROID
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface);
#else
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle);
#endif
swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height);
// Don't add code within this and the swapchain creation.
swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci);

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,6 +8,8 @@
#include "common/common_types.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
struct VkSurfaceKHR_T;
namespace Layout {
struct FramebufferLayout;
}
@@ -23,7 +22,11 @@ class Scheduler;
class Swapchain {
public:
explicit Swapchain(
VkSurfaceKHR_T* surface,
#ifdef ANDROID
VkSurfaceKHR surface,
#else
VkSurfaceKHR_T* surface_handle,
#endif
const Device& device,
Scheduler& scheduler,
u32 width,
@@ -32,7 +35,11 @@ public:
/// Creates (or recreates) the swapchain with a given size.
void Create(
VkSurfaceKHR_T* surface,
#ifdef ANDROID
VkSurfaceKHR surface,
#else
VkSurfaceKHR_T* surface_handle,
#endif
u32 width,
u32 height);
@@ -118,7 +125,11 @@ private:
bool NeedsPresentModeUpdate() const;
VkSurfaceKHR_T* surface;
#ifdef ANDROID
VkSurfaceKHR surface;
#else
VkSurfaceKHR_T* surface_handle;
#endif
const Device& device;
Scheduler& scheduler;

View File

@@ -29,6 +29,3 @@
#undef False
#undef None
#undef True
// "Catch-all" handle for both Android and.. the rest of platforms
struct VkSurfaceKHR_T;

View File

@@ -413,7 +413,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
: instance{instance_}, dld{dld_}, physical{physical_},
format_properties(GetFormatProperties(physical)) {
// Get suitability and device properties.
const bool is_suitable = GetSuitability(surface != VkSurfaceKHR{});
const bool is_suitable = GetSuitability(surface != nullptr);
const VkDriverId driver_id = properties.driver.driverID;
const auto device_id = properties.properties.deviceID;

View File

@@ -15,7 +15,7 @@ vk::SurfaceKHR CreateSurface(
const vk::Instance& instance,
[[maybe_unused]] const Core::Frontend::EmuWindow::WindowSystemInfo& window_info) {
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
VkSurfaceKHR unsafe_surface = VkSurfaceKHR{};
VkSurfaceKHR unsafe_surface = nullptr;
#ifdef _WIN32
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {

View File

@@ -399,13 +399,13 @@ public:
/// Construct a handle transferring the ownership from another handle.
Handle(Handle&& rhs) noexcept
: handle{std::exchange(rhs.handle, Type{})}, owner{rhs.owner}, dld{rhs.dld} {}
: handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
/// Assign the current handle transferring the ownership from another handle.
/// Destroys any previously held object.
Handle& operator=(Handle&& rhs) noexcept {
Release();
handle = std::exchange(rhs.handle, Type{});
handle = std::exchange(rhs.handle, nullptr);
owner = rhs.owner;
dld = rhs.dld;
return *this;
@@ -419,7 +419,7 @@ public:
/// Destroys any held object.
void reset() noexcept {
Release();
handle = Type{};
handle = nullptr;
}
/// Returns the address of the held object.
@@ -435,7 +435,7 @@ public:
/// Returns true when there's a held object.
explicit operator bool() const noexcept {
return handle != Type{};
return handle != nullptr;
}
#ifndef ANDROID
@@ -450,7 +450,7 @@ public:
#endif
protected:
Type handle{};
Type handle = nullptr;
OwnerType owner = nullptr;
const Dispatch* dld = nullptr;
@@ -458,7 +458,7 @@ private:
/// Destroys the held object if it exists.
void Release() noexcept {
if (handle) {
Destroy(OwnerType(owner), Type(handle), *dld);
Destroy(owner, handle, *dld);
}
}
};
@@ -501,7 +501,7 @@ public:
/// Destroys any held object.
void reset() noexcept {
Release();
handle = {};
handle = nullptr;
}
/// Returns the address of the held object.
@@ -517,7 +517,7 @@ public:
/// Returns true when there's a held object.
explicit operator bool() const noexcept {
return handle != Type{};
return handle != nullptr;
}
#ifndef ANDROID
@@ -532,7 +532,7 @@ public:
#endif
protected:
Type handle{};
Type handle = nullptr;
const Dispatch* dld = nullptr;
private:
@@ -602,7 +602,7 @@ private:
std::unique_ptr<AllocationType[]> allocations;
std::size_t num = 0;
VkDevice device = nullptr;
PoolType pool{};
PoolType pool = nullptr;
const DeviceDispatch* dld = nullptr;
};
@@ -664,12 +664,12 @@ public:
Image& operator=(const Image&) = delete;
Image(Image&& rhs) noexcept
: handle{std::exchange(rhs.handle, VkImage{})}, usage{rhs.usage}, owner{rhs.owner},
: handle{std::exchange(rhs.handle, nullptr)}, usage{rhs.usage}, owner{rhs.owner},
allocator{rhs.allocator}, allocation{rhs.allocation}, dld{rhs.dld} {}
Image& operator=(Image&& rhs) noexcept {
Release();
handle = std::exchange(rhs.handle, VkImage{});
handle = std::exchange(rhs.handle, nullptr);
usage = rhs.usage;
owner = rhs.owner;
allocator = rhs.allocator;
@@ -688,11 +688,11 @@ public:
void reset() noexcept {
Release();
handle = VkImage{};
handle = nullptr;
}
explicit operator bool() const noexcept {
return handle != VkImage{};
return handle != nullptr;
}
void SetObjectNameEXT(const char* name) const;
@@ -704,7 +704,7 @@ public:
private:
void Release() const noexcept;
VkImage handle{};
VkImage handle = nullptr;
VkImageUsageFlags usage{};
VkDevice owner = nullptr;
VmaAllocator allocator = nullptr;
@@ -725,13 +725,13 @@ public:
Buffer& operator=(const Buffer&) = delete;
Buffer(Buffer&& rhs) noexcept
: handle{std::exchange(rhs.handle, VkBuffer{})}, owner{rhs.owner}, allocator{rhs.allocator},
: handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
allocation{rhs.allocation}, mapped{rhs.mapped},
is_coherent{rhs.is_coherent}, dld{rhs.dld} {}
Buffer& operator=(Buffer&& rhs) noexcept {
Release();
handle = std::exchange(rhs.handle, VkBuffer{});
handle = std::exchange(rhs.handle, nullptr);
owner = rhs.owner;
allocator = rhs.allocator;
allocation = rhs.allocation;
@@ -751,11 +751,11 @@ public:
void reset() noexcept {
Release();
handle = VkBuffer{};
handle = nullptr;
}
explicit operator bool() const noexcept {
return handle != VkBuffer{};
return handle != nullptr;
}
/// Returns the host mapped memory, an empty span otherwise.
@@ -781,7 +781,7 @@ public:
private:
void Release() const noexcept;
VkBuffer handle{};
VkBuffer handle = nullptr;
VkDevice owner = nullptr;
VmaAllocator allocator = nullptr;
VmaAllocation allocation = nullptr;
@@ -1015,10 +1015,10 @@ public:
[[nodiscard]] PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
[[nodiscard]] Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci,
VkPipelineCache cache = {}) const;
VkPipelineCache cache = nullptr) const;
[[nodiscard]] Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci,
VkPipelineCache cache = {}) const;
VkPipelineCache cache = nullptr) const;
[[nodiscard]] Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;