Browse Source
renderer_vulkan: split up blit screen resources into separate antialias and window adapt passes
nce_cpp
renderer_vulkan: split up blit screen resources into separate antialias and window adapt passes
nce_cpp
11 changed files with 985 additions and 913 deletions
-
5src/video_core/CMakeLists.txt
-
70src/video_core/renderer_vulkan/present/filters.cpp
-
30src/video_core/renderer_vulkan/present/filters.h
-
50src/video_core/renderer_vulkan/present/util.cpp
-
2src/video_core/renderer_vulkan/present/util.h
-
512src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
-
71src/video_core/renderer_vulkan/present/window_adapt_pass.h
-
33src/video_core/renderer_vulkan/renderer_vulkan.cpp
-
3src/video_core/renderer_vulkan/renderer_vulkan.h
-
935src/video_core/renderer_vulkan/vk_blit_screen.cpp
-
93src/video_core/renderer_vulkan/vk_blit_screen.h
@ -0,0 +1,70 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
|
||||
|
#include "video_core/host_shaders/present_bicubic_frag_spv.h"
|
||||
|
#include "video_core/host_shaders/present_gaussian_frag_spv.h"
|
||||
|
#include "video_core/host_shaders/vulkan_present_frag_spv.h"
|
||||
|
#include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h"
|
||||
|
#include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h"
|
||||
|
#include "video_core/renderer_vulkan/present/filters.h"
|
||||
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
vk::ShaderModule SelectScaleForceShader(const Device& device) { |
||||
|
if (device.IsFloat16Supported()) { |
||||
|
return BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP16_FRAG_SPV); |
||||
|
} else { |
||||
|
return BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP32_FRAG_SPV); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format) { |
||||
|
return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, |
||||
|
CreateNearestNeighborSampler(device), |
||||
|
BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format) { |
||||
|
return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, |
||||
|
CreateBilinearSampler(device), |
||||
|
BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format) { |
||||
|
return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, |
||||
|
CreateBilinearSampler(device), |
||||
|
BuildShader(device, PRESENT_BICUBIC_FRAG_SPV)); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format) { |
||||
|
return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, |
||||
|
CreateBilinearSampler(device), |
||||
|
BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV)); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format) { |
||||
|
return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, |
||||
|
CreateBilinearSampler(device), |
||||
|
SelectScaleForceShader(device)); |
||||
|
} |
||||
|
|
||||
|
} // namespace Vulkan
|
||||
@ -0,0 +1,30 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "video_core/renderer_vulkan/present/window_adapt_pass.h" |
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format); |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format); |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format); |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format); |
||||
|
|
||||
|
std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, |
||||
|
const MemoryAllocator& memory_allocator, |
||||
|
size_t image_count, VkFormat frame_format); |
||||
|
|
||||
|
} // namespace Vulkan |
||||
@ -0,0 +1,512 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include <cstring>
|
||||
|
|
||||
|
#include "core/frontend/framebuffer_layout.h"
|
||||
|
#include "video_core/host_shaders/vulkan_present_vert_spv.h"
|
||||
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||
|
#include "video_core/renderer_vulkan/present/window_adapt_pass.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_present_manager.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
|
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
struct ScreenRectVertex { |
||||
|
ScreenRectVertex() = default; |
||||
|
explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} |
||||
|
|
||||
|
std::array<f32, 2> position; |
||||
|
std::array<f32, 2> tex_coord; |
||||
|
|
||||
|
static VkVertexInputBindingDescription GetDescription() { |
||||
|
return { |
||||
|
.binding = 0, |
||||
|
.stride = sizeof(ScreenRectVertex), |
||||
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { |
||||
|
return {{ |
||||
|
{ |
||||
|
.location = 0, |
||||
|
.binding = 0, |
||||
|
.format = VK_FORMAT_R32G32_SFLOAT, |
||||
|
.offset = offsetof(ScreenRectVertex, position), |
||||
|
}, |
||||
|
{ |
||||
|
.location = 1, |
||||
|
.binding = 0, |
||||
|
.format = VK_FORMAT_R32G32_SFLOAT, |
||||
|
.offset = offsetof(ScreenRectVertex, tex_coord), |
||||
|
}, |
||||
|
}}; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { |
||||
|
// clang-format off
|
||||
|
return { 2.f / width, 0.f, 0.f, 0.f, |
||||
|
0.f, 2.f / height, 0.f, 0.f, |
||||
|
0.f, 0.f, 1.f, 0.f, |
||||
|
-1.f, -1.f, 0.f, 1.f}; |
||||
|
// clang-format on
|
||||
|
} |
||||
|
|
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
struct WindowAdaptPass::BufferData { |
||||
|
struct { |
||||
|
std::array<f32, 4 * 4> modelview_matrix; |
||||
|
} uniform; |
||||
|
|
||||
|
std::array<ScreenRectVertex, 4> vertices; |
||||
|
}; |
||||
|
|
||||
|
WindowAdaptPass::WindowAdaptPass(const Device& device_, const MemoryAllocator& memory_allocator, |
||||
|
size_t num_images, VkFormat frame_format, vk::Sampler&& sampler_, |
||||
|
vk::ShaderModule&& fragment_shader_) |
||||
|
: device(device_), sampler(std::move(sampler_)), fragment_shader(std::move(fragment_shader_)) { |
||||
|
CreateDescriptorPool(num_images); |
||||
|
CreateDescriptorSetLayout(); |
||||
|
CreateDescriptorSets(num_images); |
||||
|
CreatePipelineLayout(); |
||||
|
CreateVertexShader(); |
||||
|
CreateRenderPass(frame_format); |
||||
|
CreatePipeline(); |
||||
|
CreateBuffer(memory_allocator); |
||||
|
} |
||||
|
|
||||
|
WindowAdaptPass::~WindowAdaptPass() = default; |
||||
|
|
||||
|
void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, |
||||
|
VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, |
||||
|
const Layout::FramebufferLayout& layout, Frame* dst) { |
||||
|
ConfigureLayout(image_index, src_image_view, layout, crop_rect); |
||||
|
|
||||
|
const VkFramebuffer host_framebuffer{*dst->framebuffer}; |
||||
|
const VkRenderPass renderpass{*render_pass}; |
||||
|
const VkPipeline graphics_pipeline{*pipeline}; |
||||
|
const VkDescriptorSet descriptor_set{descriptor_sets[image_index]}; |
||||
|
const VkExtent2D render_area{ |
||||
|
.width = dst->width, |
||||
|
.height = dst->height, |
||||
|
}; |
||||
|
|
||||
|
scheduler.Record([=](vk::CommandBuffer cmdbuf) { |
||||
|
const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; |
||||
|
const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; |
||||
|
const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; |
||||
|
const VkClearValue clear_color{ |
||||
|
.color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, |
||||
|
}; |
||||
|
const VkRenderPassBeginInfo renderpass_bi{ |
||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.renderPass = renderpass, |
||||
|
.framebuffer = host_framebuffer, |
||||
|
.renderArea = |
||||
|
{ |
||||
|
.offset = {0, 0}, |
||||
|
.extent = render_area, |
||||
|
}, |
||||
|
.clearValueCount = 1, |
||||
|
.pClearValues = &clear_color, |
||||
|
}; |
||||
|
const VkViewport viewport{ |
||||
|
.x = 0.0f, |
||||
|
.y = 0.0f, |
||||
|
.width = static_cast<float>(render_area.width), |
||||
|
.height = static_cast<float>(render_area.height), |
||||
|
.minDepth = 0.0f, |
||||
|
.maxDepth = 1.0f, |
||||
|
}; |
||||
|
const VkRect2D scissor{ |
||||
|
.offset = {0, 0}, |
||||
|
.extent = render_area, |
||||
|
}; |
||||
|
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); |
||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); |
||||
|
cmdbuf.SetViewport(0, viewport); |
||||
|
cmdbuf.SetScissor(0, scissor); |
||||
|
cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); |
||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, |
||||
|
descriptor_set, {}); |
||||
|
cmdbuf.Draw(4, 1, 0, 0); |
||||
|
cmdbuf.EndRenderPass(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
VkRenderPass WindowAdaptPass::GetRenderPass() { |
||||
|
return *render_pass; |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateDescriptorPool(size_t num_images) { |
||||
|
const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ |
||||
|
{ |
||||
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
||||
|
.descriptorCount = static_cast<u32>(num_images), |
||||
|
}, |
||||
|
{ |
||||
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
||||
|
.descriptorCount = static_cast<u32>(num_images), |
||||
|
}, |
||||
|
}}; |
||||
|
|
||||
|
const VkDescriptorPoolCreateInfo ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.maxSets = static_cast<u32>(num_images), |
||||
|
.poolSizeCount = static_cast<u32>(pool_sizes.size()), |
||||
|
.pPoolSizes = pool_sizes.data(), |
||||
|
}; |
||||
|
descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateDescriptorSetLayout() { |
||||
|
const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ |
||||
|
{ |
||||
|
.binding = 0, |
||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
||||
|
.descriptorCount = 1, |
||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, |
||||
|
.pImmutableSamplers = nullptr, |
||||
|
}, |
||||
|
{ |
||||
|
.binding = 1, |
||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
||||
|
.descriptorCount = 1, |
||||
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, |
||||
|
.pImmutableSamplers = nullptr, |
||||
|
}, |
||||
|
}}; |
||||
|
|
||||
|
const VkDescriptorSetLayoutCreateInfo ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.bindingCount = static_cast<u32>(layout_bindings.size()), |
||||
|
.pBindings = layout_bindings.data(), |
||||
|
}; |
||||
|
|
||||
|
descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateDescriptorSets(size_t num_images) { |
||||
|
const std::vector layouts(num_images, *descriptor_set_layout); |
||||
|
descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateBuffer(const MemoryAllocator& memory_allocator) { |
||||
|
const VkBufferCreateInfo ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.size = sizeof(BufferData), |
||||
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
||||
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
||||
|
.queueFamilyIndexCount = 0, |
||||
|
.pQueueFamilyIndices = nullptr, |
||||
|
}; |
||||
|
|
||||
|
buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { |
||||
|
const VkAttachmentDescription color_attachment{ |
||||
|
.flags = 0, |
||||
|
.format = frame_format, |
||||
|
.samples = VK_SAMPLE_COUNT_1_BIT, |
||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, |
||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE, |
||||
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
||||
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, |
||||
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
||||
|
.finalLayout = VK_IMAGE_LAYOUT_GENERAL, |
||||
|
}; |
||||
|
|
||||
|
const VkAttachmentReference color_attachment_ref{ |
||||
|
.attachment = 0, |
||||
|
.layout = VK_IMAGE_LAYOUT_GENERAL, |
||||
|
}; |
||||
|
|
||||
|
const VkSubpassDescription subpass_description{ |
||||
|
.flags = 0, |
||||
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, |
||||
|
.inputAttachmentCount = 0, |
||||
|
.pInputAttachments = nullptr, |
||||
|
.colorAttachmentCount = 1, |
||||
|
.pColorAttachments = &color_attachment_ref, |
||||
|
.pResolveAttachments = nullptr, |
||||
|
.pDepthStencilAttachment = nullptr, |
||||
|
.preserveAttachmentCount = 0, |
||||
|
.pPreserveAttachments = nullptr, |
||||
|
}; |
||||
|
|
||||
|
const VkSubpassDependency dependency{ |
||||
|
.srcSubpass = VK_SUBPASS_EXTERNAL, |
||||
|
.dstSubpass = 0, |
||||
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, |
||||
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, |
||||
|
.srcAccessMask = 0, |
||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
||||
|
.dependencyFlags = 0, |
||||
|
}; |
||||
|
|
||||
|
const VkRenderPassCreateInfo renderpass_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.attachmentCount = 1, |
||||
|
.pAttachments = &color_attachment, |
||||
|
.subpassCount = 1, |
||||
|
.pSubpasses = &subpass_description, |
||||
|
.dependencyCount = 1, |
||||
|
.pDependencies = &dependency, |
||||
|
}; |
||||
|
|
||||
|
render_pass = device.GetLogical().CreateRenderPass(renderpass_ci); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreateVertexShader() { |
||||
|
vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreatePipelineLayout() { |
||||
|
const VkPipelineLayoutCreateInfo ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.setLayoutCount = 1, |
||||
|
.pSetLayouts = descriptor_set_layout.address(), |
||||
|
.pushConstantRangeCount = 0, |
||||
|
.pPushConstantRanges = nullptr, |
||||
|
}; |
||||
|
pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::SetUniformData(BufferData& data, |
||||
|
const Layout::FramebufferLayout& layout) const { |
||||
|
data.uniform.modelview_matrix = |
||||
|
MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::SetVertexData(BufferData& data, const Layout::FramebufferLayout& layout, |
||||
|
const Common::Rectangle<f32>& crop) const { |
||||
|
// Map the coordinates to the screen.
|
||||
|
const auto& screen = layout.screen; |
||||
|
const auto x = static_cast<f32>(screen.left); |
||||
|
const auto y = static_cast<f32>(screen.top); |
||||
|
const auto w = static_cast<f32>(screen.GetWidth()); |
||||
|
const auto h = static_cast<f32>(screen.GetHeight()); |
||||
|
|
||||
|
data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); |
||||
|
data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); |
||||
|
data.vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); |
||||
|
data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::UpdateDescriptorSet(size_t image_index, VkImageView image_view) { |
||||
|
const VkDescriptorBufferInfo buffer_info{ |
||||
|
.buffer = *buffer, |
||||
|
.offset = offsetof(BufferData, uniform), |
||||
|
.range = sizeof(BufferData::uniform), |
||||
|
}; |
||||
|
|
||||
|
const VkWriteDescriptorSet ubo_write{ |
||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
||||
|
.pNext = nullptr, |
||||
|
.dstSet = descriptor_sets[image_index], |
||||
|
.dstBinding = 0, |
||||
|
.dstArrayElement = 0, |
||||
|
.descriptorCount = 1, |
||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
||||
|
.pImageInfo = nullptr, |
||||
|
.pBufferInfo = &buffer_info, |
||||
|
.pTexelBufferView = nullptr, |
||||
|
}; |
||||
|
|
||||
|
const VkDescriptorImageInfo image_info{ |
||||
|
.sampler = *sampler, |
||||
|
.imageView = image_view, |
||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL, |
||||
|
}; |
||||
|
|
||||
|
const VkWriteDescriptorSet sampler_write{ |
||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
||||
|
.pNext = nullptr, |
||||
|
.dstSet = descriptor_sets[image_index], |
||||
|
.dstBinding = 1, |
||||
|
.dstArrayElement = 0, |
||||
|
.descriptorCount = 1, |
||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
||||
|
.pImageInfo = &image_info, |
||||
|
.pBufferInfo = nullptr, |
||||
|
.pTexelBufferView = nullptr, |
||||
|
}; |
||||
|
|
||||
|
device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::ConfigureLayout(size_t image_index, VkImageView image_view, |
||||
|
const Layout::FramebufferLayout& layout, |
||||
|
const Common::Rectangle<f32>& crop_rect) { |
||||
|
BufferData data; |
||||
|
SetUniformData(data, layout); |
||||
|
SetVertexData(data, layout, crop_rect); |
||||
|
|
||||
|
const std::span<u8> mapped_span = buffer.Mapped(); |
||||
|
std::memcpy(mapped_span.data(), &data, sizeof(data)); |
||||
|
|
||||
|
UpdateDescriptorSet(image_index, image_view); |
||||
|
} |
||||
|
|
||||
|
void WindowAdaptPass::CreatePipeline() { |
||||
|
const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ |
||||
|
{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.stage = VK_SHADER_STAGE_VERTEX_BIT, |
||||
|
.module = *vertex_shader, |
||||
|
.pName = "main", |
||||
|
.pSpecializationInfo = nullptr, |
||||
|
}, |
||||
|
{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT, |
||||
|
.module = *fragment_shader, |
||||
|
.pName = "main", |
||||
|
.pSpecializationInfo = nullptr, |
||||
|
}, |
||||
|
}}; |
||||
|
|
||||
|
const auto vertex_binding_description = ScreenRectVertex::GetDescription(); |
||||
|
const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); |
||||
|
|
||||
|
const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.vertexBindingDescriptionCount = 1, |
||||
|
.pVertexBindingDescriptions = &vertex_binding_description, |
||||
|
.vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, |
||||
|
.pVertexAttributeDescriptions = vertex_attrs_description.data(), |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
||||
|
.primitiveRestartEnable = VK_FALSE, |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineViewportStateCreateInfo viewport_state_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.viewportCount = 1, |
||||
|
.pViewports = nullptr, |
||||
|
.scissorCount = 1, |
||||
|
.pScissors = nullptr, |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineRasterizationStateCreateInfo rasterization_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.depthClampEnable = VK_FALSE, |
||||
|
.rasterizerDiscardEnable = VK_FALSE, |
||||
|
.polygonMode = VK_POLYGON_MODE_FILL, |
||||
|
.cullMode = VK_CULL_MODE_NONE, |
||||
|
.frontFace = VK_FRONT_FACE_CLOCKWISE, |
||||
|
.depthBiasEnable = VK_FALSE, |
||||
|
.depthBiasConstantFactor = 0.0f, |
||||
|
.depthBiasClamp = 0.0f, |
||||
|
.depthBiasSlopeFactor = 0.0f, |
||||
|
.lineWidth = 1.0f, |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineMultisampleStateCreateInfo multisampling_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, |
||||
|
.sampleShadingEnable = VK_FALSE, |
||||
|
.minSampleShading = 0.0f, |
||||
|
.pSampleMask = nullptr, |
||||
|
.alphaToCoverageEnable = VK_FALSE, |
||||
|
.alphaToOneEnable = VK_FALSE, |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineColorBlendAttachmentState color_blend_attachment{ |
||||
|
.blendEnable = VK_FALSE, |
||||
|
.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
||||
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
||||
|
.colorBlendOp = VK_BLEND_OP_ADD, |
||||
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, |
||||
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, |
||||
|
.alphaBlendOp = VK_BLEND_OP_ADD, |
||||
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | |
||||
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, |
||||
|
}; |
||||
|
|
||||
|
const VkPipelineColorBlendStateCreateInfo color_blend_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.logicOpEnable = VK_FALSE, |
||||
|
.logicOp = VK_LOGIC_OP_COPY, |
||||
|
.attachmentCount = 1, |
||||
|
.pAttachments = &color_blend_attachment, |
||||
|
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, |
||||
|
}; |
||||
|
|
||||
|
static constexpr std::array dynamic_states{ |
||||
|
VK_DYNAMIC_STATE_VIEWPORT, |
||||
|
VK_DYNAMIC_STATE_SCISSOR, |
||||
|
}; |
||||
|
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.dynamicStateCount = static_cast<u32>(dynamic_states.size()), |
||||
|
.pDynamicStates = dynamic_states.data(), |
||||
|
}; |
||||
|
|
||||
|
const VkGraphicsPipelineCreateInfo pipeline_ci{ |
||||
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
||||
|
.pNext = nullptr, |
||||
|
.flags = 0, |
||||
|
.stageCount = static_cast<u32>(shader_stages.size()), |
||||
|
.pStages = shader_stages.data(), |
||||
|
.pVertexInputState = &vertex_input_ci, |
||||
|
.pInputAssemblyState = &input_assembly_ci, |
||||
|
.pTessellationState = nullptr, |
||||
|
.pViewportState = &viewport_state_ci, |
||||
|
.pRasterizationState = &rasterization_ci, |
||||
|
.pMultisampleState = &multisampling_ci, |
||||
|
.pDepthStencilState = nullptr, |
||||
|
.pColorBlendState = &color_blend_ci, |
||||
|
.pDynamicState = &dynamic_state_ci, |
||||
|
.layout = *pipeline_layout, |
||||
|
.renderPass = *render_pass, |
||||
|
.subpass = 0, |
||||
|
.basePipelineHandle = 0, |
||||
|
.basePipelineIndex = 0, |
||||
|
}; |
||||
|
|
||||
|
pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); |
||||
|
} |
||||
|
|
||||
|
} // namespace Vulkan
|
||||
@ -0,0 +1,71 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "common/math_util.h" |
||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h" |
||||
|
|
||||
|
namespace Layout { |
||||
|
struct FramebufferLayout; |
||||
|
} |
||||
|
|
||||
|
namespace Tegra { |
||||
|
struct FramebufferConfig; |
||||
|
} |
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
class Device; |
||||
|
struct Frame; |
||||
|
class MemoryAllocator; |
||||
|
class Scheduler; |
||||
|
|
||||
|
class WindowAdaptPass final { |
||||
|
public: |
||||
|
explicit WindowAdaptPass(const Device& device, const MemoryAllocator& memory_allocator, |
||||
|
size_t num_images, VkFormat frame_format, vk::Sampler&& sampler, |
||||
|
vk::ShaderModule&& fragment_shader); |
||||
|
~WindowAdaptPass(); |
||||
|
|
||||
|
void Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, |
||||
|
VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, |
||||
|
const Layout::FramebufferLayout& layout, Frame* dst); |
||||
|
|
||||
|
VkRenderPass GetRenderPass(); |
||||
|
|
||||
|
private: |
||||
|
struct BufferData; |
||||
|
|
||||
|
void SetUniformData(BufferData& data, const Layout::FramebufferLayout& layout) const; |
||||
|
void SetVertexData(BufferData& data, const Layout::FramebufferLayout& layout, |
||||
|
const Common::Rectangle<f32>& crop_rect) const; |
||||
|
void UpdateDescriptorSet(size_t image_index, VkImageView image_view); |
||||
|
void ConfigureLayout(size_t image_index, VkImageView image_view, |
||||
|
const Layout::FramebufferLayout& layout, |
||||
|
const Common::Rectangle<f32>& crop_rect); |
||||
|
|
||||
|
void CreateDescriptorPool(size_t num_images); |
||||
|
void CreateDescriptorSetLayout(); |
||||
|
void CreateDescriptorSets(size_t num_images); |
||||
|
void CreatePipelineLayout(); |
||||
|
void CreateVertexShader(); |
||||
|
void CreateRenderPass(VkFormat frame_format); |
||||
|
void CreatePipeline(); |
||||
|
void CreateBuffer(const MemoryAllocator& memory_allocator); |
||||
|
|
||||
|
private: |
||||
|
const Device& device; |
||||
|
vk::DescriptorPool descriptor_pool; |
||||
|
vk::DescriptorSetLayout descriptor_set_layout; |
||||
|
vk::DescriptorSets descriptor_sets; |
||||
|
vk::PipelineLayout pipeline_layout; |
||||
|
vk::Sampler sampler; |
||||
|
vk::ShaderModule vertex_shader; |
||||
|
vk::ShaderModule fragment_shader; |
||||
|
vk::RenderPass render_pass; |
||||
|
vk::Pipeline pipeline; |
||||
|
vk::Buffer buffer; |
||||
|
}; |
||||
|
|
||||
|
} // namespace Vulkan |
||||
935
src/video_core/renderer_vulkan/vk_blit_screen.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue