mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-03-30 07:59:42 -06:00
libretro: draw cursor in vulkan
This commit is contained in:
parent
0407568006
commit
3a5fa35449
@ -626,6 +626,7 @@ bool retro_load_game(const struct retro_game_info* info) {
|
||||
#endif
|
||||
break;
|
||||
case Settings::GraphicsAPI::Software:
|
||||
emu_instance->emu_window->CreateContext();
|
||||
emu_instance->game_loaded = do_load_game();
|
||||
if (!emu_instance->game_loaded)
|
||||
return false;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
#include "audio_core/audio_types.h"
|
||||
#include "citra_libretro/citra_libretro.h"
|
||||
#include "citra_libretro/core_settings.h"
|
||||
#include "citra_libretro/environment.h"
|
||||
#include "citra_libretro/input/input_factory.h"
|
||||
#include "common/settings.h"
|
||||
@ -85,9 +86,7 @@ void EmuWindow_LibRetro::SwapBuffers() {
|
||||
}
|
||||
case Settings::GraphicsAPI::Vulkan: {
|
||||
#ifdef ENABLE_VULKAN
|
||||
if (enableEmulatedPointer && tracker) {
|
||||
tracker->Render(width, height);
|
||||
}
|
||||
// Cursor is drawn inside the Vulkan render pass (RendererVulkan::DrawCursor)
|
||||
LibRetro::UploadVideoFrame(RETRO_HW_FRAME_BUFFER_VALID, static_cast<unsigned>(width),
|
||||
static_cast<unsigned>(height), 0);
|
||||
#endif
|
||||
@ -340,3 +339,10 @@ void EmuWindow_LibRetro::CreateContext() {
|
||||
void EmuWindow_LibRetro::DestroyContext() {
|
||||
tracker = nullptr;
|
||||
}
|
||||
|
||||
Frontend::EmuWindow::CursorInfo EmuWindow_LibRetro::GetCursorInfo() const {
|
||||
if (enableEmulatedPointer && tracker && LibRetro::settings.render_touchscreen) {
|
||||
return tracker->GetCursorInfo();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -57,6 +57,9 @@ public:
|
||||
/// When true, SwapBuffers() is suppressed (used during savestate drain loops)
|
||||
bool suppressPresentation = false;
|
||||
|
||||
/// Get cursor state for rendering a touch crosshair on the bottom screen.
|
||||
CursorInfo GetCursorInfo() const override;
|
||||
|
||||
private:
|
||||
/// Called when a configuration change affects the minimal size of the window
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||
|
||||
@ -219,17 +219,9 @@ void MouseTracker::Update(int bufferWidth, int bufferHeight,
|
||||
|
||||
Restrict(0, 0, layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight());
|
||||
|
||||
// Make the coordinates 0 -> 1
|
||||
projectedX = (float)x / layout.bottom_screen.GetWidth();
|
||||
projectedY = (float)y / layout.bottom_screen.GetHeight();
|
||||
|
||||
// Ensure that the projected position doesn't overlap outside the bottom screen framebuffer.
|
||||
// TODO: Provide config option
|
||||
renderRatio = (float)layout.bottom_screen.GetHeight() / 30;
|
||||
|
||||
// Map the mouse coord to the bottom screen's position
|
||||
projectedX = layout.bottom_screen.left + projectedX * layout.bottom_screen.GetWidth();
|
||||
projectedY = layout.bottom_screen.top + projectedY * layout.bottom_screen.GetHeight();
|
||||
// Store as bottom-screen-local pixel coordinates
|
||||
projectedX = static_cast<float>(x);
|
||||
projectedY = static_cast<float>(y);
|
||||
|
||||
isPressed = state;
|
||||
|
||||
@ -241,10 +233,15 @@ void MouseTracker::Render(int bufferWidth, int bufferHeight, void* framebuffer_d
|
||||
return;
|
||||
}
|
||||
|
||||
// Delegate to renderer-specific implementation
|
||||
// Delegate to renderer-specific implementation.
|
||||
// Convert from bottom-screen-local to layout-absolute for the legacy renderers.
|
||||
if (cursor_renderer) {
|
||||
cursor_renderer->Render(bufferWidth, bufferHeight, projectedX, projectedY, renderRatio,
|
||||
framebuffer_layout, framebuffer_data);
|
||||
const float abs_x = framebuffer_layout.bottom_screen.left + projectedX;
|
||||
const float abs_y = framebuffer_layout.bottom_screen.top + projectedY;
|
||||
const float ratio =
|
||||
static_cast<float>(framebuffer_layout.bottom_screen.GetHeight()) / 30.0f;
|
||||
cursor_renderer->Render(bufferWidth, bufferHeight, abs_x, abs_y, ratio, framebuffer_layout,
|
||||
framebuffer_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,30 +346,12 @@ void OpenGLCursorRenderer::Render(int bufferWidth, int bufferHeight, float proje
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
// Vulkan-specific cursor renderer implementation
|
||||
VulkanCursorRenderer::VulkanCursorRenderer() {
|
||||
// Vulkan cursor rendering will be integrated into the main rendering pipeline
|
||||
}
|
||||
|
||||
// Vulkan cursor is drawn by RendererVulkan::DrawCursor() inside the render pass.
|
||||
// This class exists only to satisfy the CursorRenderer interface.
|
||||
VulkanCursorRenderer::VulkanCursorRenderer() = default;
|
||||
VulkanCursorRenderer::~VulkanCursorRenderer() = default;
|
||||
|
||||
void VulkanCursorRenderer::Render(int bufferWidth, int bufferHeight, float projectedX,
|
||||
float projectedY, float renderRatio,
|
||||
const Layout::FramebufferLayout& layout, void* framebuffer_data) {
|
||||
// Use shared coordinate calculation
|
||||
CursorCoordinates coords(bufferWidth, bufferHeight, projectedX, projectedY, renderRatio,
|
||||
layout);
|
||||
|
||||
// TODO: Implement actual Vulkan cursor drawing using the renderer's command buffer
|
||||
// This would involve:
|
||||
// 1. Creating a simple vertex buffer with cursor geometry using coords
|
||||
// 2. Using a basic shader pipeline
|
||||
// 3. Recording draw commands into the current command buffer
|
||||
// 4. Using blend mode similar to OpenGL (ONE_MINUS_DST_COLOR, ONE_MINUS_SRC_COLOR)
|
||||
|
||||
// For now, this is a placeholder - the cursor won't be visible in Vulkan mode
|
||||
// but the touchscreen input will still work
|
||||
}
|
||||
void VulkanCursorRenderer::Render(int, int, float, float, float, const Layout::FramebufferLayout&,
|
||||
void*) {}
|
||||
#endif
|
||||
|
||||
// Software-specific cursor renderer implementation
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
@ -47,10 +48,15 @@ public:
|
||||
return isPressed;
|
||||
}
|
||||
|
||||
/// Get the pressed position, relative to the framebuffer.
|
||||
/// Get the pressed position in layout-absolute coordinates.
|
||||
std::pair<unsigned, unsigned> GetPressedPosition() {
|
||||
return {static_cast<const unsigned int&>(projectedX),
|
||||
static_cast<const unsigned int&>(projectedY)};
|
||||
return {static_cast<unsigned>(framebuffer_layout.bottom_screen.left + projectedX),
|
||||
static_cast<unsigned>(framebuffer_layout.bottom_screen.top + projectedY)};
|
||||
}
|
||||
|
||||
/// Get cursor rendering state for external renderers (e.g. Vulkan).
|
||||
Frontend::EmuWindow::CursorInfo GetCursorInfo() const {
|
||||
return {true, projectedX, projectedY};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -62,7 +68,6 @@ private:
|
||||
|
||||
float projectedX;
|
||||
float projectedY;
|
||||
float renderRatio;
|
||||
|
||||
bool isPressed;
|
||||
|
||||
|
||||
@ -269,6 +269,23 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Cursor state for rendering a touch crosshair on the bottom screen.
|
||||
struct CursorInfo {
|
||||
bool visible = false;
|
||||
|
||||
/// Cursor position in bottom-screen-local pixel coordinates.
|
||||
/// Origin is the top-left corner of the bottom screen, with x ranging
|
||||
/// from 0 to bottom_screen.GetWidth() and y from 0 to
|
||||
/// bottom_screen.GetHeight().
|
||||
float projected_x = 0;
|
||||
float projected_y = 0;
|
||||
};
|
||||
|
||||
/// Returns the current cursor state. Override to provide cursor position.
|
||||
virtual CursorInfo GetCursorInfo() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
Settings::StereoRenderOption get3DMode() const;
|
||||
|
||||
protected:
|
||||
|
||||
@ -24,6 +24,8 @@ set(SHADER_FILES
|
||||
vulkan_present_anaglyph.frag
|
||||
vulkan_present_interlaced.frag
|
||||
vulkan_blit_depth_stencil.frag
|
||||
vulkan_cursor.frag
|
||||
vulkan_cursor.vert
|
||||
)
|
||||
|
||||
set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
|
||||
|
||||
12
src/video_core/host_shaders/vulkan_cursor.frag
Normal file
12
src/video_core/host_shaders/vulkan_cursor.frag
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#version 450 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout (location = 0) out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
12
src/video_core/host_shaders/vulkan_cursor.vert
Normal file
12
src/video_core/host_shaders/vulkan_cursor.vert
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#version 450 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout (location = 0) in vec2 vert_position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vert_position, 0.0, 1.0);
|
||||
}
|
||||
@ -20,6 +20,9 @@
|
||||
#include "video_core/host_shaders/vulkan_present_interlaced_frag.h"
|
||||
#include "video_core/host_shaders/vulkan_present_vert.h"
|
||||
|
||||
#include "video_core/host_shaders/vulkan_cursor_frag.h"
|
||||
#include "video_core/host_shaders/vulkan_cursor_vert.h"
|
||||
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#if defined(__APPLE__) && !defined(HAVE_LIBRETRO)
|
||||
@ -153,6 +156,10 @@ RendererVulkan::~RendererVulkan() {
|
||||
device.destroyImageView(info.texture.image_view);
|
||||
vmaDestroyImage(instance.GetAllocator(), info.texture.image, info.texture.allocation);
|
||||
}
|
||||
|
||||
device.destroyPipeline(cursor_pipeline);
|
||||
device.destroyShaderModule(cursor_vertex_shader);
|
||||
device.destroyShaderModule(cursor_fragment_shader);
|
||||
}
|
||||
|
||||
void RendererVulkan::PrepareRendertarget() {
|
||||
@ -294,6 +301,11 @@ void RendererVulkan::CompileShaders() {
|
||||
present_shaders[2] = Compile(HostShaders::VULKAN_PRESENT_INTERLACED_FRAG,
|
||||
vk::ShaderStageFlagBits::eFragment, device, preamble);
|
||||
|
||||
cursor_vertex_shader =
|
||||
Compile(HostShaders::VULKAN_CURSOR_VERT, vk::ShaderStageFlagBits::eVertex, device);
|
||||
cursor_fragment_shader =
|
||||
Compile(HostShaders::VULKAN_CURSOR_FRAG, vk::ShaderStageFlagBits::eFragment, device);
|
||||
|
||||
auto properties = instance.GetPhysicalDevice().getProperties();
|
||||
for (std::size_t i = 0; i < present_samplers.size(); i++) {
|
||||
const vk::Filter filter_mode = i == 0 ? vk::Filter::eLinear : vk::Filter::eNearest;
|
||||
@ -330,6 +342,9 @@ void RendererVulkan::BuildLayouts() {
|
||||
.pPushConstantRanges = &push_range,
|
||||
};
|
||||
present_pipeline_layout = instance.GetDevice().createPipelineLayoutUnique(layout_info);
|
||||
|
||||
const vk::PipelineLayoutCreateInfo cursor_layout_info = {};
|
||||
cursor_pipeline_layout = instance.GetDevice().createPipelineLayoutUnique(cursor_layout_info);
|
||||
}
|
||||
|
||||
void RendererVulkan::BuildPipelines() {
|
||||
@ -460,6 +475,126 @@ void RendererVulkan::BuildPipelines() {
|
||||
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build present pipelines");
|
||||
present_pipelines[i] = pipeline;
|
||||
}
|
||||
|
||||
// Build cursor pipeline (simple position-only, inverted color blending)
|
||||
{
|
||||
const vk::VertexInputBindingDescription cursor_binding = {
|
||||
.binding = 0,
|
||||
.stride = sizeof(float) * 2,
|
||||
.inputRate = vk::VertexInputRate::eVertex,
|
||||
};
|
||||
|
||||
const vk::VertexInputAttributeDescription cursor_attribute = {
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = vk::Format::eR32G32Sfloat,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
const vk::PipelineVertexInputStateCreateInfo cursor_vertex_input = {
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &cursor_binding,
|
||||
.vertexAttributeDescriptionCount = 1,
|
||||
.pVertexAttributeDescriptions = &cursor_attribute,
|
||||
};
|
||||
|
||||
const vk::PipelineInputAssemblyStateCreateInfo cursor_input_assembly = {
|
||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||
.primitiveRestartEnable = false,
|
||||
};
|
||||
|
||||
const vk::PipelineRasterizationStateCreateInfo cursor_raster = {
|
||||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.cullMode = vk::CullModeFlagBits::eNone,
|
||||
.frontFace = vk::FrontFace::eClockwise,
|
||||
.depthBiasEnable = false,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
const vk::PipelineMultisampleStateCreateInfo cursor_multisample = {
|
||||
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
||||
.sampleShadingEnable = false,
|
||||
};
|
||||
|
||||
const vk::PipelineColorBlendAttachmentState cursor_blend_attachment = {
|
||||
.blendEnable = true,
|
||||
.srcColorBlendFactor = vk::BlendFactor::eOneMinusDstColor,
|
||||
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor,
|
||||
.colorBlendOp = vk::BlendOp::eAdd,
|
||||
.srcAlphaBlendFactor = vk::BlendFactor::eOne,
|
||||
.dstAlphaBlendFactor = vk::BlendFactor::eZero,
|
||||
.alphaBlendOp = vk::BlendOp::eAdd,
|
||||
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||
};
|
||||
|
||||
const vk::PipelineColorBlendStateCreateInfo cursor_color_blending = {
|
||||
.logicOpEnable = false,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &cursor_blend_attachment,
|
||||
};
|
||||
|
||||
const vk::Viewport placeholder_vp = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
|
||||
const vk::Rect2D placeholder_sc = {{0, 0}, {1, 1}};
|
||||
const vk::PipelineViewportStateCreateInfo cursor_viewport = {
|
||||
.viewportCount = 1,
|
||||
.pViewports = &placeholder_vp,
|
||||
.scissorCount = 1,
|
||||
.pScissors = &placeholder_sc,
|
||||
};
|
||||
|
||||
const std::array cursor_dynamic_states = {
|
||||
vk::DynamicState::eViewport,
|
||||
vk::DynamicState::eScissor,
|
||||
};
|
||||
|
||||
const vk::PipelineDynamicStateCreateInfo cursor_dynamic = {
|
||||
.dynamicStateCount = static_cast<u32>(cursor_dynamic_states.size()),
|
||||
.pDynamicStates = cursor_dynamic_states.data(),
|
||||
};
|
||||
|
||||
const vk::PipelineDepthStencilStateCreateInfo cursor_depth = {
|
||||
.depthTestEnable = false,
|
||||
.depthWriteEnable = false,
|
||||
.depthCompareOp = vk::CompareOp::eAlways,
|
||||
.depthBoundsTestEnable = false,
|
||||
.stencilTestEnable = false,
|
||||
};
|
||||
|
||||
const std::array cursor_shader_stages = {
|
||||
vk::PipelineShaderStageCreateInfo{
|
||||
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||
.module = cursor_vertex_shader,
|
||||
.pName = "main",
|
||||
},
|
||||
vk::PipelineShaderStageCreateInfo{
|
||||
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||
.module = cursor_fragment_shader,
|
||||
.pName = "main",
|
||||
},
|
||||
};
|
||||
|
||||
const vk::GraphicsPipelineCreateInfo cursor_pipeline_info = {
|
||||
.stageCount = static_cast<u32>(cursor_shader_stages.size()),
|
||||
.pStages = cursor_shader_stages.data(),
|
||||
.pVertexInputState = &cursor_vertex_input,
|
||||
.pInputAssemblyState = &cursor_input_assembly,
|
||||
.pViewportState = &cursor_viewport,
|
||||
.pRasterizationState = &cursor_raster,
|
||||
.pMultisampleState = &cursor_multisample,
|
||||
.pDepthStencilState = &cursor_depth,
|
||||
.pColorBlendState = &cursor_color_blending,
|
||||
.pDynamicState = &cursor_dynamic,
|
||||
.layout = *cursor_pipeline_layout,
|
||||
.renderPass = main_present_window.Renderpass(),
|
||||
};
|
||||
|
||||
const auto [result, pipeline] =
|
||||
instance.GetDevice().createGraphicsPipeline({}, cursor_pipeline_info);
|
||||
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build cursor pipeline");
|
||||
cursor_pipeline = pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
@ -909,9 +1044,71 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
|
||||
}
|
||||
}
|
||||
|
||||
DrawCursor(layout);
|
||||
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.endRenderPass(); });
|
||||
}
|
||||
|
||||
void RendererVulkan::DrawCursor(const Layout::FramebufferLayout& layout) {
|
||||
const auto cursor = render_window.GetCursorInfo();
|
||||
if (!cursor.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float buf_w = static_cast<float>(layout.width);
|
||||
const float buf_h = static_cast<float>(layout.height);
|
||||
|
||||
// Convert from bottom-screen-local to layout-absolute, then to NDC
|
||||
const float abs_x = layout.bottom_screen.left + cursor.projected_x;
|
||||
const float abs_y = layout.bottom_screen.top + cursor.projected_y;
|
||||
const float cx = (abs_x / buf_w) * 2.0f - 1.0f;
|
||||
const float cy = (abs_y / buf_h) * 2.0f - 1.0f;
|
||||
const float ratio = static_cast<float>(layout.bottom_screen.GetHeight()) / 30.0f;
|
||||
const float rw = ratio / buf_w;
|
||||
const float rh = ratio / buf_h;
|
||||
|
||||
// Bottom screen bounds in NDC
|
||||
const float bl = (layout.bottom_screen.left / buf_w) * 2.0f - 1.0f;
|
||||
const float bt = (layout.bottom_screen.top / buf_h) * 2.0f - 1.0f;
|
||||
const float br = (layout.bottom_screen.right / buf_w) * 2.0f - 1.0f;
|
||||
const float bb = (layout.bottom_screen.bottom / buf_h) * 2.0f - 1.0f;
|
||||
|
||||
// Crosshair geometry clamped to bottom screen bounds
|
||||
const float vl = std::fmax(cx - rw / 5.0f, bl);
|
||||
const float vr = std::fmin(cx + rw / 5.0f, br);
|
||||
const float vt = std::fmax(cy - rh, bt);
|
||||
const float vb = std::fmin(cy + rh, bb);
|
||||
|
||||
const float hl = std::fmax(cx - rw, bl);
|
||||
const float hr = std::fmin(cx + rw, br);
|
||||
const float ht = std::fmax(cy - rh / 5.0f, bt);
|
||||
const float hb = std::fmin(cy + rh / 5.0f, bb);
|
||||
|
||||
// 12 vertices = 4 triangles (2 for vertical bar, 2 for horizontal bar)
|
||||
// clang-format off
|
||||
const float vertices[] = {
|
||||
// Vertical bar
|
||||
vl, vt, vr, vt, vr, vb,
|
||||
vl, vt, vr, vb, vl, vb,
|
||||
// Horizontal bar
|
||||
hl, ht, hr, ht, hr, hb,
|
||||
hl, ht, hr, hb, hl, hb,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const u64 size = sizeof(vertices);
|
||||
auto [data, offset, invalidate] = vertex_buffer.Map(size, 16);
|
||||
std::memcpy(data, vertices, size);
|
||||
vertex_buffer.Commit(size);
|
||||
|
||||
scheduler.Record([this, offset = offset, pipeline = cursor_pipeline](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
||||
cmdbuf.bindVertexBuffers(0, vertex_buffer.Handle(), {0});
|
||||
const u32 first_vertex = static_cast<u32>(offset) / (sizeof(float) * 2);
|
||||
cmdbuf.draw(12, 1, first_vertex, 0);
|
||||
});
|
||||
}
|
||||
|
||||
void RendererVulkan::SwapBuffers() {
|
||||
system.perf_stats->StartSwap();
|
||||
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
|
||||
|
||||
@ -112,6 +112,8 @@ private:
|
||||
|
||||
void ApplySecondLayerOpacity(float alpha);
|
||||
|
||||
void DrawCursor(const Layout::FramebufferLayout& layout);
|
||||
|
||||
void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info,
|
||||
bool right_eye);
|
||||
void FillScreen(Common::Vec3<u8> color, const TextureInfo& texture);
|
||||
@ -144,6 +146,11 @@ private:
|
||||
std::array<ScreenInfo, 3> screen_infos{};
|
||||
PresentUniformData draw_info{};
|
||||
vk::ClearColorValue clear_color{};
|
||||
|
||||
vk::ShaderModule cursor_vertex_shader{};
|
||||
vk::ShaderModule cursor_fragment_shader{};
|
||||
vk::Pipeline cursor_pipeline{};
|
||||
vk::UniquePipelineLayout cursor_pipeline_layout{};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Loading…
Reference in New Issue
Block a user