create_semaphore.cpp

本文提供了一个使用信号量进行线程同步的示例代码。该示例展示了如何创建信号量、启动子线程等待信号量、保持信号量一段时间并最终释放信号量的过程。通过消息传递来显示同步操作的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5572165936844014&dt=1194442938015&lmt=1194190197&format=336x280_as&output=html&correlator=1194442937843&url=file%3A%2F%2F%2FC%3A%2FDocuments%2520and%2520Settings%2Flhh1%2F%E6%A1%8C%E9%9D%A2%2FCLanguage.htm&color_bg=FFFFFF&color_text=000000&color_link=000000&color_url=FFFFFF&color_border=FFFFFF&ad_type=text&ga_vid=583001034.1194442938&ga_sid=1194442938&ga_hid=1942779085&flash=9&u_h=768&u_w=1024&u_ah=740&u_aw=1024&u_cd=32&u_tz=480&u_java=true" frameborder="0" width="336" scrolling="no" height="280" allowtransparency="allowtransparency"> #include <genstub.cpp>

// This is a child thread procedure that waits for a semaphore,
// holds the semaphore for five seconds, and releases the semaphore.
// Threads that cannot get semaphores will wait until other threads exit.
DWORD WINAPI ChildThreadProc( HWND hWnd )
{
    TCHAR szBuffer[256];                            // buffer
    DWORD dwSemCount = 0;                           // printing semaphore count
    HANDLE hSemaphore = OpenSemaphore( SYNCHRONIZE, FALSE, "TEST_SEMAPHORE" );
    wsprintf( szBuffer,"Thread %x waiting for semaphore %x",
             GetCurrentThreadId( ), hSemaphore );
    SendMessage( hWnd, WM_USER, 0, (LPARAM) szBuffer );
    // Check for signaled semaphore.
    WaitForSingleObject( hSemaphore, INFINITE );
    wsprintf( szBuffer,"Thread %x got semaphore", GetCurrentThreadId( ) );
    SendMessage( hWnd, WM_USER, 0, (LPARAM) szBuffer );
    Sleep( 5000 );
    // Release semaphore.
    ReleaseSemaphore( hSemaphore, 1, &dwSemCount );
    wsprintf( szBuffer,"Thread %x is done with semaphore. Its count was %ld.",
            GetCurrentThreadId( ), dwSemCount );
    SendMessage( hWnd, WM_USER, 0, (LPARAM) szBuffer );
    CloseHandle( hSemaphore );
    ExitThread( TRUE );
}

// Windows message procedure.
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   static HANDLE hSemaphore = 0;

   switch (uMsg)
   {
           case WM_CREATE:
                   hSemaphore = CreateSemaphore( NULL, 4, 4, "TEST_SEMAPHORE" );
                   return DefWindowProc( hWnd, uMsg, wParam, lParam );
           case WM_COMMAND:       // process menu items
                   switch ( LOWORD( wParam )  )
                   {
                      case IDM_TEST:     // start up a thread.
                        {
                           DWORD dwChildId;
                           CreateThread( NULL, 0, ChildThreadProc, hWnd, 0, &dwChildId );
                        }
                        break;
                      case IDM_EXIT:
                           DestroyWindow( hWnd );
                           break;
                   }
           break;
           case WM_USER:
                   {  // Message to show synchronization actions.
                      TCHAR szBuffer[101];
                      static int row = 0;
                      static int msg_num = 1;
                      HDC hDC = GetDC( hWnd );
                      FillMemory( szBuffer, 100, 32 );
                      TextOut( hDC, 0, row, szBuffer, 100 );
                      wsprintf( szBuffer, "%3d: %s", msg_num++, (LPTSTR)lParam );
                      TextOut( hDC, 0, row, szBuffer, lstrlen( szBuffer ) );
                      if ( row > 200 )
                         row = 0;
                      else
                         row += 20;
                      ReleaseDC( hWnd, hDC );
                   }
                   break;
           case WM_DESTROY:
                   if ( hSemaphore )
                      CloseHandle( hSemaphore );
                   PostQuitMessage( 0 );
                   break;
           default:
                return DefWindowProc( hWnd, uMsg, wParam, lParam );
   }
   return NULL;
}

#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, &region); 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 合缓冲
最新发布
07-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值