#include <cstdlib>
#include <dlfcn.h>
#include "VulkanGraphics.h"
#include "imgui_impl_vulkan.h"
#include <vulkan/vulkan_android.h>
#include <android/native_window.h>
#include <unistd.h>
#ifndef NDEBUG
static void check_vk_result(VkResult err) {
if (err == 0)
return;
fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err);
if (err < 0)
abort();
}
#else
static void check_vk_result(VkResult err) {
}
#endif
VkPhysicalDevice VulkanGraphics::SetupVulkan_SelectPhysicalDevice() {
uint32_t gpu_count;
VkResult err = vkEnumeratePhysicalDevices(m_Instance, &gpu_count, nullptr);
check_vk_result(err);
IM_ASSERT(gpu_count > 0);
ImVector<VkPhysicalDevice> gpus;
gpus.resize(gpu_count);
err = vkEnumeratePhysicalDevices(m_Instance, &gpu_count, gpus.Data);
check_vk_result(err);
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
for (VkPhysicalDevice &device: gpus) {
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(device, &properties);
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
return device;
}
// Use first GPU (Integrated) is a Discrete one is not available.
if (gpu_count > 0)
return gpus[0];
return VK_NULL_HANDLE;
}
bool VulkanGraphics::Create(ANativeWindow *Window, int m_Width, int m_Height) {
this->m_Window = Window;
if (InitVulkan() != 1) {
fprintf(stderr, "Vulkan is not supported %s\n", dlerror());
abort();
}
wd = std::make_unique<ImGui_ImplVulkanH_Window>();
//为imgui加载vulkan函数
void *libvulkan = dlopen("libvulkan.so", RTLD_NOW);
ImGui_ImplVulkan_LoadFunctions([](const char *function_name, void *handle) -> PFN_vkVoidFunction {
return reinterpret_cast<PFN_vkVoidFunction>(dlsym(handle, function_name));
}, libvulkan);
VkResult err;
// Create Vulkan Instance
{
const char *instance_extensions[] = {
"VK_KHR_surface",
"VK_KHR_android_surface",
};
VkApplicationInfo appInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = nullptr,
.pApplicationName = "pApplicationName",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "pEngineName",
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_MAKE_VERSION(1, 1, 0),
};
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &appInfo;
create_info.enabledExtensionCount = sizeof(instance_extensions) / sizeof(instance_extensions[0]);
create_info.ppEnabledExtensionNames = instance_extensions;
#ifdef IMGUI_VULKAN_DEBUG_REPORT
// Enabling validation layers
const char* layers[] = { "VK_LAYER_KHRONOS_validation" };
create_info.enabledLayerCount = 1;
create_info.ppEnabledLayerNames = layers;
// Enable debug report extension (we need additional storage, so we duplicate the user array to add our new extension to it)
const char** extensions_ext = (const char**)malloc(sizeof(const char*) * (extensions_count + 1));
memcpy(extensions_ext, extensions, extensions_count * sizeof(const char*));
extensions_ext[extensions_count] = "VK_EXT_debug_report";
create_info.enabledExtensionCount = extensions_count + 1;
create_info.ppEnabledExtensionNames = extensions_ext;
// Create Vulkan Instance
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
check_vk_result(err);
free(extensions_ext);
// Get the function pointer (required for any extensions)
auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT");
IM_ASSERT(vkCreateDebugReportCallbackEXT != NULL);
// Setup the debug report callback
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
debug_report_ci.pfnCallback = debug_report;
debug_report_ci.pUserData = NULL;
err = vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport);
check_vk_result(err);
#else
// Create Vulkan Instance without any debug feature
err = vkCreateInstance(&create_info, m_Allocator, &m_Instance);
check_vk_result(err);
IM_UNUSED(m_DebugReport);
#endif
}
// Select Physical Device (GPU)
m_PhysicalDevice = SetupVulkan_SelectPhysicalDevice();
// Select graphics queue family
{
uint32_t count;
vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &count, nullptr);
VkQueueFamilyProperties *queues = (VkQueueFamilyProperties *) malloc(sizeof(VkQueueFamilyProperties) * count);
vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &count, queues);
for (uint32_t i = 0; i < count; i++)
if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
m_QueueFamily = i;
break;
}
free(queues);
IM_ASSERT(m_QueueFamily != (uint32_t) -1);
}
// Create Logical Device (with 1 queue)
{
ImVector<const char *> device_extensions;
device_extensions.push_back("VK_KHR_swapchain");
// Enumerate physical device extension
uint32_t properties_count;
ImVector<VkExtensionProperties> properties;
vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &properties_count, nullptr);
properties.resize(properties_count);
vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &properties_count, properties.Data);
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
const float queue_priority[] = {1.0f};
VkDeviceQueueCreateInfo queue_info[1] = {};
queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[0].queueFamilyIndex = m_QueueFamily;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = queue_priority;
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
create_info.pQueueCreateInfos = queue_info;
create_info.enabledExtensionCount = (uint32_t) device_extensions.Size;
create_info.ppEnabledExtensionNames = device_extensions.Data;
err = vkCreateDevice(m_PhysicalDevice, &create_info, m_Allocator, &m_Device);
check_vk_result(err);
vkGetDeviceQueue(m_Device, m_QueueFamily, 0, &m_Queue);
}
// Create Descriptor Pool
{
VkDescriptorPoolSize pool_sizes[] =
{
{VK_DESCRIPTOR_TYPE_SAMPLER, 1000},
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000},
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000},
{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000}
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
pool_info.poolSizeCount = (uint32_t) IM_ARRAYSIZE(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(m_Device, &pool_info, m_Allocator, &m_DescriptorPool);
check_vk_result(err);
}
{
// Create Window Surface
VkSurfaceKHR surface;
VkAndroidSurfaceCreateInfoKHR createInfo{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.window = m_Window};
err = vkCreateAndroidSurfaceKHR(m_Instance, &createInfo, m_Allocator,
&surface);
check_vk_result(err);
wd->Surface = surface;
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(m_PhysicalDevice, m_QueueFamily, wd->Surface, &res);
if (res != VK_TRUE) {
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
const VkFormat requestSurfaceImageFormat[] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM};
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(m_PhysicalDevice, wd->Surface,
requestSurfaceImageFormat,
(size_t) IM_ARRAYSIZE(requestSurfaceImageFormat),
requestSurfaceColorSpace);
// 呈现模式
// 代码中已有逻辑,无需修改,只需确保不定义APP_USE_UNLIMITED_FRAME_RATE
#ifndef APP_USE_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_FIFO_KHR}; // 垂直同步模式
#endif
wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(m_PhysicalDevice, wd->Surface, &present_modes[0],
IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(m_MinImageCount >= 2);
// 在调用 ImGui_ImplVulkanH_CreateOrResizeWindow 前添加
m_MinImageCount = 2; // 双缓冲,或根据屏幕刷新率设置为3(三缓冲)
ImGui_ImplVulkanH_CreateOrResizeWindow(m_Instance, m_PhysicalDevice, m_Device, wd.get(), m_QueueFamily,
m_Allocator,
(int) m_Width, (int) m_Height, m_MinImageCount);
}
return true;
}
void VulkanGraphics::Setup() {
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = m_Instance;
init_info.PhysicalDevice = m_PhysicalDevice;
init_info.Device = m_Device;
init_info.QueueFamily = m_QueueFamily;
init_info.Queue = m_Queue;
init_info.PipelineCache = m_PipelineCache;
init_info.DescriptorPool = m_DescriptorPool;
init_info.RenderPass = wd->RenderPass;
init_info.Subpass = 0;
init_info.MinImageCount = m_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_2_BIT;
init_info.Allocator = m_Allocator;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
}
void VulkanGraphics::PrepareFrame(bool resize) {
if (m_SwapChainRebuild || resize) {
int width = ANativeWindow_getWidth(m_Window);
int height = ANativeWindow_getHeight(m_Window);
if (m_LastWidth == 0 || m_LastHeight == 0) {
m_LastWidth = width;
m_LastHeight = height;
}
if (width > 0 && height > 0) {
if (width != m_LastWidth || height != m_LastHeight) {
//切屏休息半秒
usleep(500000);
m_LastWidth = width;
m_LastHeight = height;
ImGui_ImplVulkan_SetMinImageCount(m_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(m_Instance, m_PhysicalDevice, m_Device, wd.get(),
m_QueueFamily, m_Allocator, width, height, m_MinImageCount);
wd->FrameIndex = 0;
m_SwapChainRebuild = false;
}
}
}
ImGui_ImplVulkan_NewFrame();
}
void VulkanGraphics::Render(ImDrawData *drawData) {
VkResult err;
VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
err = vkAcquireNextImageKHR(m_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE,
&wd->FrameIndex);
if (err == VK_ERROR_OUT_OF_DATE_KHR /*|| err == VK_SUBOPTIMAL_KHR*/) {
m_SwapChainRebuild = true;
return;
}
//check_vk_result(err);
ImGui_ImplVulkanH_Frame *fd = &wd->Frames[wd->FrameIndex];
{
err = vkWaitForFences(m_Device, 1, &fd->Fence, VK_TRUE,
UINT64_MAX); // wait indefinitely instead of periodically checking
check_vk_result(err);
err = vkResetFences(m_Device, 1, &fd->Fence);
check_vk_result(err);
}
{
err = vkResetCommandPool(m_Device, fd->CommandPool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
check_vk_result(err);
}
{
//透明 默认已经是0了
//memset(wd->ClearValue.color.float32, 0, sizeof(wd->ClearValue.color.float32));
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
info.pClearValues = &wd->ClearValue;
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(drawData, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
{
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &image_acquired_semaphore;
info.pWaitDstStageMask = &wait_stage;
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
err = vkQueueSubmit(m_Queue, 1, &info, fd->Fence);
check_vk_result(err);
}
{
if (m_SwapChainRebuild)
return;
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &render_complete_semaphore;
info.swapchainCount = 1;
info.pSwapchains = &wd->Swapchain;
info.pImageIndices = &wd->FrameIndex;
VkResult err = vkQueuePresentKHR(m_Queue, &info);
if (err == VK_ERROR_OUT_OF_DATE_KHR /*|| err == VK_SUBOPTIMAL_KHR*/) {
m_SwapChainRebuild = true;
return;
}
//check_vk_result(err);
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
}
}
void VulkanGraphics::PrepareShutdown() {
VkResult err = vkDeviceWaitIdle(m_Device);
check_vk_result(err);
ImGui_ImplVulkan_Shutdown();
}
//==========//
void VulkanGraphics::Cleanup() {
ImGui_ImplVulkanH_DestroyWindow(m_Instance, m_Device, wd.get(), m_Allocator);
vkDestroyDescriptorPool(m_Device, m_DescriptorPool, m_Allocator);
#ifdef APP_USE_VULKAN_DEBUG_REPORT
// Remove the debug report callback
auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT");
vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator);
#endif // APP_USE_VULKAN_DEBUG_REPORT
vkDestroyDevice(m_Device, m_Allocator);
vkDestroyInstance(m_Instance, m_Allocator);
}
//清理释放
// Helper function to find Vulkan memory type bits. See ImGui_ImplVulkan_MemoryType() in imgui_impl_vulkan.cpp
uint32_t VulkanGraphics::findMemoryType(uint32_t type_filter, VkMemoryPropertyFlags properties) {
VkPhysicalDeviceMemoryProperties mem_properties;
vkGetPhysicalDeviceMemoryProperties(m_PhysicalDevice, &mem_properties);
for (uint32_t i = 0; i < mem_properties.memoryTypeCount; i++)
if ((type_filter & (1 << i)) && (mem_properties.memoryTypes[i].propertyFlags & properties) == properties)
return i;
return 0xFFFFFFFF; // Unable to find memoryType
}
BaseTexData *VulkanGraphics::LoadTexture(BaseTexData *tex, void *pixel_data) {
auto *tex_data = new VulkanTextureData();
tex_data->Width = tex->Width;
tex_data->Height = tex->Height;
tex_data->Channels = tex->Channels;
// tex_data->UserData=
// Calculate allocation size (in number of bytes)
size_t image_size = tex_data->Width * tex_data->Height * tex_data->Channels;
VkResult err;
// Create the Vulkan image.
{
VkImageCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = VK_IMAGE_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.extent.width = tex_data->Width;
info.extent.height = tex_data->Height;
info.extent.depth = 1;
info.mipLevels = 1;
info.arrayLayers = 1;
info.samples = VK_SAMPLE_COUNT_2_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
err = vkCreateImage(m_Device, &info, m_Allocator, &tex_data->Image);
check_vk_result(err);
VkMemoryRequirements req;
vkGetImageMemoryRequirements(m_Device, tex_data->Image, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = findMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
err = vkAllocateMemory(m_Device, &alloc_info, m_Allocator, &tex_data->ImageMemory);
check_vk_result(err);
err = vkBindImageMemory(m_Device, tex_data->Image, tex_data->ImageMemory, 0);
check_vk_result(err);
}
// Create the Image View
{
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = tex_data->Image;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
err = vkCreateImageView(m_Device, &info, m_Allocator, &tex_data->ImageView);
check_vk_result(err);
}
// Create Sampler
{
VkSamplerCreateInfo sampler_info{};
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler_info.magFilter = VK_FILTER_LINEAR;
sampler_info.minFilter = VK_FILTER_LINEAR;
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; // outside image bounds just use border color
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.minLod = -1000;
sampler_info.maxLod = 1000;
sampler_info.maxAnisotropy = 1.0f;
err = vkCreateSampler(m_Device, &sampler_info, m_Allocator, &tex_data->Sampler);
check_vk_result(err);
}
// Create Descriptor Set using ImGUI's implementation
tex_data->DS = (void *) ImGui_ImplVulkan_AddTexture(tex_data->Sampler, tex_data->ImageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Create Upload Buffer
{
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = image_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
err = vkCreateBuffer(m_Device, &buffer_info, m_Allocator, &tex_data->UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
vkGetBufferMemoryRequirements(m_Device, tex_data->UploadBuffer, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = findMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
err = vkAllocateMemory(m_Device, &alloc_info, m_Allocator, &tex_data->UploadBufferMemory);
check_vk_result(err);
err = vkBindBufferMemory(m_Device, tex_data->UploadBuffer, tex_data->UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
void *map = NULL;
err = vkMapMemory(m_Device, tex_data->UploadBufferMemory, 0, image_size, 0, &map);
check_vk_result(err);
memcpy(map, pixel_data, image_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = tex_data->UploadBufferMemory;
range[0].size = image_size;
err = vkFlushMappedMemoryRanges(m_Device, 1, range);
check_vk_result(err);
vkUnmapMemory(m_Device, tex_data->UploadBufferMemory);
}
// Create a command buffer that will perform following steps when hit in the command queue.
// TODO: this works in the example, but may need input if this is an acceptable way to access the pool/create the command buffer.
VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
VkCommandBuffer command_buffer;
{
VkCommandBufferAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandPool = command_pool;
alloc_info.commandBufferCount = 1;
err = vkAllocateCommandBuffers(m_Device, &alloc_info, &command_buffer);
check_vk_result(err);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(command_buffer, &begin_info);
check_vk_result(err);
}
// Copy to Image
{
VkImageMemoryBarrier copy_barrier[1] = {};
copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
copy_barrier[0].image = tex_data->Image;
copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_barrier[0].subresourceRange.levelCount = 1;
copy_barrier[0].subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL,
0,
NULL, 1, copy_barrier);
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1;
region.imageExtent.width = tex_data->Width;
region.imageExtent.height = tex_data->Height;
region.imageExtent.depth = 1;
vkCmdCopyBufferToImage(command_buffer, tex_data->UploadBuffer, tex_data->Image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
VkImageMemoryBarrier use_barrier[1] = {};
use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
use_barrier[0].image = tex_data->Image;
use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
use_barrier[0].subresourceRange.levelCount = 1;
use_barrier[0].subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL, 0, NULL, 1, use_barrier);
}
// End command buffer
{
VkSubmitInfo end_info = {};
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
end_info.commandBufferCount = 1;
end_info.pCommandBuffers = &command_buffer;
err = vkEndCommandBuffer(command_buffer);
check_vk_result(err);
err = vkQueueSubmit(m_Queue, 1, &end_info, VK_NULL_HANDLE);
check_vk_result(err);
err = vkDeviceWaitIdle(m_Device);
check_vk_result(err);
}
return tex_data;
}
void VulkanGraphics::RemoveTexture(BaseTexData *tex) {
auto *tex_data = (VulkanTextureData *) (tex);
vkFreeMemory(m_Device, tex_data->UploadBufferMemory, nullptr);
vkDestroyBuffer(m_Device, tex_data->UploadBuffer, nullptr);
vkDestroySampler(m_Device, tex_data->Sampler, nullptr);
vkDestroyImageView(m_Device, tex_data->ImageView, nullptr);
vkDestroyImage(m_Device, tex_data->Image, nullptr);
vkFreeMemory(m_Device, tex_data->ImageMemory, nullptr);
ImGui_ImplVulkan_RemoveTexture((VkDescriptorSet) tex_data->DS);
delete tex_data;
}
TextureInfo VulkanGraphics::ImAgeHeadFile(const unsigned char *buf, int len) {
TextureInfo ret_data{0};
BaseTexData tex_data{};
tex_data.Channels = 4;
//unsigned char *image_data = loadFunc(&tex_data);
unsigned char *image_data = stbi_load_from_memory((const stbi_uc *) buf, len, &tex_data.Width, &tex_data.Height, nullptr, tex_data.Channels);
if (image_data == nullptr)
return ret_data;
auto result = LoadTexture(&tex_data, image_data);
stbi_image_free(image_data);
ret_data.textureId = (ImTextureID)result->DS;
ret_data.w = tex_data.Width;
ret_data.h = tex_data.Height;
return ret_data;
}
怎么改成 3 合缓冲
最新发布