setting up vulkan part 4

This commit is contained in:
KojoZero 2026-05-12 03:01:21 -07:00
parent e2c3e2819c
commit 3308763c7d
2 changed files with 129 additions and 43 deletions

View file

@ -171,6 +171,12 @@ RendererVulkan::~RendererVulkan() {
device.destroyShaderModule(present_shaders[i]);
}
for (u32 i = 0; i < POST_PIPELINES; i++) {
device.destroyPipeline(post_pipelines[i]);
device.destroyShaderModule(post_vert_shaders[i]);
device.destroyShaderModule(post_frag_shaders[i]);
}
for (auto& sampler : present_samplers) {
device.destroySampler(sampler);
}
@ -330,21 +336,21 @@ void RendererVulkan::CompileShaders() {
Compile(HostShaders::VULKAN_CURSOR_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// Simple Present Shader
simplepresent_vertex_shader =
post_vert_shaders[0] =
Compile(HostShaders::VULKAN_SIMPLE_PRESENT_VERT, vk::ShaderStageFlagBits::eVertex, device);
simplepresent_frag_shader =
post_frag_shaders[0] =
Compile(HostShaders::VULKAN_SIMPLE_PRESENT_FRAG, vk::ShaderStageFlagBits::eFragment, device, preamble);
// Area Sampling Shader
area_sampling_vertex_shader =
post_vert_shaders[1] =
Compile(HostShaders::VULKAN_AREA_SAMPLING_VERT, vk::ShaderStageFlagBits::eVertex, device);
area_sampling_frag_shader =
post_frag_shaders[1] =
Compile(HostShaders::VULKAN_AREA_SAMPLING_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// FXAA Shader
fxaa_vertex_shader =
post_vert_shaders[2] =
Compile(HostShaders::VULKAN_FXAA_VERT, vk::ShaderStageFlagBits::eVertex, device);
fxaa_frag_shader =
post_frag_shaders[2] =
Compile(HostShaders::VULKAN_FXAA_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 0 Shader
@ -354,9 +360,9 @@ void RendererVulkan::CompileShaders() {
std::string smaa_pass_0_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS0_PRE_FRAG);
smaa_pass_0_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_0_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS0_POST_FRAG);
smaa_pass_0_vertex_shader =
post_vert_shaders[3] =
Compile(smaa_pass_0_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
smaa_pass_0_frag_shader =
post_frag_shaders[3] =
Compile(smaa_pass_0_shader_frag_data, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 1 Shader
@ -366,9 +372,9 @@ void RendererVulkan::CompileShaders() {
std::string smaa_pass_1_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS1_PRE_FRAG);
smaa_pass_1_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_1_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS1_POST_FRAG);
smaa_pass_1_vertex_shader =
post_vert_shaders[4] =
Compile(smaa_pass_1_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
smaa_pass_1_frag_shader =
post_frag_shaders[4] =
Compile(smaa_pass_1_shader_frag_data, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 2 Shader
@ -378,11 +384,12 @@ void RendererVulkan::CompileShaders() {
std::string smaa_pass_2_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS2_PRE_FRAG);
smaa_pass_2_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_2_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS2_POST_FRAG);
smaa_pass_2_vertex_shader =
post_vert_shaders[5] =
Compile(smaa_pass_2_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
smaa_pass_2_frag_shader =
post_frag_shaders[5] =
Compile(smaa_pass_2_shader_frag_data, 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;
@ -553,6 +560,42 @@ void RendererVulkan::BuildPipelines() {
present_pipelines[i] = pipeline;
}
// Build Post Proccessing Pipelines
for (u32 i = 0; i < POST_PIPELINES; i++) {
const std::array shader_stages = {
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eVertex,
.module = post_vert_shaders[i],
.pName = "main",
},
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eFragment,
.module = post_frag_shaders[i],
.pName = "main",
},
};
const vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_info,
.pInputAssemblyState = &input_assembly,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_state,
.pMultisampleState = &multisampling,
.pDepthStencilState = &depth_info,
.pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info,
.layout = *present_pipeline_layout,
.renderPass = main_present_window.Renderpass(),
};
const auto [result, pipeline] =
instance.GetDevice().createGraphicsPipeline({}, pipeline_info);
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build present pipelines");
post_pipelines[i] = pipeline;
}
// Build cursor pipeline (simple position-only, inverted color blending)
{
const vk::VertexInputBindingDescription cursor_binding = {
@ -807,64 +850,103 @@ void RendererVulkan::ReloadPipeline(Settings::StereoRenderOption render_3d) {
}
}
void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w, float h,
void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float screenTop, float screenWidth, float screenHeight,
Layout::DisplayOrientation orientation) {
const ScreenInfo& screen_info = screen_infos[screen_id];
const auto& texcoords = screen_info.texcoords;
std::array<ScreenRectVertex, 4> vertices;
const u32 scale_factor = GetResolutionScaleFactor();
float textureWidth = static_cast<float>(screen_info.texture.height * scale_factor);
float textureHeight = static_cast<float>(screen_info.texture.width * scale_factor);
// Texture Width and Height when correctly rotated to landscape
bool isDownsampling = false;
int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is High Quality Scaling (Upsampling via Gamma Corrected Bilinear, Downsampling is Gamma Corrected Area Sampling)
if (Settings::values.filter_mode.GetValue()){
scalingMode = 2;
} else {
scalingMode = 0;
}
int antialiasingMode = static_cast<int>(Settings::values.antialiasing_filter.GetValue()); //0 is none, 1 is FXAA, 2 is SMAA
if (orientation == Layout::DisplayOrientation::Landscape || orientation == Layout::DisplayOrientation::LandscapeFlipped) {
if (textureWidth > screenWidth){
isDownsampling = true;
}
} else {
if (textureWidth > screenHeight){
isDownsampling = true;
}
}
// Rotate Internal Texture to Landscape (The 3DS stores images rotated 90° internally)
std::array<ScreenRectVertex, 4> rotate_vertices;
rotate_vertices = {{
ScreenRectVertex(-1.f, 1.f, texcoords.bottom, texcoords.left), //Left, Top
ScreenRectVertex(1.f, 1.f, texcoords.bottom, texcoords.right), //Right, Top
ScreenRectVertex(-1.f, -1.f, texcoords.top, texcoords.left), //Left, Bottom
ScreenRectVertex(1.f, -1.f, texcoords.top, texcoords.right), //Right, Bottom
}};
// Vertices for 1:1 Texture Mapping.
std::array<ScreenRectVertex, 4> pass_through_vertices;
pass_through_vertices = {{
ScreenRectVertex(-1.f, 1.f, 0.f, 1.f), //Left, Top
ScreenRectVertex(1.f, 1.f, 1.f, 1.f), //Right, Top
ScreenRectVertex(-1.f, -1.f, 0.f, 0.f), //Left, Bottom
ScreenRectVertex(1.f, -1.f, 1.f, 0.f), //Right, Bottom
}};
// Vertices for Azahar's Output Layout
std::array<ScreenRectVertex, 4> output_vertices;
switch (orientation) {
case Layout::DisplayOrientation::Landscape:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f), //Right, Bottom
}};
break;
case Layout::DisplayOrientation::Portrait:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 1.f, 1.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 0.f, 0.f), //Right, Bottom
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
case Layout::DisplayOrientation::LandscapeFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left),
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom
}};
break;
case Layout::DisplayOrientation::PortraitFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.right),
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 0.f, 1.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 1.f, 0.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
default:
LOG_ERROR(Render_Vulkan, "Unknown DisplayOrientation: {}", orientation);
LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation);
break;
}
const u64 size = sizeof(ScreenRectVertex) * vertices.size();
const u64 size = sizeof(ScreenRectVertex) * output_vertices.size();
auto [data, offset, invalidate] = vertex_buffer.Map(size, 16);
std::memcpy(data, vertices.data(), size);
std::memcpy(data, output_vertices.data(), size);
vertex_buffer.Commit(size);
const u32 scale_factor = GetResolutionScaleFactor();
draw_info.i_resolution =
Common::MakeVec(static_cast<f32>(screen_info.texture.width * scale_factor),
static_cast<f32>(screen_info.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.height * scale_factor));
draw_info.o_resolution = Common::MakeVec(h, w, 1.0f / h, 1.0f / w);
draw_info.o_resolution = Common::MakeVec(screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
draw_info.screen_id_l = screen_id;
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {

View file

@ -72,7 +72,7 @@ static_assert(sizeof(PresentUniformData) == 128,
class RendererVulkan : public VideoCore::RendererBase {
static constexpr std::size_t PRESENT_PIPELINES = 3;
static constexpr std::size_t POST_PIPELINES = 6;
public:
explicit RendererVulkan(Core::System& system, Pica::PicaCore& pica, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window);
@ -100,6 +100,7 @@ private:
void RenderScreenshotWithStagingCopy();
bool TryRenderScreenshotWithHostMemory();
void PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout);
void PrepareTextureDraw(Frame* frame, const Layout::FramebufferLayout& layout);
void RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout,
bool flipped);
@ -142,7 +143,10 @@ private:
DescriptorHeap present_heap;
vk::UniquePipelineLayout present_pipeline_layout;
std::array<vk::Pipeline, PRESENT_PIPELINES> present_pipelines;
std::array<vk::Pipeline, POST_PIPELINES> post_pipelines;
std::array<vk::ShaderModule, PRESENT_PIPELINES> present_shaders;
std::array<vk::ShaderModule, POST_PIPELINES> post_vert_shaders;
std::array<vk::ShaderModule, POST_PIPELINES> post_frag_shaders;
std::array<vk::Sampler, 2> present_samplers;
vk::ShaderModule present_vertex_shader;
vk::ShaderModule simplepresent_vertex_shader;