How to render Vulkan's scene to ImGui window - vulkan

https://github.com/ocornut/imgui/issues/5110
Version: 1.87
Branch: docking
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_Vulkan.cpp + imgui_impl_Vulkan.cpp
Operating System: MacOS
My Issue/Question:
How to render Vulakn's scene to ImGui window?
want to achieve this:
image
I have read various documents and #914,but I'm still at a loss.
Maybe I'm close to the answer?
Here is my project code, built quickly via CMake. It is implemented with reference to the Vulkan tutorial.
Also would appreciate any help, thanks a lot.
The key code is here:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");
ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});
ImGui::End();
I tried several ways:
According to this code I got it:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");
ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});
ImGui::End();
image
According to this code I got it:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_SwapChainImageViews[currentFrame], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// std::vector<VkImageView> m_SwapChainImageViews;
...
ImGui::Begin("Viewport");
ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});
ImGui::End();
image
But when I drag the ImGui window to the main window:
image
3.last attempt:
// remove m_Dset = ImGui_ImplVulkan_AddTexture(...);
...
ImGui::Begin("Viewport");
ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_DescriptorSets[currentFrame], ImVec2{viewportPanelSize.x, viewportPanelSize.y});
ImGui::End();
I got it:
image
Hope you understand what I mean......Any help would be greatly appreciated.It can be quickly reproduced with the items provided above, if you have the time.
I've been stuck for days.
ps: I'm working tirelessly on problems I've encountered while learning Vulkan and ImGui. I have a cold because of it. 😭😭😭😭😭
I must be low IQ.
I have these variables:
private:
GLFWwindow *m_Window;
VkInstance m_Instance;
VkDebugUtilsMessengerEXT m_DebugMessenger;
VkPhysicalDevice m_PhysicalDevice = VK_NULL_HANDLE;
VkDevice m_Device;
VkQueue m_GraphicsQueue;
VkQueue m_PresentQueue;
VkSurfaceKHR m_Surface;
VkSwapchainKHR m_SwapChain;
std::vector<VkImage> m_SwapChainImages;
VkFormat m_SwapChainImageFormat;
VkExtent2D m_SwapChainExtent;
std::vector<VkImageView> m_SwapChainImageViews;
VkRenderPass m_RenderPass;
VkDescriptorSetLayout m_DescriptorSetLayout;
VkPipelineLayout m_PipelineLayout;
VkPipeline m_GraphicsPipeline;
std::vector<VkFramebuffer> m_SwapChainFramebuffers;
VkCommandPool m_CommandPool;
// for imgui
VkDescriptorPool m_ImGuiDescriptorPool;
VkRenderPass m_ImGuiRenderPass;
std::vector<VkFramebuffer> m_ImGuiFramebuffers;
VkCommandPool m_ImGuiCommandPool;
std::vector<VkCommandBuffer> m_ImGuiCommandBuffers;
VkImage m_TextureImage;
VkDeviceMemory m_TextureImageMemory;
VkImageView m_TextureImageView;
VkSampler m_TextureSampler;
VkImage m_DepthImage;
VkDeviceMemory m_DepthImageMemory;
VkImageView m_DepthImageView;
VkBuffer m_VertexBuffer;
VkDeviceMemory m_VertexBufferMemory;
VkBuffer m_IndexBuffer;
VkDeviceMemory m_IndexBufferMemory;
// UniformBuffer
std::vector<VkBuffer> m_UniformBuffers;
std::vector<VkDeviceMemory> m_UniformBuffersMemory;
VkDescriptorPool m_DescriptorPool;
std::vector<VkDescriptorSet> m_DescriptorSets;
std::vector<VkCommandBuffer> m_CommandBuffers;
std::vector<VkSemaphore> m_ImageAvailableSemaphores;
std::vector<VkSemaphore> m_RenderFinishedSemaphores;
std::vector<VkFence> m_InFlightFences;
QueueFamilyIndices m_QueueFamilyIndices;
uint32_t currentFrame = 0;
uint32_t m_ImageCount = 2;
VkDescriptorSet m_Dset;
void initVulkan()
{
createInstance();
setupDebugMessenger();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
createSwapChain();
createImageViews();
createRenderPass();
createDescriptorSetLayout();
createGraphicsPipeline();
createCommandPool(&m_CommandPool);
createDepthResources();
createFramebuffers();
createTextureImage();
createTextureImageView();
createTextureSampler();
createVertexBuffer();
createIndexBuffer();
createUniformBuffers();
createDescriptorPool();
createDescriptorSets();
createCommandBuffers();
createSyncObjects();
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
ImGui::StyleColorsDark();
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle &style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
{
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;
if (vkCreateDescriptorPool(m_Device, &pool_info, nullptr, &m_ImGuiDescriptorPool) != VK_SUCCESS)
throw std::runtime_error("Create DescriptorPool for m_ImGuiDescriptorPool failed!");
}
// Create RenderPass for m_ImGuiRenderPass
{
createImGuiRenderPass();
}
// Create CommandPool for m_ImGuiCommandPool
{
createCommandPool(&m_ImGuiCommandPool);
}
// Create CommandBuffers for m_ImGuiCommandBuffers
{
createImGuiCommandBuffers();
}
{
createImGuiFramebuffers();
}
ImGui_ImplGlfw_InitForVulkan(m_Window, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = m_Instance;
init_info.PhysicalDevice = m_PhysicalDevice;
init_info.Device = m_Device;
init_info.QueueFamily = m_QueueFamilyIndices.graphicsFamily.value();
init_info.Queue = m_GraphicsQueue;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.DescriptorPool = m_ImGuiDescriptorPool;
init_info.Subpass = 0;
init_info.MinImageCount = m_ImageCount;
init_info.ImageCount = m_ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = nullptr;
init_info.CheckVkResultFn = nullptr;
ImGui_ImplVulkan_Init(&init_info, m_ImGuiRenderPass);
// Upload Fonts
{
VkCommandBuffer commandBuffer = beginSingleTimeCommands(m_ImGuiCommandPool);
ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
endSingleTimeCommands(commandBuffer, m_ImGuiCommandPool);
ImGui_ImplVulkan_DestroyFontUploadObjects();
}
// m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void drawFrame()
{
vkWaitForFences(m_Device, 1, &m_InFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(m_Device, m_SwapChain, UINT64_MAX, m_ImageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
{
recreateSwapChain();
return;
}
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
throw std::runtime_error("failed to acquire swap chain image!");
}
// Only reset the fence if we are submitting work
vkResetFences(m_Device, 1, &m_InFlightFences[currentFrame]);
// vkResetCommandBuffer(m_CommandBuffers[currentFrame], 0);
recordCommandBuffer(m_CommandBuffers[currentFrame], imageIndex, m_DescriptorSets[currentFrame]);
{
// vkResetCommandPool(m_Device, m_ImGuiCommandPool, 0);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(m_ImGuiCommandBuffers[currentFrame], &info);
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_ImGuiRenderPass;
renderPassInfo.framebuffer = m_ImGuiFramebuffers[imageIndex];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_SwapChainExtent;
VkClearValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;
vkCmdBeginRenderPass(m_ImGuiCommandBuffers[currentFrame], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), m_ImGuiCommandBuffers[currentFrame]);
vkCmdEndRenderPass(m_ImGuiCommandBuffers[currentFrame]);
vkEndCommandBuffer(m_ImGuiCommandBuffers[currentFrame]);
}
updateUniformBuffer(currentFrame);
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
std::array<VkCommandBuffer, 2> submitCommandBuffers =
{m_CommandBuffers[currentFrame], m_ImGuiCommandBuffers[currentFrame]};
VkSemaphore waitSemaphores[] = {m_ImageAvailableSemaphores[currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = static_cast<uint32_t>(submitCommandBuffers.size());
submitInfo.pCommandBuffers = submitCommandBuffers.data();
VkSemaphore signalSemaphores[] = {m_RenderFinishedSemaphores[currentFrame]};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, m_InFlightFences[currentFrame]) != VK_SUCCESS)
{
throw std::runtime_error("failed to submit draw command buffer!");
}
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = {m_SwapChain};
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr; // Optional
result = vkQueuePresentKHR(m_PresentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_FramebufferResized)
{
m_FramebufferResized = false;
recreateSwapChain();
}
else if (result != VK_SUCCESS)
{
throw std::runtime_error("failed to present swap chain image!");
}
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
void recordCommandBuffer(const VkCommandBuffer &commandBuffer, const uint32_t &imageIndex, const VkDescriptorSet &descriptorSet)
{
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
// beginInfo.flags = 0; // Optional
// beginInfo.pInheritanceInfo = nullptr; // Optional
if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS)
{
throw std::runtime_error("failed to begin recording command buffer!");
}
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_RenderPass;
renderPassInfo.framebuffer = m_SwapChainFramebuffers[imageIndex];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_SwapChainExtent;
std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_GraphicsPipeline);
VkBuffer vertexBuffers[] = {m_VertexBuffer};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, m_IndexBuffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_PipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffer);
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
{
throw std::runtime_error("failed to record command buffer!");
}
}

For me image just not rendering in ImGui::Image and i don't know why. I saw my image in shader inputs, but in shader outputs i had just black color.
I guess in your case you should render your scene to another image (not swapchain image). And it means that you need to use another render pass for it. Use swapchain images only for imgui output.

I think when we createSwapChain(); set
VkSurfaceFormatKHR surfaceFormat;
surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
like this to avoid validation error!

Related

VK_ERROR_SURFACE_LOST_KHR while executing vkGetPhysicalDeviceSurfaceCapabilitiesKHR()

I met some problem while learning Vulkan. I followed Vulkan Coockbook but I failed on executing vkGetPhysicalDeviceSurfaceCapabilitiesKHR(), it returned VK_ERROR_SURFACE_LOST_KHR. I have no idea what the wrong is with my code.
CyApplication::CyApplication(void) {
#ifdef _WIN32
VulkanLibrary = LoadLibrary(L"vulkan-1.dll");
#elif defined __linux
VulkanLibrary = dlopen("libvulkan.so.1", RTLD_NOW);
#endif
if (VulkanLibrary == nullptr) {
throw std::runtime_error("");
}
#ifdef _WIN32
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(VulkanLibrary, "vkGetInstanceProcAddr");
#elif defined __linux
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(VulkanLibrary, "vkGetInstanceProcAddr");
#endif
// Load global functions
vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceExtensionProperties");
vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceLayerProperties");
vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(nullptr, "vkCreateInstance");
// Create instance
desiredInstanceExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
desiredInstanceExtensions.emplace_back(
#ifdef VK_USE_PLATFORM_WIN32_KHR
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_XLIB_KHR
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_XCB_KHR
VK_KHR_XCB_SURFACE_EXTENSION_NAME
#endif
);
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pNext = nullptr;
applicationInfo.pApplicationName = "Cygine";
applicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
applicationInfo.pEngineName = "Cygine";
applicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pNext = nullptr;
instanceCreateInfo.flags = 0;
instanceCreateInfo.pApplicationInfo = &applicationInfo;
instanceCreateInfo.enabledLayerCount = 0;
instanceCreateInfo.ppEnabledLayerNames = nullptr;
instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(desiredInstanceExtensions.size());
instanceCreateInfo.ppEnabledExtensionNames = desiredInstanceExtensions.data();
if (vkCreateInstance(&instanceCreateInfo, nullptr, &instance)) {
throw std::runtime_error("Failed to create the Vulkan instance.");
}
loadInstanceLevelFunctions();
// Create presentation surface
#ifdef VK_USE_PLATFORM_WIN32_KHR
wndParams.HInstance = GetModuleHandle(nullptr);
WNDCLASSEX window_class = {
sizeof(WNDCLASSEX), // UINT cbSize
// Win 3.x
CS_HREDRAW | CS_VREDRAW, // UINT style
WindowProcedure, // WNDPROC lpfnWndProc
0, // int cbClsExtra
0, // int cbWndExtra
wndParams.HInstance, // HINSTANCE hInstance
nullptr, // HICON hIcon
LoadCursor(nullptr, IDC_ARROW), // HCURSOR hCursor
(HBRUSH)(COLOR_WINDOW + 1), // HBRUSH hbrBackground
nullptr, // LPCSTR lpszMenuName
L"CygineWindow", // LPCSTR lpszClassName
// Win 4.0
nullptr // HICON hIconSm
};
if (!RegisterClassEx(&window_class)) {
throw std::runtime_error("WSL");
}
wndParams.Hwnd = CreateWindow(L"CyApplicationWindow",
L"CyApplication",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
(HWND)nullptr,
(HMENU)nullptr,
wndParams.HInstance,
(LPVOID)nullptr);
if (wndParams.Hwnd = nullptr) {
throw std::runtime_error("");
}
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.HInstance;
surfaceCreateInfo.hwnd = wndParams.Hwnd;
ShowWindow(wndParams.Hwnd, SW_SHOW);
VkResult result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS) {
exit(EXIT_FAILURE);
}
#elif defined VK_USE_PLATFORM_XLIB_KHR
wndParams.dpy = XOpenDisplay();
wndParams.window = XCreateWindow(nullptr);
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.dpy;
surfaceCreateInfo.hwnd = wndParams.window;
VkResult result = vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS || surface == VK_NULL_HANDLE) {
exit(EXIT_FAILURE);
}
#elif defined VK_USE_PLATFORM_XCB_KHR
wndParams.connect = xcb_connect();
wndParams.window = xcb_generate_id(nullptr);
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.dpy;
surfaceCreateInfo.hwnd = wndParams.window;
VkResult result = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS || surface == VK_NULL_HANDLE) {
exit(EXIT_FAILURE);
}
#endif
// Select physical device
desiredPhysicalDeviceExtensions.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
getAvailablePhysicalDevices();
do {
fmt::print("Select a physical device that Cygine will run on: ");
std::cin >> selectedPhysicalDeviceID;
} while (selectedPhysicalDeviceID >= availablePhysicalDevicesCount);
physicalDevice = availablePhysicalDevices[selectedPhysicalDeviceID];
getAvailablePhysicalDeviceExtensions(physicalDevice);
// Create logical device
getPhysicalDeviceQueueFamilyProperties(availablePhysicalDevices[selectedPhysicalDeviceID]);
selectQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.pNext = nullptr;
queueCreateInfo.flags = 0;
queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.pNext = nullptr;
deviceCreateInfo.flags = 0;
deviceCreateInfo.queueCreateInfoCount = /*static_cast<uint32_t>(queueCreateInfos.size())*/ 1;
deviceCreateInfo.pQueueCreateInfos = /*queueCreateInfos.data()*/ &queueCreateInfo;
deviceCreateInfo.enabledLayerCount = 0;
deviceCreateInfo.ppEnabledLayerNames = nullptr;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(desiredPhysicalDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = desiredPhysicalDeviceExtensions.data();
deviceCreateInfo.pEnabledFeatures = &desiredDeviceFeatures;
if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
loadDeviceLevelFunctions();
// Create presentation surface
/*
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(640, 480, "Window Title", NULL, NULL);
if (glfwCreateWindowSurface(instance, window, nullptr, &surface))
throw std::runtime_error("failed to create");
*/
getSurfaceCapabilities();
fmt::print("Min Image Count: {}\n", surfaceCapabilities.minImageCount);
}
} // CygineApplicationAbstractions
Above is a part of my code. Have to say cooking Vulkan is really trivial 😭... Does any one have an idea? Hope you can solve my problem. Thanks!
if (wndParams.Hwnd = nullptr) {
You assign nullptr to Hwnd, so the surface is invalid when you query it.

Cannot create logical device only in debug mode

I'm getting VK_ERROR_FEATURE_NOT_PRESENT(-8).
But i'm using vkGetPhysicalDeviceFeatures to get features.
My Code:
std::vector<VkDeviceQueueCreateInfo> LogicalDevice::CreateDeviceQueueCreateInfos(QueueFamilies queueFamilies)
{
std::vector uniqueQueueFamilies = queueFamilies.GetUniqueQueueFamilies();
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
for (auto queueFamily : uniqueQueueFamilies)
{
const int countOfQueues = queueFamily.CountOfQueues;
std::vector<float> queuePriorities(countOfQueues);
for (int indexOfPriority = 0; indexOfPriority < countOfQueues; indexOfPriority++)
{
queuePriorities[indexOfPriority] = 1.0f - ( (float) indexOfPriority / countOfQueues);
}
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily.Index.value();
queueCreateInfo.queueCount = queueFamily.CountOfQueues;
queueCreateInfo.flags = queueFamily.Flags;
queueCreateInfo.pQueuePriorities = queuePriorities.data();
queueCreateInfos.push_back(queueCreateInfo);
}
return queueCreateInfos;
}
VkDeviceCreateInfo LogicalDevice::GetDeviceCreateInfo(std::vector<VkDeviceQueueCreateInfo> deviceQueueCreateInfos, VkPhysicalDevice physicalDevice)
{
VkPhysicalDeviceFeatures deviceFeatures{};
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
VkDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(deviceQueueCreateInfos.size());
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfos.data();
deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
return deviceCreateInfo;
}
void LogicalDevice::Initialize(VkPhysicalDevice physicalDevice, VkSurfaceKHR surfaceForPickingPhysicalDevice)
{
m_queueFamilies = QueueFamilies::GetQueueFamilies(physicalDevice, surfaceForPickingPhysicalDevice);
std::vector<VkDeviceQueueCreateInfo> deviceQueueCreateInfos = CreateDeviceQueueCreateInfos(m_queueFamilies);
VkDeviceCreateInfo deviceCreateInfo = GetDeviceCreateInfo(deviceQueueCreateInfos, physicalDevice);
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &m_vulkanDevice);
if (result != VK_SUCCESS)
{
throw new std::runtime_error("Cannot create logical device.");
}
}
The deviceFeature variable that you read the features into and which is pointed at in the create info structure is local to GetDeviceCreateInfo. This is out-of-scope at the point where you call vkCreateDevice, which results in undefined behavior. You're probably getting random junk at device creation time instead, which causes that error.

Input attachment from previous subpass in Vulkan

I am trying to first render some content to an R8_UNORM image view in subpass 0, and then use the result as an input attachment in subpass 1, using subpassLoad in the fragment shader. However, the final output from the render pass (which is also the swapchain image(s) that is presented) contains garbage (see https://imgur.com/a/RmNdcxg) using the following fragment shader:
#version 420
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput input_text;
layout(location=0) out vec4 color;
void main()
{
float value = subpassLoad(input_text).r;
if (value > 0.0f) {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
}
Yet, using this fragment shader:
#version 420
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput input_text;
layout(location=0) out vec4 color;
void main()
{
float value = subpassLoad(input_text).r;
if (value > 0.0f) {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
else {
color = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
}
gives me the expected results (see https://imgur.com/a/JfhuJUk), so I'm suspecting some synchronization issue that isn't present when each fragment is written to.
The clear values used for the two framebuffer attachments are as follows:
VkClearColorValue black_clear_color = { 0.0f, 0.0f, 0.0f, 0.0f };
VkClearColorValue red_clear_color = { 1.0f, 0.0f, 0.0f, 1.0f };
VkClearValue clear_value[2];
clear_value[0].color = vk_black_clear_color; // R8_UNORM attachment
clear_value[1].color = vk_red_clear_color; // Swapchain attachment
with the fragment shader for subpass 0 always writing 1.0f to each fragment it is to shade.
Here's what I deem to be the relevant code:
Command buffer recording, submission, and image presentation
// Record
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, text_graphics_pipeline);
vkCmdBindVertexBuffers(command_buffer, 0, 1, &text_vertex_buffer, &vertex_buffer_offset);
vkCmdDraw(command_buffer, 15, 1, 0, 0);
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, final_graphics_pipeline);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, final_pipeline_layout, 0, 1, &final_descriptor_set, 0, NULL);
vkCmdBindVertexBuffers(command_buffer, 0, 1, &final_vertex_buffer, &vertex_buffer_offset);
vkCmdDraw(command_buffer, 6, 1, 0, 0);
vkCmdEndRenderPass(command_buffer);
CHECK_VK_RES(vkEndCommandBuffer(command_buffer));
// Submit
VkPipelineStageFlags pipeline_wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &swapchain_image_avilable_semaphore;
submit_info.pWaitDstStageMask = &pipeline_wait_stages;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &command_buffer_finished_semaphore;
CHECK_VK_RES(vkQueueSubmit(queue, 1, &submit_info, command_buffer_finished_fence));
// Present
VkPresentInfoKHR present_info;
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = NULL;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &command_buffer_finished_semaphore;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &image_available_idx;
present_info.pResults = NULL;
CHECK_VK_RES(vkQueuePresentKHR(queue, &present_info));
Render Pass Setup
// Render pass attachments
VkAttachmentDescription vk_render_pass_attachment_descriptions[2];
// Text attachment
render_pass_attachment_descriptions[0].flags = 0;
render_pass_attachment_descriptions[0].format = VK_FORMAT_R8_UNORM;
render_pass_attachment_descriptions[0].samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment_descriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment_descriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment_descriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment_descriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment_descriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment_descriptions[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// Final attachment
render_pass_attachment_descriptions[1].flags = 0;
render_pass_attachment_descriptions[1].format = swapchain_format; // BGRA8_UNORM
render_pass_attachment_descriptions[1].samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment_descriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment_descriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment_descriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment_descriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment_descriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment_descriptions[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// Subpass descriptions
VkSubpassDescription render_pass_subpass_descriptions[2];
// Subpass 0
VkAttachmentReference text_subpass_color_attachment_reference;
text_subpass_color_attachment_reference.attachment = 0;
text_subpass_color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_subpass_descriptions[0].flags = 0;
render_pass_subpass_descriptions[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass_descriptions[0].inputAttachmentCount = 0;
render_pass_subpass_descriptions[0].pInputAttachments = NULL;
render_pass_subpass_descriptions[0].colorAttachmentCount = 1;
render_pass_subpass_descriptions[0].pColorAttachments = &text_subpass_color_attachment_reference;
render_pass_subpass_descriptions[0].pResolveAttachments = NULL;
render_pass_subpass_descriptions[0].pDepthStencilAttachment = NULL;
render_pass_subpass_descriptions[0].preserveAttachmentCount = 0;
render_pass_subpass_descriptions[0].pPreserveAttachments = NULL;
// Subpass 1
VkAttachmentReference final_subpass_input_attachment_reference;
final_subpass_input_attachment_reference.attachment = 0;
final_subpass_input_attachment_reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference final_subpass_color_attachment_reference;
final_subpass_color_attachment_reference.attachment = 1;
final_subpass_color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_subpass_descriptions[1].flags = 0;
render_pass_subpass_descriptions[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass_descriptions[1].inputAttachmentCount = 1;
render_pass_subpass_descriptions[1].pInputAttachments = &final_subpass_input_attachment_reference;
render_pass_subpass_descriptions[1].colorAttachmentCount = 1;
render_pass_subpass_descriptions[1].pColorAttachments = &final_subpass_color_attachment_reference;
render_pass_subpass_descriptions[1].pResolveAttachments = NULL;
render_pass_subpass_descriptions[1].pDepthStencilAttachment = NULL;
render_pass_subpass_descriptions[1].preserveAttachmentCount = 0;
render_pass_subpass_descriptions[1].pPreserveAttachments = NULL;
// Subpass dependencies
VkSubpassDependency renderpass_subpass_dependencies[2];
// Ensure subpass 1's color attachment (swapchain image) is transitioned before it's written to
// since the pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
renderpass_subpass_dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
renderpass_subpass_dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[0].srcAccessMask = 0;
renderpass_subpass_dependencies[0].dstSubpass = 1;
renderpass_subpass_dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
renderpass_subpass_dependencies[0].dependencyFlags = 0;
// Subpass 1 cannot read from its input attachment before subpass 0 finishes writing to its color attachment
renderpass_subpass_dependencies[1].srcSubpass = 0;
renderpass_subpass_dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
renderpass_subpass_dependencies[1].dstSubpass = 1;
renderpass_subpass_dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
renderpass_subpass_dependencies[1].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
renderpass_subpass_dependencies[1].dependencyFlags = 0;
// Render pass
VkRenderPassCreateInfo render_pass_info;
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.pNext = NULL;
render_pass_info.flags = 0;
render_pass_info.attachmentCount = 2;
render_pass_info.pAttachments = render_pass_attachment_descriptions;
render_pass_info.subpassCount = 2;
render_pass_info.pSubpasses = render_pass_subpass_descriptions;
render_pass_info.dependencyCount = 2;
render_pass_info.pDependencies = renderpass_subpass_dependencies;
VkRenderPass render_pass;
CHECK_VK_RES(vkCreateRenderPass(vk_device, &render_pass_info, NULL, &render_pass));
Any help would be greatly appreciated, as I can't seem to see what's wrong here.
The synchronization was not the culprit here. Rather, it was the fact that the out vec4 color from subpass 1 was always written out to the framebuffer (as the geometry is a full-screen quad), even though it wasn't initialized to anything if the if-condition wasn't satisfied.
By adding a discard to the shader in the else-clause, the correct output is obtained:
#version 420
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput input_text;
layout(location=0) out vec4 color;
void main()
{
float value = subpassLoad(input_text).r;
if (value > 0.0f) {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
else {
discard;
}
}
As an "fun" fact: the reason the incorrect image in the question isn't very blue in the top-left corner, but is blue for most of the rest of the image is probably that the registers that are used to store the values in color are re-used. So in the beginning (assuming the work starts from the top-left corner), the registers contain garbage, but as actual blue fragments are written out, more and more registers have old blue values in them. Therefore, when the else-clause is active, blue is written out, even though its technically garbage.

How to to create a 1D Texture in Vulkan

I have a problem to create a 1D texture and I don't know how to solve it.
The texture is a float pData[256][4].
The code is like this:
VkDeviceSize imageSize = 256 * 4 * 4;
uint32_t texMemSize = ftsize;
VkBuffer stagingBuffer;
VkDeviceMemory stagingMemory;
VkBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = imageSize;
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to create buffer!");
}
VkMemoryAllocateInfo memAllocInfo2 = { };
memAllocInfo2.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs2 = {};
vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs2);
memAllocInfo2.allocationSize = memReqs2.size;
memAllocInfo2.memoryTypeIndex = findMemoryType(memReqs2.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
if (vkAllocateMemory(device, &memAllocInfo2, nullptr, &stagingMemory) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate memory 2!");
}
vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0);
void* data;
vkMapMemory(device, stagingMemory, 0, imageSize, 0, &data);
memcpy(data, pData, static_cast<size_t>(imageSize));
vkUnmapMemory(device, stagingMemory);
delete pData;
//
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_1D;
imageInfo.extent.width = static_cast<uint32_t>(256);
imageInfo.extent.depth = 1;
imageInfo.extent.height = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R32G32B32A32_UINT;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0; // Optional
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
if (vkCreateImage(device, &imageInfo, nullptr, &tftextureImage) != VK_SUCCESS) {
throw std::runtime_error("failed to create image!");
}
The code give me always the runtime error "failed to create image", I tried to change some things like the format, the extent, etc but I can't solve it.
I believe that the mistake is only in the imageInfo part because the first one run ok.

Screenshot using SharpDX and EasyHook transparent

I have been struggling in taking screenshots with DirectX, the problem is, it's working but seems to be missing some colors (black outline is missing for example), and some stuff that is also rendered by DX doesn't show.
I have uploaded the images (how the image should render and the rendered one) and also the code, what might be the issue?
Correct Image
Rendered Image
Greetings
public class Screenshot
{
public static void TakeScreenshot(string name = null)
{
var t = new Thread((ThreadStart) delegate
{
// destination folder
var destinationFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.Create) + "\\My Software\\Screenshots";
if (!Directory.Exists(destinationFolder)) Directory.CreateDirectory(destinationFolder);
// file name
string filename = name;
if (string.IsNullOrEmpty(name))
filename = "image-" + (Directory.GetFiles(destinationFolder, "*.png").Count() + 1).ToString("000") + ".png";
// # of graphics card adapter
const int numAdapter = 0;
// # of output device (i.e. monitor)
const int numOutput = 0;
// Create DXGI Factory1
var factory = new Factory1();
var adapter = factory.GetAdapter1(numAdapter);
// Create device from Adapter
var device = new Device(adapter);
// Get DXGI.Output
var output = adapter.GetOutput(numOutput);
var output1 = output.QueryInterface<Output1>();
// Width/Height of desktop to capture
int width = ((SharpDX.Rectangle)output.Description.DesktopBounds).Width;
int height = ((SharpDX.Rectangle)output.Description.DesktopBounds).Height;
// Create Staging texture CPU-accessible
var textureDesc = new Texture2DDescription
{
CpuAccessFlags = CpuAccessFlags.Read,
BindFlags = BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription = { Count = 1, Quality = 0 },
Usage = ResourceUsage.Staging
};
var screenTexture = new Texture2D(device, textureDesc);
// Duplicate the output
var duplicatedOutput = output1.DuplicateOutput(device);
bool captureDone = false;
for (int i = 0; !captureDone; i++)
{
try
{
SharpDX.DXGI.Resource screenResource;
OutputDuplicateFrameInformation duplicateFrameInformation;
// Try to get duplicated frame within given time
duplicatedOutput.AcquireNextFrame(10000, out duplicateFrameInformation, out screenResource);
if (i > 0)
{
// copy resource into memory that can be accessed by the CPU
using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
// Get the desktop capture texture
var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);
// Create Drawing.Bitmap
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var boundsRect = new System.Drawing.Rectangle(0, 0, width, height);
// Copy pixels from screen capture Texture to GDI bitmap
var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
var sourcePtr = mapSource.DataPointer;
var destPtr = mapDest.Scan0;
for (int y = 0; y < height; y++)
{
// Copy a single line
Utilities.CopyMemory(destPtr, sourcePtr, width * 4);
// Advance pointers
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
}
// Release source and dest locks
bitmap.UnlockBits(mapDest);
device.ImmediateContext.UnmapSubresource(screenTexture, 0);
// Save the output
bitmap.Save(destinationFolder + Path.DirectorySeparatorChar + filename);
// Send Message
Main.Chat.AddMessage(null, "~b~Screenshot saved as " + filename);
// Capture done
captureDone = true;
}
screenResource.Dispose();
duplicatedOutput.ReleaseFrame();
}
catch (SharpDXException e)
{
if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
{
throw e;
}
}
}
});
t.IsBackground = true;
t.Start();
}
}