aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorswurl <swurl@swurl.xyz>2025-05-11 23:58:25 +0000
committercrueter <crueter@noreply.localhost>2025-05-11 23:58:25 +0000
commit7e943732bf025bb7ead5ee3e104b88c020f9f422 (patch)
tree0f1a403b8f44190c90f9b4fab0a8de188237f735 /src/video_core
parent5bbb9eba32734219cd9b57dfeefaa028b1e8ab02 (diff)
fix a large variety of issues (#101)
- GLASM/SPIR-V mixup on Android - potential greenscreen fix (thx suyu) - save memory layout and add 10gb/12gb options - potential samsung gaming hub fix - fix layout of controller UI - fix default settings to sensible defaults. - note to TotK that you should increase memory layout - Error checking for Windows linking - fix an IDE error - improved migration system w/threading and busy indicator - disabled citron migration for now - replaced some user-facing legacy strings with eden - Added 10GB and 12GB DRAM layouts - Fix Android black screen issues - add discord link & update FAQ/Quickstart - update links in about page - add back rich presence - add Don't show again for desktop pre alpha banner - add citron warning to android and polaris to desktop Signed-off-by: swurl <swurl@swurl.xyz> Co-authored-by: Pavel Barabanov <pavelbarabanov94@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/101 Co-authored-by: swurl <swurl@swurl.xyz> Co-committed-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp182
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp114
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp41
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h18
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp62
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h26
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h4
8 files changed, 387 insertions, 62 deletions
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
index 7e955223db..fe85efaab3 100644
--- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp
+++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
@@ -1,6 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2024 suyu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
@@ -49,7 +55,8 @@ AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* p
return codec_context->pix_fmt;
}
-std::string AVError(int errnum) {
+std::string AVError(int errnum)
+{
char errbuf[AV_ERROR_MAX_STRING_SIZE] = {};
av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum);
return errbuf;
@@ -218,6 +225,167 @@ bool DecoderContext::OpenContext(const Decoder& decoder) {
return true;
}
+// Nasty but allows linux builds to pass.
+// Requires double checks when FFMPEG gets updated.
+// Hopefully a future FFMPEG update will all and expose a solution in the public API.
+namespace {
+
+typedef struct FFCodecDefault {
+ const char* key;
+ const char* value;
+} FFCodecDefault;
+
+typedef struct FFCodec {
+ /**
+ * The public AVCodec. See codec.h for it.
+ */
+ AVCodec p;
+
+ /**
+ * Internal codec capabilities FF_CODEC_CAP_*.
+ */
+ unsigned caps_internal : 29;
+
+ /**
+ * This field determines the type of the codec (decoder/encoder)
+ * and also the exact callback cb implemented by the codec.
+ * cb_type uses enum FFCodecType values.
+ */
+ unsigned cb_type : 3;
+
+ int priv_data_size;
+ /**
+ * @name Frame-level threading support functions
+ * @{
+ */
+ /**
+ * Copy necessary context variables from a previous thread context to the current one.
+ * If not defined, the next thread will start automatically; otherwise, the codec
+ * must call ff_thread_finish_setup().
+ *
+ * dst and src will (rarely) point to the same context, in which case memcpy should be skipped.
+ */
+ int (*update_thread_context)(struct AVCodecContext* dst, const struct AVCodecContext* src);
+
+ /**
+ * Copy variables back to the user-facing context
+ */
+ int (*update_thread_context_for_user)(struct AVCodecContext* dst,
+ const struct AVCodecContext* src);
+ /** @} */
+
+ /**
+ * Private codec-specific defaults.
+ */
+ const FFCodecDefault* defaults;
+
+ /**
+ * Initialize codec static data, called from av_codec_iterate().
+ *
+ * This is not intended for time consuming operations as it is
+ * run for every codec regardless of that codec being used.
+ */
+ void (*init_static_data)(struct FFCodec* codec);
+
+ int (*init)(struct AVCodecContext*);
+
+ union {
+ /**
+ * Decode to an AVFrame.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_DECODE.
+ *
+ * @param avctx codec context
+ * @param[out] frame AVFrame for output
+ * @param[out] got_frame_ptr decoder sets to 0 or 1 to indicate that
+ * a non-empty frame was returned in frame.
+ * @param[in] avpkt AVPacket containing the data to be decoded
+ * @return amount of bytes read from the packet on success,
+ * negative error code on failure
+ */
+ int (*decode)(struct AVCodecContext* avctx, struct AVFrame* frame, int* got_frame_ptr,
+ struct AVPacket* avpkt);
+ /**
+ * Decode subtitle data to an AVSubtitle.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_DECODE_SUB.
+ *
+ * Apart from that this is like the decode callback.
+ */
+ int (*decode_sub)(struct AVCodecContext* avctx, struct AVSubtitle* sub, int* got_frame_ptr,
+ const struct AVPacket* avpkt);
+ /**
+ * Decode API with decoupled packet/frame dataflow.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_RECEIVE_FRAME.
+ *
+ * This function is called to get one output frame. It should call
+ * ff_decode_get_packet() to obtain input data.
+ */
+ int (*receive_frame)(struct AVCodecContext* avctx, struct AVFrame* frame);
+ /**
+ * Encode data to an AVPacket.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_ENCODE
+ *
+ * @param avctx codec context
+ * @param[out] avpkt output AVPacket
+ * @param[in] frame AVFrame containing the input to be encoded
+ * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a
+ * non-empty packet was returned in avpkt.
+ * @return 0 on success, negative error code on failure
+ */
+ int (*encode)(struct AVCodecContext* avctx, struct AVPacket* avpkt,
+ const struct AVFrame* frame, int* got_packet_ptr);
+ /**
+ * Encode subtitles to a raw buffer.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_ENCODE_SUB.
+ */
+ int (*encode_sub)(struct AVCodecContext* avctx, uint8_t* buf, int buf_size,
+ const struct AVSubtitle* sub);
+ /**
+ * Encode API with decoupled frame/packet dataflow.
+ * cb is in this state if cb_type is FF_CODEC_CB_TYPE_RECEIVE_PACKET.
+ *
+ * This function is called to get one output packet.
+ * It should call ff_encode_get_frame() to obtain input data.
+ */
+ int (*receive_packet)(struct AVCodecContext* avctx, struct AVPacket* avpkt);
+ } cb;
+
+ int (*close)(struct AVCodecContext*);
+
+ /**
+ * Flush buffers.
+ * Will be called when seeking
+ */
+ void (*flush)(struct AVCodecContext*);
+
+ /**
+ * Decoding only, a comma-separated list of bitstream filters to apply to
+ * packets before decoding.
+ */
+ const char* bsfs;
+
+ /**
+ * Array of pointers to hardware configurations supported by the codec,
+ * or NULL if no hardware supported. The array is terminated by a NULL
+ * pointer.
+ *
+ * The user can only access this field via avcodec_get_hw_config().
+ */
+ const struct AVCodecHWConfigInternal* const* hw_configs;
+
+ /**
+ * List of supported codec_tags, terminated by FF_CODEC_TAGS_END.
+ */
+ const uint32_t* codec_tags;
+} FFCodec;
+
+#ifndef ANDROID
+static av_always_inline const FFCodec* ffcodec(const AVCodec* codec) {
+ return (const FFCodec*)codec;
+}
+#endif
+} // namespace
+
+
bool DecoderContext::SendPacket(const Packet& packet) {
m_temp_frame = std::make_shared<Frame>();
m_got_frame = 0;
@@ -227,8 +395,12 @@ bool DecoderContext::SendPacket(const Packet& packet) {
#ifndef ANDROID
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
m_decode_order = true;
- const int ret = avcodec_send_frame(m_codec_context, m_temp_frame->GetFrame());
- if (ret < 0) {
+ auto* codec{ffcodec(m_decoder.GetCodec())};
+ if (const int ret = codec->cb.decode(m_codec_context,
+ m_temp_frame->GetFrame(),
+ &m_got_frame,
+ packet.GetPacket());
+ ret < 0) {
LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", AVError(ret));
return false;
}
@@ -247,9 +419,11 @@ bool DecoderContext::SendPacket(const Packet& packet) {
std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
// Android can randomly crash when calling decode directly, so skip.
// TODO update ffmpeg and hope that fixes it.
+// TODO: This is causing issues on linux, need to bisect
#ifndef ANDROID
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
m_decode_order = true;
+ auto* codec{ffcodec(m_decoder.GetCodec())};
int ret{0};
if (m_got_frame == 0) {
@@ -257,7 +431,7 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
auto* pkt = packet.GetPacket();
pkt->data = nullptr;
pkt->size = 0;
- ret = avcodec_receive_packet(m_codec_context, pkt);
+ ret = codec->cb.decode(m_codec_context, m_temp_frame->GetFrame(), &m_got_frame, pkt);
m_codec_context->has_b_frames = 0;
}
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 3260ef8cc2..30f5ff7a75 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -1,6 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <algorithm>
#include <array>
#include <cstring>
@@ -99,52 +102,91 @@ Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dl
}
RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window,
- Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
- std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
- : RendererBase(emu_window, std::move(context_)), device_memory(device_memory_), gpu(gpu_),
- library(OpenLibrary(context.get())),
- // Create raw Vulkan instance first
- instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
- Settings::values.renderer_debug.GetValue())),
- // Now create RAII wrappers for the resources in the correct order
- managed_instance(MakeManagedInstance(instance, dld)),
- // Create debug messenger if debug is enabled
- debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
- : vk::DebugUtilsMessenger{}),
- managed_debug_messenger(Settings::values.renderer_debug
- ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld)
- : ManagedDebugUtilsMessenger{}),
- // Create surface
- surface(CreateSurface(instance, render_window.GetWindowInfo())),
- managed_surface(MakeManagedSurface(surface, instance, dld)),
- device(CreateDevice(instance, dld, *surface)),
- memory_allocator(device), state_tracker(),
- scheduler(device, state_tracker),
- swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
- render_window.GetFramebufferLayout().height),
- present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
- *surface),
- blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForDisplay),
- blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForDisplay),
- blit_applet(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForAppletCapture),
- rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
- scheduler),
- applet_frame() {
-
- if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
+ Tegra::MaxwellDeviceMemoryManager& device_memory_,
+ Tegra::GPU& gpu_,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context_)
+try
+ : RendererBase(emu_window, std::move(context_))
+ , device_memory(device_memory_)
+ , gpu(gpu_)
+ , library(OpenLibrary(context.get()))
+ ,
+ // Create raw Vulkan instance first
+ instance(CreateInstance(*library,
+ dld,
+ VK_API_VERSION_1_1,
+ render_window.GetWindowInfo().type,
+ Settings::values.renderer_debug.GetValue()))
+ ,
+ // Now create RAII wrappers for the resources in the correct order
+ managed_instance(MakeManagedInstance(instance, dld))
+ ,
+ // Create debug messenger if debug is enabled
+ debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
+ : vk::DebugUtilsMessenger{})
+ , managed_debug_messenger(Settings::values.renderer_debug
+ ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld)
+ : ManagedDebugUtilsMessenger{})
+ ,
+ // Create surface
+ surface(CreateSurface(instance, render_window.GetWindowInfo()))
+ , managed_surface(MakeManagedSurface(surface, instance, dld))
+ , device(CreateDevice(instance, dld, *surface))
+ , memory_allocator(device)
+ , state_tracker()
+ , scheduler(device, state_tracker)
+ , swapchain(*surface,
+ device,
+ scheduler,
+ render_window.GetFramebufferLayout().width,
+ render_window.GetFramebufferLayout().height)
+ , present_manager(instance,
+ render_window,
+ device,
+ memory_allocator,
+ scheduler,
+ swapchain,
+#ifdef ANDROID
+ surface)
+ ,
+#else
+ *surface)
+ ,
+#endif
+ blit_swapchain(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForDisplay)
+ , blit_capture(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForDisplay)
+ , blit_applet(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForAppletCapture)
+ , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler)
+ , applet_frame() {
+
+ if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
turbo_mode.emplace(instance, dld);
scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
}
+#ifndef ANDROID
// Release ownership from the old instance and surface
instance.release();
surface.release();
if (Settings::values.renderer_debug) {
debug_messenger.release();
}
+#endif
Report();
} catch (const vk::Exception& exception) {
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 8f5edeae24..a448dc5288 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -95,15 +95,31 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form
} // Anonymous namespace
-PresentManager::PresentManager(const vk::Instance& instance_, Core::Frontend::EmuWindow& render_window_,
- const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
- Swapchain& swapchain_, VkSurfaceKHR_T* surface_handle_)
- : instance{instance_}, render_window{render_window_}, device{device_},
- memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
- surface_handle{surface_handle_},
- blit_supported{CanBlitToSwapchain(device.GetPhysical(),
- swapchain.GetImageViewFormat())},
- use_present_thread{Settings::values.async_presentation.GetValue()} {
+PresentManager::PresentManager(const vk::Instance& instance_,
+ Core::Frontend::EmuWindow& render_window_,
+ const Device& device_,
+ MemoryAllocator& memory_allocator_,
+ Scheduler& scheduler_,
+ Swapchain& swapchain_,
+#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()}
+{
SetImageCount();
auto& dld = device.GetLogical();
@@ -289,7 +305,11 @@ void PresentManager::PresentThread(std::stop_token token) {
}
void PresentManager::RecreateSwapchain(Frame* frame) {
+#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();
}
@@ -307,6 +327,9 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
try {
// Recreate surface and swapchain if needed.
if (requires_recreation) {
+#ifdef ANDROID
+ surface = CreateSurface(instance, render_window.GetWindowInfo());
+#endif
RecreateSwapchain(frame);
}
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index 96850ed56f..5820280602 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -37,9 +37,17 @@ struct Frame {
class PresentManager {
public:
- PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window,
- const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
- Swapchain& swapchain, VkSurfaceKHR_T* surface_handle);
+ PresentManager(const vk::Instance& instance,
+ Core::Frontend::EmuWindow& render_window,
+ const Device& device,
+ MemoryAllocator& memory_allocator,
+ Scheduler& scheduler,
+ Swapchain& swapchain,
+#ifdef ANDROID
+ vk::SurfaceKHR& surface);
+#else
+ VkSurfaceKHR_T* surface_handle);
+#endif
~PresentManager();
/// Returns the last used presentation frame
@@ -73,7 +81,11 @@ private:
MemoryAllocator& memory_allocator;
Scheduler& scheduler;
Swapchain& swapchain;
+#ifdef ANDROID
+ vk::SurfaceKHR& surface;
+#else
VkSurfaceKHR_T* surface_handle;
+#endif
vk::CommandPool cmdpool;
std::vector<Frame> frames;
std::queue<Frame*> present_queue;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index a28296bdaf..44c06eddf3 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -176,7 +176,7 @@ public:
PauseCounter();
}
AbandonCurrentQuery();
- std::function<void()> func([this, counts = pending_flush_queries.size()] {
+ std::function<void()> func([this] {
amend_value = 0;
accumulation_value = 0;
});
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index ec96b75036..a002ca83a0 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -105,23 +105,58 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
} // Anonymous namespace
-Swapchain::Swapchain(VkSurfaceKHR_T* surface_handle_, const Device& device_, Scheduler& scheduler_,
- u32 width_, u32 height_)
- : surface_handle{surface_handle_}, device{device_}, scheduler{scheduler_} {
+Swapchain::Swapchain(
+#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_handle_, u32 width_, u32 height_) {
+void Swapchain::Create(
+#ifdef ANDROID
+ VkSurfaceKHR surface_,
+#else
+ VkSurfaceKHR_T* surface_handle_,
+#endif
+ u32 width_,
+ u32 height_)
+{
is_outdated = false;
is_suboptimal = false;
width = width_;
height = height_;
+#ifdef ANDROID
+ surface = surface_;
+#else
surface_handle = surface_handle_;
+#endif
const auto physical_device = device.GetPhysical();
+#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;
}
@@ -199,10 +234,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
const auto physical_device{device.GetPhysical()};
+
+#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);
- has_mailbox = std::find(present_modes.begin(), present_modes.end(),
- VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
+#endif
+
+ has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR)
+ != present_modes.end();
has_imm = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end();
has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(),
@@ -228,7 +270,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
+#ifdef ANDROID
+ .surface = surface,
+#else
.surface = surface_handle,
+#endif
.minImageCount = requested_image_count,
.imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace,
@@ -269,7 +315,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.
+#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);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index f5090c27f4..b3e1c4f025 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -21,12 +21,27 @@ class Scheduler;
class Swapchain {
public:
- explicit Swapchain(VkSurfaceKHR_T* surface_handle, const Device& device, Scheduler& scheduler, u32 width,
- u32 height);
+ explicit Swapchain(
+#ifdef ANDROID
+ VkSurfaceKHR surface,
+#else
+ VkSurfaceKHR_T* surface_handle,
+#endif
+ const Device& device,
+ Scheduler& scheduler,
+ u32 width,
+ u32 height);
~Swapchain();
/// Creates (or recreates) the swapchain with a given size.
- void Create(VkSurfaceKHR_T* surface_handle, u32 width, u32 height);
+ void Create(
+#ifdef ANDROID
+ VkSurfaceKHR surface,
+#else
+ VkSurfaceKHR_T* surface_handle,
+#endif
+ u32 width,
+ u32 height);
/// Acquires the next image in the swapchain, waits as needed.
bool AcquireNextImage();
@@ -110,7 +125,12 @@ private:
bool NeedsPresentModeUpdate() const;
+#ifdef ANDROID
+ VkSurfaceKHR surface;
+#else
VkSurfaceKHR_T* surface_handle;
+#endif
+
const Device& device;
Scheduler& scheduler;
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index aa9fb8e17b..4607bf516c 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -430,6 +430,7 @@ public:
return handle != nullptr;
}
+#ifndef ANDROID
/**
* Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle.
@@ -438,6 +439,7 @@ public:
Type release() noexcept {
return std::exchange(handle, nullptr);
}
+#endif
protected:
Type handle = nullptr;
@@ -510,6 +512,7 @@ public:
return handle != nullptr;
}
+#ifndef ANDROID
/**
* Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle.
@@ -518,6 +521,7 @@ public:
Type release() noexcept {
return std::exchange(handle, nullptr);
}
+#endif
protected:
Type handle = nullptr;