/* ============= R_SetupMatrix ============= */ void R_SetupMatrix (void) { GL_Viewport(glx + r_refdef.vrect.x, gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height); // Projection matrix GL_FrustumMatrix(vulkan_globals.projection_matrix, DEG2RAD(r_fovx), DEG2RAD(r_fovy)); // View matrix float rotation_matrix[16]; RotationMatrix(vulkan_globals.view_matrix, -M_PI / 2.0f, 1.0f, 0.0f, 0.0f); RotationMatrix(rotation_matrix, M_PI / 2.0f, 0.0f, 0.0f, 1.0f); MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix); RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[2]), 1.0f, 0.0f, 0.0f); MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix); RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[0]), 0.0f, 1.0f, 0.0f); MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix); RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[1]), 0.0f, 0.0f, 1.0f); MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix); float translation_matrix[16]; TranslationMatrix(translation_matrix, -r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); MatrixMultiply(vulkan_globals.view_matrix, translation_matrix); // View projection matrix memcpy(vulkan_globals.view_projection_matrix, vulkan_globals.projection_matrix, 16 * sizeof(float)); MatrixMultiply(vulkan_globals.view_projection_matrix, vulkan_globals.view_matrix); vkCmdPushConstants(vulkan_globals.command_buffer, vulkan_globals.basic_pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), vulkan_globals.view_projection_matrix); }
bool game_buffer_editor_record_vulkan_commands(game_buffer *game_buffer, vulkan *vulkan) { game_buffer_editor *editor = game_buffer->editor; ImDrawData *draw_data = ImGui::GetDrawData(); VkResult vk_result = {}; { uint64 vertices_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); uint64 indices_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); uint64 map_size = round_to_multi(vertices_size + indices_size, vulkan->physical_device_non_coherent_atom_size); assert(map_size <= editor->imgui_vertex_index_vulkan_buffer.size); uint8 *buf_ptr = nullptr; if ((vk_result = vkMapMemory(vulkan->device, editor->imgui_vertex_index_vulkan_buffer.device_memory, 0, map_size, 0, (void **)&buf_ptr)) != VK_SUCCESS) { return false; } assert((uintptr_t)buf_ptr % 16 == 0); for (int i = 0; i < draw_data->CmdListsCount; i += 1) { ImDrawList *dlist = draw_data->CmdLists[i]; memcpy(buf_ptr, dlist->VtxBuffer.Data, dlist->VtxBuffer.Size * sizeof(ImDrawVert)); buf_ptr += dlist->VtxBuffer.Size * sizeof(ImDrawVert); } for (int i = 0; i < draw_data->CmdListsCount; i += 1) { ImDrawList *dlist = draw_data->CmdLists[i]; memcpy(buf_ptr, dlist->IdxBuffer.Data, dlist->IdxBuffer.Size * sizeof(ImDrawIdx)); buf_ptr += dlist->IdxBuffer.Size * sizeof(ImDrawIdx); } VkMappedMemoryRange memory_range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; memory_range.memory = editor->imgui_vertex_index_vulkan_buffer.device_memory; memory_range.offset = map_size; if ((vk_result = vkFlushMappedMemoryRanges(vulkan->device, 1, &memory_range)) != VK_SUCCESS) { return false; } vkUnmapMemory(vulkan->device, editor->imgui_vertex_index_vulkan_buffer.device_memory); } vkCmdBindPipeline(vulkan->swap_chain_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, editor->imgui_vulkan_pipeline); VkViewport viewport = { 0, 0, (float)game_buffer->vulkan_framebuffer_image_width, (float)game_buffer->vulkan_framebuffer_image_height, 0, 1 }; vkCmdSetViewport(vulkan->swap_chain_cmd_buffer, 0, 1, &viewport); vec2 push_consts = { (float)game_buffer->vulkan_framebuffer_image_width, (float)game_buffer->vulkan_framebuffer_image_height }; vkCmdPushConstants(vulkan->swap_chain_cmd_buffer, editor->imgui_vulkan_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_consts), &push_consts); VkDeviceSize vertex_offset = 0; VkDeviceSize index_offset = draw_data->TotalVtxCount * sizeof(ImDrawVert); for (int i = 0; i < draw_data->CmdListsCount; i += 1) { ImDrawList *dlist = draw_data->CmdLists[i]; vkCmdBindVertexBuffers(vulkan->swap_chain_cmd_buffer, 0, 1, &editor->imgui_vertex_index_vulkan_buffer.buffer, &vertex_offset); vertex_offset += dlist->VtxBuffer.Size * sizeof(ImDrawVert); for (int i = 0; i < dlist->CmdBuffer.Size; i += 1) { ImDrawCmd *dcmd = &dlist->CmdBuffer.Data[i]; VkRect2D scissor = { { (int)dcmd->ClipRect.x, (int)dcmd->ClipRect.y }, { (uint)dcmd->ClipRect.z, (uint)dcmd->ClipRect.w } }; vkCmdSetScissor(vulkan->swap_chain_cmd_buffer, 0, 1, &scissor); if (dcmd->TextureId == editor->imgui_font_atlas_vulkan_image.image) { vkCmdBindDescriptorSets(vulkan->swap_chain_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, editor->imgui_vulkan_pipeline_layout, 0, 1, &editor->imgui_vulkan_descriptor_sets[0], 0, nullptr); } else { vkCmdBindDescriptorSets(vulkan->swap_chain_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, editor->imgui_vulkan_pipeline_layout, 0, 1, &editor->imgui_vulkan_descriptor_sets[1], 0, nullptr); } vkCmdBindIndexBuffer(vulkan->swap_chain_cmd_buffer, editor->imgui_vertex_index_vulkan_buffer.buffer, index_offset, VK_INDEX_TYPE_UINT16); vkCmdDrawIndexed(vulkan->swap_chain_cmd_buffer, dcmd->ElemCount, 1, 0, 0, 0); index_offset += dcmd->ElemCount * sizeof(ImDrawIdx); } } return true; }
void ComputeShaderDispatcher::SetPushConstants(const void* data, size_t data_size) { _assert_(static_cast<u32>(data_size) < PUSH_CONSTANT_BUFFER_SIZE); vkCmdPushConstants(m_command_buffer, m_pipeline_info.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, static_cast<u32>(data_size), data); }
XCamReturn VKComputePipeline::push_consts_by ( VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const) { VkCommandBuffer cmd_buf_id = cmd_buf.get_cmd_buf_id (); XCAM_FAIL_RETURN ( ERROR, XCAM_IS_VALID_VK_ID (cmd_buf_id) && XCAM_IS_VALID_VK_ID (_pipe_layout), XCAM_RETURN_ERROR_PARAM, "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id."); XCAM_ASSERT (push_const.ptr ()); VkPushConstantRange const_range; xcam_mem_clear (const_range); void *ptr = NULL; push_const->get_const_data (const_range, ptr); XCAM_FAIL_RETURN ( ERROR, const_range.stageFlags == VK_SHADER_STAGE_COMPUTE_BIT, XCAM_RETURN_ERROR_PARAM, "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id."); vkCmdPushConstants( cmd_buf_id, _pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, const_range.offset, const_range.size, ptr); return XCAM_RETURN_NO_ERROR; }
void flush(const type::supplier<type::serialize_type> &constants, VkPipelineLayout pipeline_layout, const std::vector<VkPushConstantRange> &push_constant_ranges, queue::queue_type &queue) { if (type::dirty(*constants)) { const type::supplier<device::device_type> device( vcc::internal::get_parent(queue)); std::string buffer(type::size(*constants), '\0'); type::flush(*constants, &buffer[0]); command_pool::command_pool_type command_pool(command_pool::create( device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queue::get_family_index(queue))); command_buffer::command_buffer_type cmd(std::move( command_buffer::allocate(device, std::ref(command_pool), VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1).front())); { command_buffer::begin_type begin(command_buffer::begin( std::ref(cmd), VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, VK_FALSE, 0, 0)); for (const VkPushConstantRange &range : push_constant_ranges) { assert(range.offset + range.size <= buffer.size()); vkCmdPushConstants(vcc::internal::get_instance(cmd), pipeline_layout, range.stageFlags, range.offset, range.size, &buffer[range.offset]); } } // Must block until our command finish executing. fence::fence_type fence(fence::create(device)); queue::submit(queue, {}, { std::ref(cmd) }, {}, fence); fence::wait(*device, { std::ref(fence) }, true, std::chrono::nanoseconds::max()); } }
void UtilityShaderDraw::SetPushConstants(const void* data, size_t data_size) { _assert_(static_cast<u32>(data_size) < PUSH_CONSTANT_BUFFER_SIZE); vkCmdPushConstants(m_command_buffer, m_pipeline_info.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, static_cast<u32>(data_size), data); }
void renderNode(vkglTF::Node *node, VkCommandBuffer commandBuffer) { if (node->mesh) { for (vkglTF::Primitive * primitive : node->mesh->primitives) { const std::vector<VkDescriptorSet> descriptorsets = { descriptorSet, node->mesh->uniformBuffer.descriptorSet }; vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL); struct PushBlock { glm::vec4 baseColorFactor; } pushBlock; pushBlock.baseColorFactor = primitive->material.baseColorFactor; vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushBlock), &pushBlock); /* [POI] Setup the conditional rendering */ VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo{}; conditionalRenderingBeginInfo.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT; conditionalRenderingBeginInfo.buffer = conditionalBuffer.buffer; conditionalRenderingBeginInfo.offset = sizeof(int32_t) * node->index; /* [POI] Begin conditionally rendered section If the value from the conditional rendering buffer at the given offset is != 0, the draw commands will be executed */ vkCmdBeginConditionalRenderingEXT(commandBuffer, &conditionalRenderingBeginInfo); vkCmdDrawIndexed(commandBuffer, primitive->indexCount, 1, primitive->firstIndex, 0, 0); vkCmdEndConditionalRenderingEXT(commandBuffer); } }; for (auto child : node->children) { renderNode(child, commandBuffer); } }
void updateSecondaryCommandBuffer(VkCommandBufferInheritanceInfo inheritanceInfo) { // Secondary command buffer for the sky sphere VkCommandBufferBeginInfo commandBufferBeginInfo = vkTools::initializers::commandBufferBeginInfo(); commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo; VK_CHECK_RESULT(vkBeginCommandBuffer(secondaryCommandBuffer, &commandBufferBeginInfo)); VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(secondaryCommandBuffer, 0, 1, &viewport); VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(secondaryCommandBuffer, 0, 1, &scissor); vkCmdBindPipeline(secondaryCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.starsphere); glm::mat4 view = glm::mat4(); view = glm::rotate(view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); view = glm::rotate(view, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); view = glm::rotate(view, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); glm::mat4 mvp = matrices.projection * view; vkCmdPushConstants( secondaryCommandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(mvp), &mvp); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(secondaryCommandBuffer, 0, 1, &meshes.skysphere.vertices.buf, offsets); vkCmdBindIndexBuffer(secondaryCommandBuffer, meshes.skysphere.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(secondaryCommandBuffer, meshes.skysphere.indexCount, 1, 0, 0, 0); VK_CHECK_RESULT(vkEndCommandBuffer(secondaryCommandBuffer)); }
void VulkanWindow::Render ( const Matrix4x4& aModelMatrix, const Mesh& aMesh, const Pipeline& aPipeline, const Material* aMaterial, const UniformBuffer* aSkeleton, uint32_t aVertexStart, uint32_t aVertexCount, uint32_t aInstanceCount, uint32_t aFirstInstance ) const { const auto& vulkan_material = reinterpret_cast<const VulkanMaterial&> ( ( aMaterial ) ? *aMaterial : aPipeline.GetDefaultMaterial() ); const std::vector<VkDescriptorSet>& material_descriptor_sets = vulkan_material.GetDescriptorSets(); const auto* vk_skeleton = reinterpret_cast<const VulkanUniformBuffer*> ( aSkeleton ); assert ( material_descriptor_sets.size() < 3 ); uint32_t descriptor_set_count = 1; std::array<VkDescriptorSet, 4> descriptor_sets { { mMatrices.GetDescriptorSet() }}; if ( vk_skeleton ) { descriptor_sets[descriptor_set_count++] = vk_skeleton->GetDescriptorSet(); } memcpy ( &descriptor_sets[descriptor_set_count], material_descriptor_sets.data(), material_descriptor_sets.size() *sizeof ( VkDescriptorSet ) ); descriptor_set_count += static_cast<uint32_t> ( material_descriptor_sets.size() ); vkCmdBindPipeline ( mVulkanRenderer.GetCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, reinterpret_cast<const VulkanPipeline*> ( &aPipeline )->GetPipeline() ); vkCmdPushConstants ( mVulkanRenderer.GetCommandBuffer(), reinterpret_cast<const VulkanPipeline*> ( &aPipeline )->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof ( float ) * 16, aModelMatrix.GetMatrix4x4() ); vkCmdBindDescriptorSets ( mVulkanRenderer.GetCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, reinterpret_cast<const VulkanPipeline*> ( &aPipeline )->GetPipelineLayout(), 0, descriptor_set_count, descriptor_sets.data(), 0, nullptr ); { const VkDeviceSize offset = 0; const VulkanMesh& vulkan_mesh{reinterpret_cast<const VulkanMesh&> ( aMesh ) }; vkCmdBindVertexBuffers ( mVulkanRenderer.GetCommandBuffer(), 0, 1, &vulkan_mesh.GetBuffer(), &offset ); if ( aMesh.GetIndexCount() ) { vkCmdBindIndexBuffer ( mVulkanRenderer.GetCommandBuffer(), vulkan_mesh.GetBuffer(), ( sizeof ( Vertex ) * aMesh.GetVertexCount() ), vulkan_mesh.GetIndexType() ); vkCmdDrawIndexed ( mVulkanRenderer.GetCommandBuffer(), ( aVertexCount != 0xffffffff ) ? aVertexCount : aMesh.GetIndexCount(), aInstanceCount, aVertexStart, 0, aFirstInstance ); } else { vkCmdDraw ( mVulkanRenderer.GetCommandBuffer(), ( aVertexCount != 0xffffffff ) ? aVertexCount : aMesh.GetVertexCount(), aInstanceCount, aVertexStart, aFirstInstance ); } } }
int sample_main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Simple Push Constants"; const bool depthPresent = true; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); init_depth_buffer(info); init_uniform_buffer(info); init_renderpass(info, depthPresent); init_shaders(info, vertShaderText, fragShaderText); init_framebuffers(info, depthPresent); init_vertex_buffer(info, g_vb_texture_Data, sizeof(g_vb_texture_Data), sizeof(g_vb_texture_Data[0]), true); // Set up one descriptor sets static const unsigned descriptor_set_count = 1; static const unsigned resource_count = 1; // Create binding and layout for the following, matching contents of shader // binding 0 = uniform buffer (MVP) VkDescriptorSetLayoutBinding resource_binding[resource_count] = {}; resource_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; resource_binding[0].descriptorCount = 1; resource_binding[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; resource_binding[0].pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo resource_layout_info[1] = {}; resource_layout_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; resource_layout_info[0].pNext = NULL; resource_layout_info[0].bindingCount = resource_count; resource_layout_info[0].pBindings = resource_binding; VkDescriptorSetLayout descriptor_layouts[1] = {}; res = vkCreateDescriptorSetLayout(info.device, resource_layout_info, NULL, &descriptor_layouts[0]); assert(res == VK_SUCCESS); /* VULKAN_KEY_START */ // Set up our push constant range, which mirrors the declaration of const unsigned push_constant_range_count = 1; VkPushConstantRange push_constant_ranges[push_constant_range_count] = {}; push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; push_constant_ranges[0].offset = 0; push_constant_ranges[0].size = 8; // Create pipeline layout, including push constant info. // Create pipeline layout with multiple descriptor sets VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo[1] = {}; pipelineLayoutCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutCreateInfo[0].pNext = NULL; pipelineLayoutCreateInfo[0].pushConstantRangeCount = push_constant_range_count; pipelineLayoutCreateInfo[0].pPushConstantRanges = push_constant_ranges; pipelineLayoutCreateInfo[0].setLayoutCount = descriptor_set_count; pipelineLayoutCreateInfo[0].pSetLayouts = descriptor_layouts; res = vkCreatePipelineLayout(info.device, pipelineLayoutCreateInfo, NULL, &info.pipeline_layout); assert(res == VK_SUCCESS); // Create a single pool to contain data for our descriptor set VkDescriptorPoolSize type_count[2] = {}; type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; type_count[0].descriptorCount = 1; type_count[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; type_count[1].descriptorCount = 1; VkDescriptorPoolCreateInfo pool_info[1] = {}; pool_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info[0].pNext = NULL; pool_info[0].maxSets = descriptor_set_count; pool_info[0].poolSizeCount = sizeof(type_count) / sizeof(VkDescriptorPoolSize); pool_info[0].pPoolSizes = type_count; VkDescriptorPool descriptor_pool[1] = {}; res = vkCreateDescriptorPool(info.device, pool_info, NULL, descriptor_pool); assert(res == VK_SUCCESS); VkDescriptorSetAllocateInfo alloc_info[1]; alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info[0].pNext = NULL; alloc_info[0].descriptorPool = descriptor_pool[0]; alloc_info[0].descriptorSetCount = descriptor_set_count; alloc_info[0].pSetLayouts = descriptor_layouts; // Populate descriptor sets VkDescriptorSet descriptor_sets[descriptor_set_count] = {}; res = vkAllocateDescriptorSets(info.device, alloc_info, descriptor_sets); assert(res == VK_SUCCESS); // Using empty brace initializer on the next line triggers a bug in older // versions of gcc, so memset instead VkWriteDescriptorSet descriptor_writes[resource_count]; memset(descriptor_writes, 0, sizeof(descriptor_writes)); // Populate with info about our uniform buffer for MVP descriptor_writes[0] = {}; descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_writes[0].pNext = NULL; descriptor_writes[0].dstSet = descriptor_sets[0]; descriptor_writes[0].descriptorCount = 1; descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_writes[0].pBufferInfo = &info.uniform_data.buffer_info; // populated by init_uniform_buffer() descriptor_writes[0].dstArrayElement = 0; descriptor_writes[0].dstBinding = 0; vkUpdateDescriptorSets(info.device, resource_count, descriptor_writes, 0, NULL); // Create our push constant data, which matches shader expectations unsigned pushConstants[2] = {}; pushConstants[0] = (unsigned)2; pushConstants[1] = (unsigned)0x3F800000; // Ensure we have enough room for push constant data if (sizeof(pushConstants) > info.gpu_props.limits.maxPushConstantsSize) assert(0 && "Too many push constants"); vkCmdPushConstants(info.cmd, info.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(pushConstants), pushConstants); /* VULKAN_KEY_END */ init_pipeline_cache(info); init_pipeline(info, depthPresent); init_presentable_image(info); VkClearValue clear_values[2]; init_clear_color_and_depth(info, clear_values); VkRenderPassBeginInfo rp_begin; init_render_pass_begin_info(info, rp_begin); rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, descriptor_sets, 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); init_viewports(info); init_scissors(info); vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); vkCmdEndRenderPass(info.cmd); res = vkEndCommandBuffer(info.cmd); assert(res == VK_SUCCESS); VkFence drawFence = {}; init_fence(info, drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submit_info = {}; init_submit_info(info, submit_info, pipe_stage_flags); /* Queue the command buffer for execution */ res = vkQueueSubmit(info.graphics_queue, 1, &submit_info, drawFence); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present = {}; init_present_info(info, present); /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.present_queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); if (info.save_images) write_ppm(info, "push_constants"); vkDestroyFence(info.device, drawFence, NULL); vkDestroySemaphore(info.device, info.imageAcquiredSemaphore, NULL); destroy_pipeline(info); destroy_pipeline_cache(info); // instead of destroy_descriptor_pool(info); vkDestroyDescriptorPool(info.device, descriptor_pool[0], NULL); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_shaders(info); destroy_renderpass(info); // instead of destroy_descriptor_and_pipeline_layouts(info); for (int i = 0; i < descriptor_set_count; i++) vkDestroyDescriptorSetLayout(info.device, descriptor_layouts[i], NULL); vkDestroyPipelineLayout(info.device, info.pipeline_layout, NULL); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) { VkResult err; ImGuiIO& io = ImGui::GetIO(); // Create the Vertex Buffer: size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); if (!g_VertexBuffer[g_FrameIndex] || g_VertexBufferSize[g_FrameIndex] < vertex_size) { if (g_VertexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_VertexBuffer[g_FrameIndex], g_Allocator); if (g_VertexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], g_Allocator); size_t vertex_buffer_size = ((vertex_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = vertex_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_VertexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_VertexBuffer[g_FrameIndex], &req); g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_VertexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindBufferMemory(g_Device, g_VertexBuffer[g_FrameIndex], g_VertexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_VertexBufferSize[g_FrameIndex] = vertex_buffer_size; } // Create the Index Buffer: size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); if (!g_IndexBuffer[g_FrameIndex] || g_IndexBufferSize[g_FrameIndex] < index_size) { if (g_IndexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_IndexBuffer[g_FrameIndex], g_Allocator); if (g_IndexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], g_Allocator); size_t index_buffer_size = ((index_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = index_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_IndexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_IndexBuffer[g_FrameIndex], &req); g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_IndexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindBufferMemory(g_Device, g_IndexBuffer[g_FrameIndex], g_IndexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_IndexBufferSize[g_FrameIndex] = index_buffer_size; } // Upload Vertex and index Data: { ImDrawVert* vtx_dst; ImDrawIdx* idx_dst; err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], 0, vertex_size, 0, (void**)(&vtx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], 0, index_size, 0, (void**)(&idx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += cmd_list->VtxBuffer.Size; idx_dst += cmd_list->IdxBuffer.Size; } VkMappedMemoryRange range[2] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].memory = g_VertexBufferMemory[g_FrameIndex]; range[0].size = vertex_size; range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[1].memory = g_IndexBufferMemory[g_FrameIndex]; range[1].size = index_size; err = vkFlushMappedMemoryRanges(g_Device, 2, range); ImGui_ImplGlfwVulkan_VkResult(err); vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); vkUnmapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex]); } // Bind pipeline and descriptor sets: { vkCmdBindPipeline(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline); VkDescriptorSet desc_set[1] = {g_DescriptorSet}; vkCmdBindDescriptorSets(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); } // Bind Vertex And Index Buffer: { VkBuffer vertex_buffers[1] = {g_VertexBuffer[g_FrameIndex]}; VkDeviceSize vertex_offset[1] = {0}; vkCmdBindVertexBuffers(g_CommandBuffer, 0, 1, vertex_buffers, vertex_offset); vkCmdBindIndexBuffer(g_CommandBuffer, g_IndexBuffer[g_FrameIndex], 0, VK_INDEX_TYPE_UINT16); } // Setup viewport: { VkViewport viewport; viewport.x = 0; viewport.y = 0; viewport.width = ImGui::GetIO().DisplaySize.x; viewport.height = ImGui::GetIO().DisplaySize.y; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; vkCmdSetViewport(g_CommandBuffer, 0, 1, &viewport); } // Setup scale and translation: { float scale[2]; scale[0] = 2.0f/io.DisplaySize.x; scale[1] = 2.0f/io.DisplaySize.y; float translate[2]; translate[0] = -1.0f; translate[1] = -1.0f; vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); } // Render the command lists: int vtx_offset = 0; int idx_offset = 0; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); } else { VkRect2D scissor; scissor.offset.x = (int32_t)(pcmd->ClipRect.x); scissor.offset.y = (int32_t)(pcmd->ClipRect.y); scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); vkCmdDrawIndexed(g_CommandBuffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); } idx_offset += pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.Size; } }
int main(void) { VkInstance instance; { const char debug_ext[] = "VK_EXT_debug_report"; const char* extensions[] = {debug_ext,}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, .flags = 0, .pApplicationInfo = NULL, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = NELEMS(extensions), .ppEnabledExtensionNames = extensions, }; assert(vkCreateInstance(&create_info, NULL, &instance) == VK_SUCCESS); } VkDebugReportCallbackEXT debug_callback; { VkDebugReportCallbackCreateInfoEXT create_info = { .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, .pNext = NULL, .flags = (VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT), .pfnCallback = &debugReportCallback, .pUserData = NULL, }; PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); assert(createDebugReportCallback); assert(createDebugReportCallback(instance, &create_info, NULL, &debug_callback) == VK_SUCCESS); } VkPhysicalDevice phy_device; { uint32_t num_devices; assert(vkEnumeratePhysicalDevices(instance, &num_devices, NULL) == VK_SUCCESS); assert(num_devices >= 1); VkPhysicalDevice * phy_devices = malloc(sizeof(*phy_devices) * num_devices); assert(vkEnumeratePhysicalDevices(instance, &num_devices, phy_devices) == VK_SUCCESS); phy_device = phy_devices[0]; free(phy_devices); } VkPhysicalDeviceMemoryProperties memory_properties; vkGetPhysicalDeviceMemoryProperties(phy_device, &memory_properties); VkDevice device; { float queue_priorities[] = {1.0}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; uint32_t nqueues; matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, NULL); assert(nqueues > 0); uint32_t * queue_family_idxs = malloc(sizeof(*queue_family_idxs) * nqueues); matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, queue_family_idxs); VkDeviceQueueCreateInfo queue_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueFamilyIndex = queue_family_idxs[0], .queueCount = 1, .pQueuePriorities = queue_priorities, }; free(queue_family_idxs); VkPhysicalDeviceFeatures features = { .geometryShader = VK_TRUE, .fillModeNonSolid = VK_TRUE, }; VkDeviceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_info, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = 0, .ppEnabledExtensionNames = NULL, .pEnabledFeatures = &features, }; assert(vkCreateDevice(phy_device, &create_info, NULL, &device) == VK_SUCCESS); } VkQueue queue; vkGetDeviceQueue(device, 0, 0, &queue); VkCommandPool cmd_pool; { VkCommandPoolCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = NULL, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = 0, }; assert(vkCreateCommandPool(device, &create_info, NULL, &cmd_pool) == VK_SUCCESS); } VkRenderPass render_pass; { VkAttachmentDescription attachments[] = {{ .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_D16_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_1_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, }}; VkAttachmentReference attachment_refs[NELEMS(attachments)] = {{ .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .attachment = 1, .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .attachment = 2, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }}; VkSubpassDescription subpasses[1] = {{ .flags = 0, .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .inputAttachmentCount = 0, .pInputAttachments = NULL, .colorAttachmentCount = 1, .pColorAttachments = &attachment_refs[0], .pResolveAttachments = &attachment_refs[2], .pDepthStencilAttachment = &attachment_refs[1], .preserveAttachmentCount = 0, .pPreserveAttachments = NULL, }}; VkSubpassDependency dependencies[] = {{ .srcSubpass = 0, .dstSubpass = VK_SUBPASS_EXTERNAL, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .dependencyFlags = 0, }}; VkRenderPassCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, .pNext = NULL, .flags = 0, .attachmentCount = NELEMS(attachments), .pAttachments = attachments, .subpassCount = NELEMS(subpasses), .pSubpasses = subpasses, .dependencyCount = NELEMS(dependencies), .pDependencies = dependencies, }; assert(vkCreateRenderPass(device, &create_info, NULL, &render_pass) == VK_SUCCESS); } VkImage images[3]; VkDeviceMemory image_memories[NELEMS(images)]; VkImageView views[NELEMS(images)]; createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[0], &image_memories[0], &views[0]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_D16_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, &images[1], &image_memories[1], &views[1]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[2], &image_memories[2], &views[2]); VkBuffer verts_buffer; VkDeviceMemory verts_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, sizeof(verts), verts, &verts_buffer, &verts_memory); VkBuffer index_buffer; VkDeviceMemory index_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, sizeof(indices), indices, &index_buffer, &index_memory); VkBuffer image_buffer; VkDeviceMemory image_buffer_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, render_size.height * render_size.width * 4, NULL, &image_buffer, &image_buffer_memory); VkFramebuffer framebuffer; createFramebuffer(device, render_size, 3, views, render_pass, &framebuffer); VkShaderModule shaders[5]; { char* filenames[NELEMS(shaders)] = {"cube.vert.spv", "cube.geom.spv", "cube.frag.spv", "wireframe.geom.spv", "color.frag.spv"}; for (size_t i = 0; i < NELEMS(shaders); i++){ size_t code_size; uint32_t * code; assert((code_size = loadModule(filenames[i], &code)) != 0); VkShaderModuleCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .pNext = NULL, .flags = 0, .codeSize = code_size, .pCode = code, }; assert(vkCreateShaderModule(device, &create_info, NULL, &shaders[i]) == VK_SUCCESS); free(code); } } VkPipelineLayout pipeline_layout; { VkPushConstantRange push_range = { .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = 4, }; VkPipelineLayoutCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = NULL, .flags = 0, .setLayoutCount = 0, .pSetLayouts = NULL, .pushConstantRangeCount = 1, .pPushConstantRanges = &push_range, }; assert(vkCreatePipelineLayout(device, &create_info, NULL, &pipeline_layout) == VK_SUCCESS); } VkPipeline pipelines[2]; { VkPipelineShaderStageCreateInfo stages[3] = {{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = shaders[0], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_GEOMETRY_BIT, .module = shaders[1], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = shaders[2], .pName = "main", .pSpecializationInfo = NULL, }}; VkVertexInputBindingDescription vtx_binding = { .binding = 0, .stride = sizeof(struct Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, }; VkVertexInputAttributeDescription vtx_attr = { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(struct Vertex, pos), }; VkPipelineVertexInputStateCreateInfo vtx_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &vtx_binding, .vertexAttributeDescriptionCount = 1, .pVertexAttributeDescriptions = &vtx_attr, }; VkPipelineInputAssemblyStateCreateInfo ia_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, .primitiveRestartEnable = VK_TRUE, }; VkViewport viewport = { .x = 0, .y = 0, .width = render_size.width, .height = render_size.height, .minDepth = 0.0, .maxDepth = 1.0, }; VkRect2D scissor= { .offset = {.x = 0, .y = 0,}, .extent = render_size, }; VkPipelineViewportStateCreateInfo viewport_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .viewportCount = 1, .pViewports = &viewport, .scissorCount = 1, .pScissors = &scissor, }; VkPipelineRasterizationStateCreateInfo rasterization_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, .cullMode = VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .lineWidth = 1.0, }; VkPipelineMultisampleStateCreateInfo multisample_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT, .sampleShadingEnable = VK_FALSE, .minSampleShading = 0.0, .pSampleMask = NULL, .alphaToCoverageEnable = VK_FALSE, .alphaToOneEnable = VK_FALSE, }; VkPipelineDepthStencilStateCreateInfo depth_stencil_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthTestEnable = VK_TRUE, .depthWriteEnable = VK_TRUE, .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL, .depthBoundsTestEnable = VK_FALSE, .stencilTestEnable = VK_FALSE, .front = {}, .back = {}, .minDepthBounds = 0.0, .maxDepthBounds = 1.0, }; VkPipelineColorBlendAttachmentState color_blend_attachment = { .blendEnable = VK_FALSE, .colorWriteMask = ( VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT), }; VkPipelineColorBlendStateCreateInfo color_blend_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .logicOpEnable = VK_FALSE, //.logicOp = 0, .attachmentCount = 1, .pAttachments = &color_blend_attachment, .blendConstants = {}, }; VkGraphicsPipelineCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = NULL, .flags = 0, .stageCount = NELEMS(stages), .pStages = stages, .pVertexInputState = &vtx_state, .pInputAssemblyState = &ia_state, .pTessellationState = NULL, .pViewportState = &viewport_state, .pRasterizationState = &rasterization_state, .pMultisampleState = &multisample_state, .pDepthStencilState = &depth_stencil_state, .pColorBlendState = &color_blend_state, .pDynamicState = NULL, .layout = pipeline_layout, .renderPass = render_pass, .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, }; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[0]) == VK_SUCCESS); stages[1].module = shaders[3]; stages[2].module = shaders[4]; rasterization_state.polygonMode = VK_POLYGON_MODE_LINE; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[1]) == VK_SUCCESS); } VkCommandBuffer draw_buffers[2]; { VkCommandBufferAllocateInfo allocate_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, .commandPool = cmd_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = NELEMS(draw_buffers), }; assert(vkAllocateCommandBuffers(device, &allocate_info, draw_buffers) == VK_SUCCESS); } { VkCommandBufferBeginInfo begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = NULL, .flags = 0, .pInheritanceInfo = NULL, }; VkClearValue clear_values[] = {{ .color.float32 = {0.0, 0.0, 0.0, 1.0}, }, { .depthStencil = {.depth = 1.0}, }}; VkRenderPassBeginInfo renderpass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = NULL, .renderPass = render_pass, .framebuffer = framebuffer, .renderArea = { .offset = {.x = 0, .y = 0}, .extent = render_size, }, .clearValueCount = NELEMS(clear_values), .pClearValues = clear_values, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ assert(vkBeginCommandBuffer(draw_buffers[i], &begin_info) == VK_SUCCESS); uint32_t persp = i == 0; vkCmdPushConstants(draw_buffers[i], pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(persp), &persp); vkCmdBeginRenderPass(draw_buffers[i], &renderpass_begin_info, VK_SUBPASS_CONTENTS_INLINE); VkDeviceSize offset = 0; vkCmdBindVertexBuffers(draw_buffers[i], 0, 1, &verts_buffer, &offset); vkCmdBindIndexBuffer(draw_buffers[i], index_buffer, 0, VK_INDEX_TYPE_UINT32); for (size_t j = 0; j < NELEMS(pipelines); j++) { vkCmdBindPipeline(draw_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[j]); vkCmdDrawIndexed(draw_buffers[i], 20, 27, 0, 0, 0); } vkCmdEndRenderPass(draw_buffers[i]); } VkBufferImageCopy copy = { .bufferOffset = 0, .bufferRowLength = 0, // Tightly packed .bufferImageHeight = 0, // Tightly packed .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, .imageOffset = {0, 0, 0}, .imageExtent = {.width = render_size.width, .height = render_size.height, .depth = 1}, }; VkBufferMemoryBarrier transfer_barrier = { .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .pNext = 0, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_HOST_READ_BIT, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .buffer = image_buffer, .offset = 0, .size = VK_WHOLE_SIZE, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ vkCmdCopyImageToBuffer(draw_buffers[i], images[2], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image_buffer, 1, ©); vkCmdPipelineBarrier(draw_buffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &transfer_barrier, 0, NULL); assert(vkEndCommandBuffer(draw_buffers[i]) == VK_SUCCESS); } } VkFence fence; { VkFenceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; assert(vkCreateFence(device, &create_info, NULL, &fence) == VK_SUCCESS); } { char * filenames[] = {"cube_persp.tif", "cube_ortho.tif"}; char * image_data; assert(vkMapMemory(device, image_buffer_memory, 0, VK_WHOLE_SIZE, 0, (void **) &image_data) == VK_SUCCESS); VkMappedMemoryRange image_flush = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .pNext = NULL, .memory = image_buffer_memory, .offset = 0, .size = VK_WHOLE_SIZE, }; VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = NULL, .waitSemaphoreCount = 0, .pWaitSemaphores = NULL, .pWaitDstStageMask = NULL, .commandBufferCount = 1, .pCommandBuffers = NULL, .signalSemaphoreCount = 0, .pSignalSemaphores = NULL, }; for (size_t i = 0; i < NELEMS(filenames); i++){ submit_info.pCommandBuffers = &draw_buffers[i]; assert(vkResetFences(device, 1, &fence) == VK_SUCCESS); assert(vkQueueSubmit(queue, 1, &submit_info, fence) == VK_SUCCESS); assert(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX) == VK_SUCCESS); assert(vkInvalidateMappedMemoryRanges(device, 1, &image_flush) == VK_SUCCESS); assert(writeTiff(filenames[i], image_data, render_size, nchannels) == 0); } vkUnmapMemory(device, image_buffer_memory); } assert(vkQueueWaitIdle(queue) == VK_SUCCESS); vkDestroyFence(device, fence, NULL); vkDestroyFramebuffer(device, framebuffer, NULL); for (size_t i = 0; i < NELEMS(images); i++){ vkDestroyImage(device, images[i], NULL); vkDestroyImageView(device, views[i], NULL); vkFreeMemory(device, image_memories[i], NULL); } vkDestroyBuffer(device, image_buffer, NULL); vkFreeMemory(device, image_buffer_memory, NULL); vkDestroyBuffer(device, verts_buffer, NULL); vkFreeMemory(device, verts_memory, NULL); vkDestroyBuffer(device, index_buffer, NULL); vkFreeMemory(device, index_memory, NULL); for (size_t i = 0; i < NELEMS(pipelines); i++){ vkDestroyPipeline(device, pipelines[i], NULL); } vkDestroyPipelineLayout(device, pipeline_layout, NULL); for(size_t i = 0; i < NELEMS(shaders); i++) vkDestroyShaderModule(device, shaders[i], NULL); vkDestroyRenderPass(device, render_pass, NULL); vkFreeCommandBuffers(device, cmd_pool, NELEMS(draw_buffers), draw_buffers); vkDestroyCommandPool(device, cmd_pool, NULL); vkDestroyDevice(device, NULL); { PFN_vkDestroyDebugReportCallbackEXT destroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); assert(destroyDebugReportCallback); destroyDebugReportCallback(instance, debug_callback, NULL); } vkDestroyInstance(instance, NULL); return 0; }
void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; clearValues[0].color = defaultClearColor; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.renderArea.offset.y = 0; renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; VkResult err; for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { // Set target frame buffer renderPassBeginInfo.framebuffer = frameBuffers[i]; err = vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo); assert(!err); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vkTools::initializers::viewport( (float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vkTools::initializers::rect2D( width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); // Update light positions // w component = light radius scale #define r 7.5f #define sin_t sin(deg_to_rad(timer * 360)) #define cos_t cos(deg_to_rad(timer * 360)) #define y -4.0f pushConstants[0] = glm::vec4(r * 1.1 * sin_t, y, r * 1.1 * cos_t, 1.0f); pushConstants[1] = glm::vec4(-r * sin_t, y, -r * cos_t, 1.0f); pushConstants[2] = glm::vec4(r * 0.85f * sin_t, y, -sin_t * 2.5f, 1.5f); pushConstants[3] = glm::vec4(0.0f, y, r * 1.25f * cos_t, 1.5f); pushConstants[4] = glm::vec4(r * 2.25f * cos_t, y, 0.0f, 1.25f); pushConstants[5] = glm::vec4(r * 2.5f * cos(deg_to_rad(timer * 360)), y, r * 2.5f * sin_t, 1.25f); #undef r #undef y #undef sin_t #undef cos_t vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); // Submit via push constant (rather than a UBO) vkCmdPushConstants( drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, VK_FLAGS_NONE, sizeof(pushConstants), pushConstants.data()); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.scene.vertices.buf, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.scene.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(drawCmdBuffers[i], meshes.scene.indexCount, 1, 0, 0, 0); vkCmdEndRenderPass(drawCmdBuffers[i]); VkImageMemoryBarrier prePresentBarrier = vkTools::prePresentBarrier(swapChain.buffers[i].image); vkCmdPipelineBarrier( drawCmdBuffers[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_FLAGS_NONE, 0, nullptr, 0, nullptr, 1, &prePresentBarrier); err = vkEndCommandBuffer(drawCmdBuffers[i]); assert(!err); } }
void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; clearValues[0].color = defaultClearColor; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.renderArea.offset.y = 0; renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { renderPassBeginInfo.framebuffer = frameBuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); // Reset timestamp query pool vkCmdResetQueryPool(drawCmdBuffers[i], queryPool, 0, static_cast<uint32_t>(pipelineStats.size())); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); VkDeviceSize offsets[1] = { 0 }; // Start capture of pipeline statistics vkCmdBeginQuery(drawCmdBuffers[i], queryPool, 0, VK_QUERY_CONTROL_PRECISE_BIT); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); for (int32_t y = 0; y < gridSize; y++) { for (int32_t x = 0; x < gridSize; x++) { glm::vec3 pos = glm::vec3(float(x - (gridSize / 2.0f)) * 2.5f, 0.0f, float(y - (gridSize / 2.0f)) * 2.5f); vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); } } // End capture of pipeline statistics vkCmdEndQuery(drawCmdBuffers[i], queryPool, 0); drawUI(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } }
void Font::drawText(const ICommandBuffersSP& cmdBuffer, const glm::mat4& viewProjection, const glm::vec2& translate, const std::string& text, const glm::vec4& color) const { if (!cmdBuffer.get()) { return; } // const VkBuffer buffers[1] = {vertexBuffer->getBuffer()->getBuffer()}; VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(cmdBuffer->getCommandBuffer(), 0, 1, buffers, offsets); // glm::vec2 cursor = translate; const Char* lastCharacter = nullptr; for (auto c : text) { // Line break. if (c == '\n') { cursor.x = translate.x; cursor.y += getLineHeight(); lastCharacter = nullptr; continue; } auto currentCharacter = allCharacters.find((int32_t)c); if (currentCharacter == allCharacters.end()) { // Character not found. lastCharacter = nullptr; continue; } // // Advance, depending on kerning of current and last character. // if (lastCharacter) { cursor.x += lastCharacter->getKerning(currentCharacter->second.getId()); } // // Get bottom left corner of the character texture. // glm::vec2 origin = cursor; origin.y += getBase(); origin.x -= currentCharacter->second.getXoffset(); // Draw Character. glm::mat4 transformVertex = viewProjection * translateMat4(origin.x, origin.y, 0.0f); vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 16, glm::value_ptr(transformVertex)); glm::mat3 translateTexCoord = translateMat3(currentCharacter->second.getX() / getScaleWidth(), (getScaleHeight() - currentCharacter->second.getY() - currentCharacter->second.getHeight()) / getScaleHeight()); glm::mat3 scaleTexCoord = scaleMat3(currentCharacter->second.getWidth() / getScaleWidth(), currentCharacter->second.getHeight() / getScaleHeight(), 1.0f); glm::mat3 transformTexCoord = translateTexCoord * scaleTexCoord; vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 16, sizeof(float) * 9, glm::value_ptr(transformTexCoord)); vkCmdPushConstants(cmdBuffer->getCommandBuffer(), graphicsPipeline->getLayout(), VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 16 + sizeof(float) * 12, sizeof(float) * 4, glm::value_ptr(color)); // Expecting triangle strip as primitive topology. vkCmdDraw(cmdBuffer->getCommandBuffer(), 4, 1, 0, 0); // // Advance, as character has been drawn. // cursor.x += currentCharacter->second.getXadvance(); lastCharacter = ¤tCharacter->second; } }
void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; clearValues[0].color = { { 0.15f, 0.15f, 0.15f, 1.0f } }; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.renderArea.offset.y = 0; renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { renderPassBeginInfo.framebuffer = frameBuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); VkDeviceSize offsets[1] = { 0 }; // Render objects vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &model.vertices.buffer, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); uint32_t objcount = static_cast<uint32_t>(objects.size()); for (uint32_t x = 0; x < objcount; x++) { /* [POI] Bind descriptor sets Set 0 = Scene matrices: Set 1 = Object inline uniform block (In shader pbr.frag: layout (set = 1, binding = 0) uniform UniformInline ... ) */ std::vector<VkDescriptorSet> descriptorSets = { descriptorSet, objects[x].descriptorSet }; vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, descriptorSets.data(), 0, nullptr); glm::vec3 pos = glm::vec3(sin(glm::radians(x * (360.0f / objcount))), cos(glm::radians(x * (360.0f / objcount))), 0.0f) * 3.5f; vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); vkCmdDrawIndexed(drawCmdBuffers[i], model.indexCount, 1, 0, 0, 0); } drawUI(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } }
// Builds the secondary command buffer for each thread void threadRenderCode(uint32_t threadIndex, uint32_t cmdBufferIndex, VkCommandBufferInheritanceInfo inheritanceInfo) { ThreadData *thread = &threadData[threadIndex]; ObjectData *objectData = &thread->objectData[cmdBufferIndex]; // Check visibility against view frustum objectData->visible = frustum.checkSphere(objectData->pos, objectSphereDim * 0.5f); if (!objectData->visible) { return; } VkCommandBufferBeginInfo commandBufferBeginInfo = vkTools::initializers::commandBufferBeginInfo(); commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo; VkCommandBuffer cmdBuffer = thread->commandBuffer[cmdBufferIndex]; VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &commandBufferBeginInfo)); VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(cmdBuffer, 0, 1, &viewport); VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(cmdBuffer, 0, 1, &scissor); vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong); // Update objectData->rotation.y += 2.5f * objectData->rotationSpeed * frameTimer; if (objectData->rotation.y > 360.0f) { objectData->rotation.y -= 360.0f; } objectData->deltaT += 0.15f * frameTimer; if (objectData->deltaT > 1.0f) objectData->deltaT -= 1.0f; objectData->pos.y = sin(glm::radians(objectData->deltaT * 360.0f)) * 2.5f; objectData->model = glm::translate(glm::mat4(), objectData->pos); objectData->model = glm::rotate(objectData->model, -sinf(glm::radians(objectData->deltaT * 360.0f)) * 0.25f, glm::vec3(objectData->rotationDir, 0.0f, 0.0f)); objectData->model = glm::rotate(objectData->model, glm::radians(objectData->rotation.y), glm::vec3(0.0f, objectData->rotationDir, 0.0f)); objectData->model = glm::rotate(objectData->model, glm::radians(objectData->deltaT * 360.0f), glm::vec3(0.0f, objectData->rotationDir, 0.0f)); objectData->model = glm::scale(objectData->model, glm::vec3(objectData->scale)); thread->pushConstBlock[cmdBufferIndex].mvp = matrices.projection * matrices.view * objectData->model; // Update shader push constant block // Contains model view matrix vkCmdPushConstants( cmdBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(ThreadPushConstantBlock), &thread->pushConstBlock[cmdBufferIndex]); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &meshes.ufo.vertices.buf, offsets); vkCmdBindIndexBuffer(cmdBuffer, meshes.ufo.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(cmdBuffer, meshes.ufo.indexCount, 1, 0, 0, 0); VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuffer)); }
void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; clearValues[0].color = defaultClearColor; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.renderArea.offset.y = 0; renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { // Set target frame buffer renderPassBeginInfo.framebuffer = frameBuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); VkDeviceSize offsets[1] = { 0 }; // Objects vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); Material mat = materials[materialIndex]; //#define SINGLE_ROW 1 #ifdef SINGLE_ROW mat.params.metallic = 1.0; uint32_t objcount = 10; for (uint32_t x = 0; x < objcount; x++) { glm::vec3 pos = glm::vec3(float(x - (objcount / 2.0f)) * 2.5f, 0.0f, 0.0f); mat.params.roughness = glm::clamp((float)x / (float)objcount, 0.005f, 1.0f); vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::vec3), sizeof(Material::PushBlock), &mat); vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); } #else for (uint32_t y = 0; y < GRID_DIM; y++) { for (uint32_t x = 0; x < GRID_DIM; x++) { glm::vec3 pos = glm::vec3(float(x - (GRID_DIM / 2.0f)) * 2.5f, 0.0f, float(y - (GRID_DIM / 2.0f)) * 2.5f); vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); mat.params.metallic = glm::clamp((float)x / (float)(GRID_DIM - 1), 0.1f, 1.0f); mat.params.roughness = glm::clamp((float)y / (float)(GRID_DIM - 1), 0.05f, 1.0f); vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::vec3), sizeof(Material::PushBlock), &mat); vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); } } #endif vkCmdEndRenderPass(drawCmdBuffers[i]); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } }
// Create all threads and initialize shader push constants void prepareMultiThreadedRenderer() { VkResult err; renderThreads.resize(numThreads); uint32_t index = 0; for (auto& thread : renderThreads) { // Command pool VkCommandPoolCreateInfo cmdPoolInfo = vkTools::initializers::commandPoolCreateInfo(); cmdPoolInfo.queueFamilyIndex = swapChain.queueNodeIndex; cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; err = vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &thread.cmdPool); assert(!err); // Command buffer // Use secondary level command buffers thread.cmdBuffers.resize(swapChain.imageCount); VkCommandBufferAllocateInfo cmdBufAllocateInfo = vkTools::initializers::commandBufferAllocateInfo( thread.cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY, (uint32_t)thread.cmdBuffers.size()); err = vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, thread.cmdBuffers.data()); assert(!err); // Push constant block // Color // todo : randomize thread.pushConstantBlock.color = glm::vec3(1.0f, 1.0f, 1.0f); // Model matrix float rot = (float)(rand() % 360); float deltaT = (float)(rand() % 255) / 255.0f; glm::mat4 modelMat = glm::translate(glm::mat4(), glm::vec3((float)index * 4.0f - (float)(numThreads-1) * 2.0f, 0.0f, 0.0f)); modelMat = glm::rotate(modelMat, -sinf(glm::radians(deltaT * 360.0f)) * 0.25f, glm::vec3(1.0f, 0.0f, 0.0f)); modelMat = glm::rotate(modelMat, glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f)); modelMat = glm::rotate(modelMat, glm::radians(deltaT * 360.0f), glm::vec3(0.0f, 1.0f, 0.0f)); thread.pushConstantBlock.model = modelMat; thread.thread = std::thread([=] { threadUpdate(index); }); index++; // Viewport and scissor rect are shared VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); // Fill command buffers for (uint32_t i = 0; i < thread.cmdBuffers.size(); ++i) { // Inheritance infor for secondary command buffers VkCommandBufferInheritanceInfo inheritanceInfo = vkTools::initializers::commandBufferInheritanceInfo(); inheritanceInfo.renderPass = renderPass; inheritanceInfo.framebuffer = frameBuffers[i]; VkCommandBufferBeginInfo beginInfo = vkTools::initializers::commandBufferBeginInfo(); beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; beginInfo.pInheritanceInfo = &inheritanceInfo; vkBeginCommandBuffer(thread.cmdBuffers[i], &beginInfo); vkCmdSetViewport(thread.cmdBuffers[i], 0, 1, &viewport); vkCmdSetScissor(thread.cmdBuffers[i], 0, 1, &scissor); vkCmdBindPipeline(thread.cmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong); // Update shader push constant block // Contains model view matrix vkCmdPushConstants( thread.cmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(ThreadPushConstantBlock), &thread.pushConstantBlock); // Render mesh VkDeviceSize offsets[1] = { 0 }; vkCmdBindDescriptorSets(thread.cmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindVertexBuffers(thread.cmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.ufo.vertices.buf, offsets); vkCmdBindIndexBuffer(thread.cmdBuffers[i], meshes.ufo.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(thread.cmdBuffers[i], meshes.ufo.indexCount, 1, 0, 0, 0); vkEndCommandBuffer(thread.cmdBuffers[i]); } } for (auto& thread : renderThreads) { thread.thread.join(); } }