Input attachment from previous subpass in Vulkan - 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.

Related

How to render Vulkan's scene to ImGui window

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!

Is the render target view the only way to output data from pixel shader in DirectX?

Purpose:
I want to render an image in the screen and save it in my disk.
Description:
I have a render target view.
I have a input shader resource view with its texture (D3D11_USAGE_DYNAMIC).
I have a output shader resource view with its texture (D3D11_USAGE_DEFAULT).
I have a auxiliar simple texture (D3D11_USAGE_STAGING).
The execution path is the following:
Read input image in a texture.
Bind the input texture view and output texture view, pixel shader, sampler and vertex shader.
Run draw command.
Copy output texture to auxiliar texture.
Save auxiliar texture in a image. The image is empty.
Question:
How can I output an additional texture and still rendering on screen?
Example code
mWidth = width;
mHeight = height;
// Create image texture to hold input image for unormalized values and CPU write/GPU read access
D3D11_TEXTURE2D_DESC inputImageDesc;
ZeroMemory(&inputImageDesc, sizeof(D3D11_TEXTURE2D_DESC));
inputImageDesc.ArraySize = 1;
inputImageDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
inputImageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // Needed for cpu write and gpu read
inputImageDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
inputImageDesc.Width = width;
inputImageDesc.Height = height;
inputImageDesc.MipLevels = 1;
inputImageDesc.SampleDesc.Count = 1;
inputImageDesc.SampleDesc.Quality = 0;
inputImageDesc.Usage = D3D11_USAGE_DYNAMIC; // Needed for cpu write and gpu read
result = engine.device()->CreateTexture2D(&inputImageDesc, nullptr, mInputTexture.GetAddressOf());
if(result < 0)
{
return -1;
}
result = engine.device()->CreateShaderResourceView(mInputTexture.Get(), nullptr, mInputView.GetAddressOf());
if(result < 0)
{
return -1;
}
// Create image texture for unormalized values and only GPU access
D3D11_TEXTURE2D_DESC gpuImageDesc;
ZeroMemory(&gpuImageDesc, sizeof(D3D11_TEXTURE2D_DESC));
gpuImageDesc.ArraySize = 1;
gpuImageDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
gpuImageDesc.CPUAccessFlags = 0; // Needed for gpu read/write (cpu no access)
gpuImageDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
gpuImageDesc.Width = width;
gpuImageDesc.Height = height;
gpuImageDesc.MipLevels = 1;
gpuImageDesc.SampleDesc.Count = 1;
gpuImageDesc.SampleDesc.Quality = 0;
gpuImageDesc.Usage = D3D11_USAGE_DEFAULT; // Needed for gpu read/write (cpu no access)
result = engine.device()->CreateTexture2D(&gpuImageDesc, nullptr, mOutputGpuTexture.GetAddressOf());
if(result < 0)
{
return -1;
}
result = engine.device()->CreateShaderResourceView(mOutputGpuTexture.Get(), nullptr, mOutputView.GetAddressOf());
if(result < 0)
{
return -1;
}
// Create image texture for unormalized values and only CPU read access
D3D11_TEXTURE2D_DESC cpuImageDesc;
ZeroMemory(&cpuImageDesc, sizeof(D3D11_TEXTURE2D_DESC));
mOutputGpuTexture->GetDesc(&cpuImageDesc);
cpuImageDesc.BindFlags = 0;
cpuImageDesc.MiscFlags = 0;
cpuImageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; // Needed for cpu read
cpuImageDesc.Usage = D3D11_USAGE_STAGING; // Needed for cpu read
result = engine.device()->CreateTexture2D(&cpuImageDesc, nullptr, mOutputCpuTexture.GetAddressOf());
if(result < 0)
{
return -1;
}
struct PixelInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
float2 coord : TEXCOORDIN;
float2 coordOut : TEXCOORDOUT;
};
Texture2D<float4> gInputTexture : register(t0);
SamplerState gSampleType : register(s0);
RWTexture2D<float4> gOutputTexture : register(t1);
float4 main(PixelInput input) : SV_TARGET
{
gOutputTexture[input.coordOut] = float4(1.0,0.0,0.0,1.0);
float4 inputPixel = float4(0.0, 0.0, 0.0, 1.0);
inputPixel.rgb = gInputTexture.Sample(gSampleType, input.coord).rgb;
return inputPixel;
}
engine.context()->CopyResource(mOutputCpuTexture.Get(), mOutputGpuTexture.Get());
D3D11_MAPPED_SUBRESOURCE mappedImgData;
ZeroMemory(&mappedImgData, sizeof(D3D11_MAPPED_SUBRESOURCE));
int32_t result = engine.context()->Map(mOutputCpuTexture.Get(), 0, D3D11_MAP_READ, 0, &mappedImgData);
if(result < EC_SUCCESS)
{
ERROR_MSG(result);
return EC_COULD_NOT_MAP_RESOURCE_TEXTURE;
}
// Copy the less bytes possible, avoiding out of bounds.
const uint32_t bytesPerRow = std::min(rowPitch, mappedImgData.RowPitch);
uint8_t* textureData = reinterpret_cast<uint8_t*>(mappedImgData.pData);
for(uint32_t i = 0; i < height; ++i)
{
memcpy(dst, textureData, bytesPerRow);
textureData += mappedImgData.RowPitch;
dst += rowPitch;
}
engine.context()->Unmap(mOutputCpuTexture.Get(), 0);
What I did to fix this was add a compute shader as intermediary, in that way I read a RWTexture (DEFAULT) with another texture (STAGING) and also another one to read the back buffer.

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.

Make Ellipse by using DirectX 11

if(shapeType == ELLIPSE)
{
Vertex* v = new Vertex[31];
v[0] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
float theta;
for(int i = 1; i < 30; ++i)
{
theta = (MATH::TWO_PI * i) / static_cast<float>(30);
v[i] = { cos(theta * i), sin(theta * i), 1.0f, 0.0f, 0.0f };
}
HRESULT hr = this->vertexBuffer.Initialize(this->device, v,31);
if (FAILED(hr))
{
ErrorLogger::Log(hr, "Failed to create vertex buffer.");
return false;
}
DWORD* indices = new DWORD[90];
int indiceHelperNum1 = 1;
int indiceHelperNum2 = 2;
for(int i = 0; i < 87; i += 3)
{
indices[i] = 0;
indices[i + 1] = indiceHelperNum1;
indices[i + 2] = indiceHelperNum2;
indiceHelperNum1++;
indiceHelperNum2++;
}
indices[84] = 0;
indices[85] = 29;
indices[86] = 1;
hr = this->indexBuffer.Initialize(this->device, indices, 90);
if (FAILED(hr))
{
ErrorLogger::Log(hr, "Failed to create indices buffer.");
return false;
}
delete[] v;
delete[] indices;
}
This is my code and I think nothing is wrong in here except memory allocation. However, when I try this code, it doesn't work. I want to make a circle with radius one whose center is origin. I picked points by using vertex and I made triangles by using indices. Please tell me if something is wrong with my code.
There are a couple problems with this code.
The primary problem is in the following line
v[i] = { cos(theta * i), sin(theta * i), 1.0f, 0.0f, 0.0f };
There is no reason to multiply theta by i.
Once you resolve that issue, you should see something like this.
Notice the problem area outlined on the right side of the image.
In order to close the gap, the last 3 indices need to be modified.
Replace
indices[84] = 0;
indices[85] = 29;
indices[86] = 1;
with
indices[87] = 0;
indices[88] = 30;
indices[89] = 1;
One last thing, is your for loop to populate the vertices is not populating the last vertex at index 30. Adjust the for loops range like so
for (int i = 1; i < 31; ++i)
{
theta = (MATH::TWO_PI * i) / static_cast<float>(30);
v[i] = { cos(theta ), sin(theta ), 1.0f, 0.0f, 0.0f };
}
Finally, you should see something like this.

Circular Gauge Gradient - TeeChart - MonoAndroid

I am using TreeChart to make an indicator as shown in the picture. But I have a problem I can not make the three-color gradient to that gauge. This is my code
Steema.TeeChart.TChart tChart = new Steema.TeeChart.TChart(this);
tChart.Panel.Transparent = false;
Steema.TeeChart.Styles.Gauges gauges = new Steema.TeeChart.Styles.Gauges(tChart.Chart);
Steema.TeeChart.Drawing.Gradient g = new Steema.TeeChart.Drawing.Gradient(gauges.Chart);
gauges.bBrush.Gradient.Direction = Steema.TeeChart.Drawing.GradientDirection.DiagonalUp;
gauges.bBrush.Gradient.StartColor = System.Drawing.Color.Red;
gauges.bBrush.Gradient.MiddleColor = System.Drawing.Color.Black;
gauges.bBrush.Gradient.EndColor = System.Drawing.Color.Blue;
gauges.bBrush.Gradient.Visible = true;
gauges.Pen.Color = System.Drawing.Color.FromArgb(5,56,73);
gauges.TotalAngle = 180; // circular arc
gauges.RotationAngle = 180; // arc rotation angle
gauges.HandStyle = Steema.TeeChart.Styles.HandStyle.Triangle; // pointer style
gauges.Center.Style = Steema.TeeChart.Styles.PointerStyles.Circle; // SPHERE center circle style
gauges.Center.HorizSize = 5; // center circle level size
gauges.Center.VertSize = 5; // center circle vertical size
gauges.ShowInLegend = false; // display the legend
gauges.HandDistance = 23; // pointer length
//---------------------------------------------------
gauges.Value = 80;
gauges.Minimum = 0; // minimum;
gauges.Maximum = 100; // maximum value
//----------------------------------------------------
gauges.MinorTickDistance = 0;
gauges.Pen.DashWidth = 23;
gauges.Chart.Axes.Left.AxisPen.Width = 65; // brush width;
gauges.Chart.Axes.Left.AxisPen.Color = System.Drawing.Color.Red;
gauges.Chart.Axes.Left.MinorTickCount = 5; // the scale value scale line number
gauges.Chart.Axes.Left.MinorTicks.Length = 10; // the scale value scale line length of
gauges.Chart.Axes.Left.Ticks.Length = 20; // display the value scale line length of
gauges.Chart.Axes.Left.Increment = 3000; // the scale value of interval size
SetContentView(tChart) ;
I also tried the following lines of code
gauges.CircleGradient.Direction = Steema.TeeChart.Drawing.GradientDirection.DiagonalUp;
gauges.CircleGradient.Visible = true;
gauges.CircleGradient.StartColor = System.Drawing.Color.Green;
gauges.CircleGradient.EndColor = System.Drawing.Color.Red;
gauges.CircleGradient.UseStandardGradient = true;
I hope I help
regards
You should use Steema.TeeChart.Styles.CircularGauge instead of Steema.TeeChart.Styles.Gauges which is a much simpler gauge version. For example, using the code snippet below, you get a similar gauge to the image in your link:
Is this similar to what you are looking for?
tChart1.Header.Visible = false;
Steema.TeeChart.Styles.CircularGauge circularGauge1 = new Steema.TeeChart.Styles.CircularGauge(tChart1.Chart);
circularGauge1.Frame.Visible = false;
circularGauge1.FaceBrush.Visible = false;
circularGauge1.DisplayTotalAngle = 180;
circularGauge1.TotalAngle = 180;
circularGauge1.Value = 200;
circularGauge1.Ticks.Visible = false;
circularGauge1.Minimum = 0;
circularGauge1.Maximum = 1000;
circularGauge1.Axis.AxisPen.Visible = false;
circularGauge1.Axis.Increment = 500;
circularGauge1.RedLine.Visible = false;
circularGauge1.GreenLineStartValue = 0;
circularGauge1.GreenLineEndValue = 1000;
circularGauge1.GreenLine.Gradient.Direction = Steema.TeeChart.Drawing.GradientDirection.LeftRight;
circularGauge1.GreenLine.Gradient.UseMiddle = true;
circularGauge1.GreenLine.Gradient.StartColor = Color.Orange;
circularGauge1.GreenLine.Gradient.MiddleColor = Color.Yellow;
circularGauge1.GreenLine.Gradient.EndColor = Color.Green;
circularGauge1.GreenLine.Pen.Visible = false;