mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-06-23 11:39:29 -04:00
* libretro core * Bringing citra libretro implementation over * libretro: hook up vulkan renderer * libretro: github actions * libretro: gyro * libretro: core options v2 * libretro: on ios turn off shader jit if unavailable * moltenvk 1.3.0 introduces 8-bit indexes but allocates 16-bit for metal; this ends up allocating stream buffer * 2 = 132MiB. Instead, just use 16-bit indexes. (This will be necessary for standalone when bumping moltenvk version.) * libretro core: address review feedback * libretro: microphone support * cmake: Add ENABLE_ROOM_STANDALONE to list of incompatible libretro flags * libretro: proper initial geometry * libretro: fix software renderer * libretro: address review feedback * .github/libretro.yml: Pin macOS runners at macOS 26 * ci: Remove explicit selection of Xcode 16.0 * .github/libretro.yml: remove unnecessary windows builder apt commands * .github/libretro.yml: bump min macos version to 11.0 * ci: Re-enable CI jobs for all libretro cores This is under the condition that we don't introduce build cache for these builds --------- Co-authored-by: OpenSauce04 <opensauce04@gmail.com> Co-authored-by: PabloMK7 <hackyglitch2@gmail.com>
175 lines
5.2 KiB
C++
175 lines
5.2 KiB
C++
// Copyright Citra Emulator Project / Azahar Emulator Project
|
|
// Licensed under GPLv2 or any later version
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <variant>
|
|
#include <fmt/format.h>
|
|
|
|
#include "common/common_types.h"
|
|
#include "common/dynamic_library/dynamic_library.h"
|
|
#include "video_core/renderer_vulkan/vk_common.h"
|
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
|
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
|
|
|
#include "libretro_vulkan.h"
|
|
|
|
VK_DEFINE_HANDLE(VmaAllocation)
|
|
|
|
namespace LibRetro {
|
|
|
|
extern void VulkanResetContext();
|
|
|
|
/// Returns VkApplicationInfo for negotiation interface
|
|
const VkApplicationInfo* GetVulkanApplicationInfo();
|
|
|
|
/// CreateDevice callback for negotiation interface
|
|
bool CreateVulkanDevice(struct retro_vulkan_context* context, VkInstance instance,
|
|
VkPhysicalDevice gpu, VkSurfaceKHR surface,
|
|
PFN_vkGetInstanceProcAddr get_instance_proc_addr,
|
|
const char** required_device_extensions,
|
|
unsigned num_required_device_extensions,
|
|
const char** required_device_layers, unsigned num_required_device_layers,
|
|
const VkPhysicalDeviceFeatures* required_features);
|
|
|
|
} // namespace LibRetro
|
|
|
|
namespace Vulkan {
|
|
|
|
class LibRetroVKInstance : public Instance {
|
|
public:
|
|
explicit LibRetroVKInstance(Frontend::EmuWindow& window, u32 physical_device_index);
|
|
|
|
/// Returns the Vulkan instance
|
|
vk::Instance GetInstance() const override;
|
|
|
|
/// Returns the Vulkan device
|
|
vk::Device GetDevice() const override;
|
|
};
|
|
|
|
class Scheduler;
|
|
class RenderManager;
|
|
class MasterSemaphore;
|
|
|
|
/// LibRetro-specific MasterSemaphore implementation
|
|
class MasterSemaphoreLibRetro : public MasterSemaphore {
|
|
using Waitable = std::pair<vk::Fence, u64>;
|
|
|
|
public:
|
|
explicit MasterSemaphoreLibRetro(const Instance& instance);
|
|
~MasterSemaphoreLibRetro() override;
|
|
|
|
void Refresh() override;
|
|
void Wait(u64 tick) override;
|
|
void SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, vk::Semaphore signal,
|
|
u64 signal_value) override;
|
|
|
|
private:
|
|
void WaitThread(std::stop_token token);
|
|
vk::Fence GetFreeFence();
|
|
|
|
const Instance& instance;
|
|
std::deque<vk::Fence> free_queue;
|
|
std::queue<Waitable> wait_queue;
|
|
std::mutex free_mutex;
|
|
std::mutex wait_mutex;
|
|
std::condition_variable free_cv;
|
|
std::condition_variable_any wait_cv;
|
|
std::jthread wait_thread;
|
|
};
|
|
|
|
/// Factory function for scheduler to create LibRetro MasterSemaphore
|
|
std::unique_ptr<MasterSemaphore> CreateLibRetroMasterSemaphore(const Instance& instance);
|
|
|
|
struct Frame {
|
|
u32 width;
|
|
u32 height;
|
|
VmaAllocation allocation;
|
|
vk::Framebuffer framebuffer;
|
|
vk::Image image;
|
|
vk::ImageView image_view;
|
|
vk::Semaphore render_ready;
|
|
vk::Fence present_done;
|
|
vk::CommandBuffer cmdbuf;
|
|
};
|
|
|
|
/// LibRetro-specific PresentWindow implementation (same interface as desktop version)
|
|
class PresentWindow final {
|
|
public:
|
|
explicit PresentWindow(Frontend::EmuWindow& emu_window, const Instance& instance,
|
|
Scheduler& scheduler, bool low_refresh_rate);
|
|
~PresentWindow();
|
|
|
|
/// Waits for all queued frames to finish presenting.
|
|
void WaitPresent();
|
|
|
|
/// Returns the last used render frame.
|
|
Frame* GetRenderFrame();
|
|
|
|
/// Recreates the render frame to match provided parameters.
|
|
void RecreateFrame(Frame* frame, u32 width, u32 height);
|
|
|
|
/// Queues the provided frame for presentation.
|
|
void Present(Frame* frame);
|
|
|
|
/// This is called to notify the rendering backend of a surface change
|
|
void NotifySurfaceChanged();
|
|
|
|
[[nodiscard]] vk::RenderPass Renderpass() const noexcept {
|
|
return present_renderpass;
|
|
}
|
|
|
|
u32 ImageCount() const noexcept {
|
|
return static_cast<u32>(frame_pool.size());
|
|
}
|
|
|
|
private:
|
|
/// Creates the render pass for LibRetro output
|
|
vk::RenderPass CreateRenderpass();
|
|
|
|
/// Creates output texture for LibRetro submission
|
|
void CreateOutputTexture(u32 width, u32 height);
|
|
|
|
/// Destroys current output texture
|
|
void DestroyOutputTexture();
|
|
|
|
/// Creates frame resources
|
|
void CreateFrameResources();
|
|
|
|
/// Destroys frame resources
|
|
void DestroyFrameResources();
|
|
|
|
private:
|
|
Frontend::EmuWindow& emu_window;
|
|
const Instance& instance;
|
|
[[maybe_unused]] Scheduler& scheduler;
|
|
|
|
// LibRetro output texture (replaces swapchain)
|
|
vk::Image output_image{};
|
|
vk::ImageView output_image_view{};
|
|
VmaAllocation output_allocation{};
|
|
vk::Format output_format{vk::Format::eR8G8B8A8Unorm};
|
|
vk::ImageViewCreateInfo output_view_create_info{};
|
|
|
|
// Frame management
|
|
vk::RenderPass present_renderpass{};
|
|
vk::CommandPool command_pool{};
|
|
std::vector<Frame> frame_pool;
|
|
u32 current_frame_index{0};
|
|
|
|
// Current output dimensions
|
|
u32 output_width{0};
|
|
u32 output_height{0};
|
|
|
|
// Vulkan objects
|
|
vk::Queue graphics_queue{};
|
|
|
|
// Persistent LibRetro image descriptor, must persist across frames for RetroArch frame duping
|
|
// during pause
|
|
retro_vulkan_image persistent_libretro_image{};
|
|
};
|
|
|
|
} // namespace Vulkan
|