|
|
|
@ -7,7 +7,6 @@
|
|
|
|
|
#include "common/memory_detect.h"
|
|
|
|
|
#include "common/microprofile.h"
|
|
|
|
|
#include "common/settings.h"
|
|
|
|
|
#include "common/texture.h"
|
|
|
|
|
#include "core/core.h"
|
|
|
|
|
#include "core/frontend/emu_window.h"
|
|
|
|
|
#include "core/hw/gpu.h"
|
|
|
|
@ -21,7 +20,6 @@
|
|
|
|
|
#include "video_core/host_shaders/vulkan_present_frag_spv.h"
|
|
|
|
|
#include "video_core/host_shaders/vulkan_present_interlaced_frag_spv.h"
|
|
|
|
|
#include "video_core/host_shaders/vulkan_present_vert_spv.h"
|
|
|
|
|
#include "vulkan/vulkan_format_traits.hpp"
|
|
|
|
|
|
|
|
|
|
#include <vk_mem_alloc.h>
|
|
|
|
|
|
|
|
|
@ -49,10 +47,6 @@ constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(u32 width, u32 height) {
|
|
|
|
|
// clang-format on
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr static std::array<vk::DescriptorSetLayoutBinding, 1> PRESENT_BINDINGS = {{
|
|
|
|
|
{0, vk::DescriptorType::eCombinedImageSampler, 3, vk::ShaderStageFlagBits::eFragment},
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
RendererVulkan::RendererVulkan(Core::System& system, Frontend::EmuWindow& window,
|
|
|
|
|
Frontend::EmuWindow* secondary_window)
|
|
|
|
|
: RendererBase{system, window, secondary_window}, memory{system.Memory()},
|
|
|
|
@ -69,10 +63,9 @@ RendererVulkan::RendererVulkan(Core::System& system, Frontend::EmuWindow& window
|
|
|
|
|
scheduler,
|
|
|
|
|
pool,
|
|
|
|
|
renderpass_cache,
|
|
|
|
|
main_window.ImageCount()},
|
|
|
|
|
present_set_provider{instance, pool, PRESENT_BINDINGS} {
|
|
|
|
|
main_window.ImageCount()} {
|
|
|
|
|
CompileShaders();
|
|
|
|
|
BuildLayouts();
|
|
|
|
|
BuildLayoutsAndDescriptors();
|
|
|
|
|
BuildPipelines();
|
|
|
|
|
if (secondary_window) {
|
|
|
|
|
second_window = std::make_unique<PresentWindow>(*secondary_window, instance, scheduler);
|
|
|
|
@ -80,17 +73,22 @@ RendererVulkan::RendererVulkan(Core::System& system, Frontend::EmuWindow& window
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RendererVulkan::~RendererVulkan() {
|
|
|
|
|
vk::Device device = instance.GetDevice();
|
|
|
|
|
const vk::Device device = instance.GetDevice();
|
|
|
|
|
scheduler.Finish();
|
|
|
|
|
device.waitIdle();
|
|
|
|
|
|
|
|
|
|
device.destroyShaderModule(present_vertex_shader);
|
|
|
|
|
for (u32 i = 0; i < PRESENT_PIPELINES; i++) {
|
|
|
|
|
device.destroyPipeline(present_pipelines[i]);
|
|
|
|
|
device.destroyShaderModule(present_shaders[i]);
|
|
|
|
|
device.destroyPipelineLayout(pipeline_layout);
|
|
|
|
|
device.destroyDescriptorPool(descriptor_pool);
|
|
|
|
|
device.destroyDescriptorSetLayout(descriptor_set_layout);
|
|
|
|
|
device.destroyDescriptorUpdateTemplate(update_template);
|
|
|
|
|
device.destroyShaderModule(vert_shader);
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < NUM_PIPELINES; i++) {
|
|
|
|
|
device.destroyPipeline(pipelines[i]);
|
|
|
|
|
device.destroyShaderModule(frag_shaders[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& sampler : present_samplers) {
|
|
|
|
|
for (auto sampler : samplers) {
|
|
|
|
|
device.destroySampler(sampler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -105,9 +103,10 @@ void RendererVulkan::Sync() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RendererVulkan::PrepareRendertarget() {
|
|
|
|
|
for (u32 i = 0; i < 3; i++) {
|
|
|
|
|
for (u32 i = 0; i < NUM_SCREENS; i++) {
|
|
|
|
|
const u32 fb_id = i == 2 ? 1 : 0;
|
|
|
|
|
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
|
|
|
|
auto& texture = screen_infos[i].texture;
|
|
|
|
|
|
|
|
|
|
// Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04
|
|
|
|
|
u32 lcd_color_addr =
|
|
|
|
@ -118,37 +117,31 @@ void RendererVulkan::PrepareRendertarget() {
|
|
|
|
|
|
|
|
|
|
if (color_fill.is_enabled) {
|
|
|
|
|
LoadColorToActiveVkTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b,
|
|
|
|
|
screen_infos[i].texture);
|
|
|
|
|
} else {
|
|
|
|
|
TextureInfo& texture = screen_infos[i].texture;
|
|
|
|
|
if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
|
|
|
|
|
texture.format != framebuffer.color_format) {
|
|
|
|
|
|
|
|
|
|
// Reallocate texture if the framebuffer size has changed.
|
|
|
|
|
// This is expected to not happen very often and hence should not be a
|
|
|
|
|
// performance problem.
|
|
|
|
|
ConfigureFramebufferTexture(texture, framebuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1);
|
|
|
|
|
|
|
|
|
|
// Resize the texture in case the framebuffer size has changed
|
|
|
|
|
texture.width = framebuffer.width;
|
|
|
|
|
texture.height = framebuffer.height;
|
|
|
|
|
texture);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
|
|
|
|
|
texture.format != framebuffer.color_format) {
|
|
|
|
|
ConfigureFramebufferTexture(texture, framebuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout) {
|
|
|
|
|
const auto sampler = present_samplers[!Settings::values.filter_mode.GetValue()];
|
|
|
|
|
std::transform(screen_infos.begin(), screen_infos.end(), present_textures.begin(),
|
|
|
|
|
[&](auto& info) {
|
|
|
|
|
return DescriptorData{vk::DescriptorImageInfo{sampler, info.image_view,
|
|
|
|
|
vk::ImageLayout::eGeneral}};
|
|
|
|
|
});
|
|
|
|
|
const auto sampler = samplers[!Settings::values.filter_mode.GetValue()];
|
|
|
|
|
std::transform(screen_infos.begin(), screen_infos.end(), image_infos.begin(), [&](auto& info) {
|
|
|
|
|
return vk::DescriptorImageInfo{sampler, info.image_view, vk::ImageLayout::eGeneral};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const auto descriptor_set = present_set_provider.Acquire(present_textures);
|
|
|
|
|
// Prepare the descriptor set with presentation images.
|
|
|
|
|
const auto descriptor_set = present_sets[frame->index];
|
|
|
|
|
const vk::Device device = instance.GetDevice();
|
|
|
|
|
device.updateDescriptorSetWithTemplate(descriptor_set, update_template, image_infos);
|
|
|
|
|
|
|
|
|
|
// Bind presentation pipeline, enter renderpass.
|
|
|
|
|
renderpass_cache.EndRendering();
|
|
|
|
|
scheduler.Record([this, layout, frame, descriptor_set, renderpass = main_window.Renderpass(),
|
|
|
|
|
index = current_pipeline](vk::CommandBuffer cmdbuf) {
|
|
|
|
@ -170,12 +163,11 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
|
|
|
|
|
cmdbuf.setScissor(0, scissor);
|
|
|
|
|
|
|
|
|
|
const vk::ClearValue clear{.color = clear_color};
|
|
|
|
|
const vk::PipelineLayout layout{*present_pipeline_layout};
|
|
|
|
|
const vk::RenderPassBeginInfo renderpass_begin_info = {
|
|
|
|
|
.renderPass = renderpass,
|
|
|
|
|
.framebuffer = frame->framebuffer,
|
|
|
|
|
.renderArea =
|
|
|
|
|
vk::Rect2D{
|
|
|
|
|
{
|
|
|
|
|
.offset = {0, 0},
|
|
|
|
|
.extent = {frame->width, frame->height},
|
|
|
|
|
},
|
|
|
|
@ -184,8 +176,9 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
|
|
|
|
|
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[index]);
|
|
|
|
|
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, descriptor_set, {});
|
|
|
|
|
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[index]);
|
|
|
|
|
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout, 0,
|
|
|
|
|
descriptor_set, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -239,13 +232,13 @@ void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
|
|
|
|
|
|
|
|
|
|
void RendererVulkan::CompileShaders() {
|
|
|
|
|
vk::Device device = instance.GetDevice();
|
|
|
|
|
present_vertex_shader = CompileSPV(VULKAN_PRESENT_VERT_SPV, device);
|
|
|
|
|
present_shaders[0] = CompileSPV(VULKAN_PRESENT_FRAG_SPV, device);
|
|
|
|
|
present_shaders[1] = CompileSPV(VULKAN_PRESENT_ANAGLYPH_FRAG_SPV, device);
|
|
|
|
|
present_shaders[2] = CompileSPV(VULKAN_PRESENT_INTERLACED_FRAG_SPV, device);
|
|
|
|
|
vert_shader = CompileSPV(VULKAN_PRESENT_VERT_SPV, device);
|
|
|
|
|
frag_shaders[0] = CompileSPV(VULKAN_PRESENT_FRAG_SPV, device);
|
|
|
|
|
frag_shaders[1] = CompileSPV(VULKAN_PRESENT_ANAGLYPH_FRAG_SPV, device);
|
|
|
|
|
frag_shaders[2] = CompileSPV(VULKAN_PRESENT_INTERLACED_FRAG_SPV, device);
|
|
|
|
|
|
|
|
|
|
auto properties = instance.GetPhysicalDevice().getProperties();
|
|
|
|
|
for (std::size_t i = 0; i < present_samplers.size(); i++) {
|
|
|
|
|
const auto properties = instance.GetPhysicalDevice().getProperties();
|
|
|
|
|
for (std::size_t i = 0; i < samplers.size(); i++) {
|
|
|
|
|
const vk::Filter filter_mode = i == 0 ? vk::Filter::eLinear : vk::Filter::eNearest;
|
|
|
|
|
const vk::SamplerCreateInfo sampler_info = {
|
|
|
|
|
.magFilter = filter_mode,
|
|
|
|
@ -261,25 +254,81 @@ void RendererVulkan::CompileShaders() {
|
|
|
|
|
.unnormalizedCoordinates = false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
present_samplers[i] = device.createSampler(sampler_info);
|
|
|
|
|
samplers[i] = device.createSampler(sampler_info);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RendererVulkan::BuildLayouts() {
|
|
|
|
|
void RendererVulkan::BuildLayoutsAndDescriptors() {
|
|
|
|
|
const vk::PushConstantRange push_range = {
|
|
|
|
|
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
|
|
|
|
.offset = 0,
|
|
|
|
|
.size = sizeof(PresentUniformData),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto descriptor_set_layout = present_set_provider.Layout();
|
|
|
|
|
const vk::PipelineLayoutCreateInfo layout_info = {
|
|
|
|
|
const vk::DescriptorSetLayoutBinding binding = {
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
|
|
|
|
.descriptorCount = 3,
|
|
|
|
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const vk::DescriptorUpdateTemplateEntry update_entry = {
|
|
|
|
|
.dstBinding = 0,
|
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
|
.descriptorCount = 3,
|
|
|
|
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
|
|
|
|
.offset = 0,
|
|
|
|
|
.stride = sizeof(vk::DescriptorImageInfo),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const vk::DescriptorSetLayoutCreateInfo layout_info = {
|
|
|
|
|
.bindingCount = 1,
|
|
|
|
|
.pBindings = &binding,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const vk::Device device = instance.GetDevice();
|
|
|
|
|
descriptor_set_layout = device.createDescriptorSetLayout(layout_info);
|
|
|
|
|
|
|
|
|
|
const vk::DescriptorUpdateTemplateCreateInfo template_info = {
|
|
|
|
|
.descriptorUpdateEntryCount = 1,
|
|
|
|
|
.pDescriptorUpdateEntries = &update_entry,
|
|
|
|
|
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
|
|
|
|
|
.descriptorSetLayout = descriptor_set_layout,
|
|
|
|
|
};
|
|
|
|
|
update_template = device.createDescriptorUpdateTemplate(template_info);
|
|
|
|
|
|
|
|
|
|
const vk::PipelineLayoutCreateInfo pipeline_layout_info = {
|
|
|
|
|
.setLayoutCount = 1,
|
|
|
|
|
.pSetLayouts = &descriptor_set_layout,
|
|
|
|
|
.pushConstantRangeCount = 1,
|
|
|
|
|
.pPushConstantRanges = &push_range,
|
|
|
|
|
};
|
|
|
|
|
present_pipeline_layout = instance.GetDevice().createPipelineLayoutUnique(layout_info);
|
|
|
|
|
pipeline_layout = device.createPipelineLayout(pipeline_layout_info);
|
|
|
|
|
|
|
|
|
|
const u32 image_count = main_window.ImageCount();
|
|
|
|
|
const vk::DescriptorPoolSize pool_size = {
|
|
|
|
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
|
|
|
|
.descriptorCount = binding.descriptorCount * image_count,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const vk::DescriptorPoolCreateInfo descriptor_pool_info = {
|
|
|
|
|
.maxSets = image_count,
|
|
|
|
|
.poolSizeCount = 1,
|
|
|
|
|
.pPoolSizes = &pool_size,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
descriptor_pool = device.createDescriptorPool(descriptor_pool_info);
|
|
|
|
|
|
|
|
|
|
std::array<vk::DescriptorSetLayout, 3> layouts;
|
|
|
|
|
layouts.fill(descriptor_set_layout);
|
|
|
|
|
|
|
|
|
|
const vk::DescriptorSetAllocateInfo alloc_info = {
|
|
|
|
|
.descriptorPool = descriptor_pool,
|
|
|
|
|
.descriptorSetCount = image_count,
|
|
|
|
|
.pSetLayouts = layouts.data(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
present_sets = device.allocateDescriptorSets(alloc_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RendererVulkan::BuildPipelines() {
|
|
|
|
@ -370,16 +419,16 @@ void RendererVulkan::BuildPipelines() {
|
|
|
|
|
.stencilTestEnable = false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < PRESENT_PIPELINES; i++) {
|
|
|
|
|
for (u32 i = 0; i < NUM_PIPELINES; i++) {
|
|
|
|
|
const std::array shader_stages = {
|
|
|
|
|
vk::PipelineShaderStageCreateInfo{
|
|
|
|
|
.stage = vk::ShaderStageFlagBits::eVertex,
|
|
|
|
|
.module = present_vertex_shader,
|
|
|
|
|
.module = vert_shader,
|
|
|
|
|
.pName = "main",
|
|
|
|
|
},
|
|
|
|
|
vk::PipelineShaderStageCreateInfo{
|
|
|
|
|
.stage = vk::ShaderStageFlagBits::eFragment,
|
|
|
|
|
.module = present_shaders[i],
|
|
|
|
|
.module = frag_shaders[i],
|
|
|
|
|
.pName = "main",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
@ -395,14 +444,14 @@ void RendererVulkan::BuildPipelines() {
|
|
|
|
|
.pDepthStencilState = &depth_info,
|
|
|
|
|
.pColorBlendState = &color_blending,
|
|
|
|
|
.pDynamicState = &dynamic_info,
|
|
|
|
|
.layout = *present_pipeline_layout,
|
|
|
|
|
.layout = pipeline_layout,
|
|
|
|
|
.renderPass = main_window.Renderpass(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto [result, pipeline] =
|
|
|
|
|
instance.GetDevice().createGraphicsPipeline({}, pipeline_info);
|
|
|
|
|
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build present pipelines");
|
|
|
|
|
present_pipelines[i] = pipeline;
|
|
|
|
|
pipelines[i] = pipeline;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -416,8 +465,7 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
|
|
|
|
|
vmaDestroyImage(instance.GetAllocator(), texture.image, texture.allocation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const VideoCore::PixelFormat pixel_format =
|
|
|
|
|
VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format);
|
|
|
|
|
const auto pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format);
|
|
|
|
|
const vk::Format format = instance.GetTraits(pixel_format).native;
|
|
|
|
|
const vk::ImageCreateInfo image_info = {
|
|
|
|
|
.imageType = vk::ImageType::e2D,
|
|
|
|
@ -603,7 +651,7 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w,
|
|
|
|
|
|
|
|
|
|
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {
|
|
|
|
|
const u32 first_vertex = static_cast<u32>(offset) / sizeof(ScreenRectVertex);
|
|
|
|
|
cmdbuf.pushConstants(*present_pipeline_layout,
|
|
|
|
|
cmdbuf.pushConstants(pipeline_layout,
|
|
|
|
|
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex,
|
|
|
|
|
0, sizeof(info), &info);
|
|
|
|
|
|
|
|
|
@ -676,7 +724,7 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
|
|
|
|
|
|
|
|
|
|
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {
|
|
|
|
|
const u32 first_vertex = static_cast<u32>(offset) / sizeof(ScreenRectVertex);
|
|
|
|
|
cmdbuf.pushConstants(*present_pipeline_layout,
|
|
|
|
|
cmdbuf.pushConstants(pipeline_layout,
|
|
|
|
|
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex,
|
|
|
|
|
0, sizeof(info), &info);
|
|
|
|
|
|
|
|
|
@ -1032,9 +1080,8 @@ bool RendererVulkan::TryRenderScreenshotWithHostMemory() {
|
|
|
|
|
.imageExtent = {width, height, 1},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const vk::MemoryHostPointerPropertiesEXT import_properties =
|
|
|
|
|
device.getMemoryHostPointerPropertiesEXT(
|
|
|
|
|
vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT, aligned_pointer);
|
|
|
|
|
const auto import_properties = device.getMemoryHostPointerPropertiesEXT(
|
|
|
|
|
vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT, aligned_pointer);
|
|
|
|
|
|
|
|
|
|
if (!import_properties.memoryTypeBits) {
|
|
|
|
|
// Could not import memory
|
|
|
|
@ -1051,33 +1098,31 @@ bool RendererVulkan::TryRenderScreenshotWithHostMemory() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryHostPointerInfoEXT>
|
|
|
|
|
allocation_chain = {
|
|
|
|
|
vk::MemoryAllocateInfo{
|
|
|
|
|
.allocationSize = aligned_size,
|
|
|
|
|
.memoryTypeIndex = memory_type_index.value(),
|
|
|
|
|
},
|
|
|
|
|
vk::ImportMemoryHostPointerInfoEXT{
|
|
|
|
|
.handleType = vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT,
|
|
|
|
|
.pHostPointer = aligned_pointer,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const vk::StructureChain allocation_chain = {
|
|
|
|
|
vk::MemoryAllocateInfo{
|
|
|
|
|
.allocationSize = aligned_size,
|
|
|
|
|
.memoryTypeIndex = memory_type_index.value(),
|
|
|
|
|
},
|
|
|
|
|
vk::ImportMemoryHostPointerInfoEXT{
|
|
|
|
|
.handleType = vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT,
|
|
|
|
|
.pHostPointer = aligned_pointer,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Import host memory
|
|
|
|
|
const vk::UniqueDeviceMemory imported_memory =
|
|
|
|
|
device.allocateMemoryUnique(allocation_chain.get());
|
|
|
|
|
|
|
|
|
|
const vk::StructureChain<vk::BufferCreateInfo, vk::ExternalMemoryBufferCreateInfo> buffer_info =
|
|
|
|
|
{
|
|
|
|
|
vk::BufferCreateInfo{
|
|
|
|
|
.size = aligned_size,
|
|
|
|
|
.usage = vk::BufferUsageFlagBits::eTransferDst,
|
|
|
|
|
.sharingMode = vk::SharingMode::eExclusive,
|
|
|
|
|
},
|
|
|
|
|
vk::ExternalMemoryBufferCreateInfo{
|
|
|
|
|
.handleTypes = vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const vk::StructureChain buffer_info = {
|
|
|
|
|
vk::BufferCreateInfo{
|
|
|
|
|
.size = aligned_size,
|
|
|
|
|
.usage = vk::BufferUsageFlagBits::eTransferDst,
|
|
|
|
|
.sharingMode = vk::SharingMode::eExclusive,
|
|
|
|
|
},
|
|
|
|
|
vk::ExternalMemoryBufferCreateInfo{
|
|
|
|
|
.handleTypes = vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Bind imported memory to buffer
|
|
|
|
|
const vk::UniqueBuffer imported_buffer = device.createBufferUnique(buffer_info.get());
|
|
|
|
|