Uniform buffer
成果
- Specify a descriptor layout during pipeline creation
- Allocate a descriptor set from a descriptor pool
- Bind the descriptor set during rendering
定義UBO架構(gòu)
struct UniformBufferObject { glm::mat4 model; glm::mat4 view; glm::mat4 proj; }; |
Vertex Shader使用範(fàn)例
#version 450 // descriptor layout(binding = 0) uniform UniformBufferObject { mat4 model; mat4 view; mat4 proj; } ubo; // attr layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { //gl_Position = vec4(inPosition, 0.0, 1.0); gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; } |
建立 descriptor set , pool , layout
void ltn::TransformObject::createDescriptorSetLayout() { // MVP uniform data VkDescriptorSetLayoutBinding uboLayoutBinding{}; uboLayoutBinding.binding = 0; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uboLayoutBinding.descriptorCount = 1; //Change this if you have multiple objects. uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; uboLayoutBinding.pImmutableSamplers = nullptr; // Optional // only relevant for image sampling related descriptors VkDescriptorSetLayoutCreateInfo layoutInfo{}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; if (vkCreateDescriptorSetLayout(m_core_instance.get_device(), &layoutInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } void ltn::TransformObject::createDescriptorPool() { VkDescriptorPoolSize poolSize{}; poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSize.descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); VkDescriptorPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.poolSizeCount = 1; poolInfo.pPoolSizes = &poolSize; poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); if (vkCreateDescriptorPool(m_core_instance.get_device(), &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } void ltn::TransformObject::createDescriptorSets() { std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, m_descriptorSetLayout); VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = m_descriptorPool; allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); allocInfo.pSetLayouts = layouts.data(); m_descriptorSets.resize(MAX_FRAMES_IN_FLIGHT); if (vkAllocateDescriptorSets(m_core_instance.get_device(), &allocInfo, m_descriptorSets.data()) != VK_SUCCESS) { throw std::runtime_error("failed to allocate descriptor sets!"); } } |
更新buffer
void ltn::TransformObject::updateUniformBuffer(FrameUpdateData& framedata) { // dummy test static auto startTime = std::chrono::high_resolution_clock::now(); auto currentTime = std::chrono::high_resolution_clock::now(); float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count(); UniformBufferObject ubo{}; ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.proj = glm::perspective(glm::radians(45.0f), framedata.aspect_ratio , 0.1f, 10.0f); ubo.proj[1][1] *= -1; memcpy(m_uniformBuffersMapped[framedata.current_image], &ubo, sizeof(ubo)); // update desc set VkDescriptorBufferInfo bufferInfo{}; bufferInfo.buffer = m_uniformBuffers[framedata.current_image]; bufferInfo.offset = 0; bufferInfo.range = sizeof(UniformBufferObject); VkWriteDescriptorSet descriptorWrite{}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.dstSet = m_descriptorSets[framedata.current_image]; descriptorWrite.dstBinding = 0; descriptorWrite.dstArrayElement = 0; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorWrite.descriptorCount = 1; descriptorWrite.pBufferInfo = &bufferInfo; descriptorWrite.pImageInfo = nullptr; // Optional descriptorWrite.pTexelBufferView = nullptr; // Optional vkUpdateDescriptorSets(m_core_instance.get_device(), 1, &descriptorWrite, 0, nullptr); } |
Binding
vkCmdBindPipeline( forward_renderer_pass->get_current_cmdbuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->get_pipeline()); vkCmdBindDescriptorSets( forward_renderer_pass->get_current_cmdbuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->get_layout(), 0, 1, &transform.m_descriptorSets[swapchain->current_frame()], 0, nullptr); model.bind(forward_renderer_pass->get_current_cmdbuffer()); model.draw(forward_renderer_pass->get_current_cmdbuffer()); |
Alignment 問(wèn)題
為甚麼創(chuàng)uniform buffer需要descriptorset但vertex buffer不需要?
不同用途的Descriptor Set可以共用一個(gè)DescriptorSetPool嗎?
VkDescriptorPoolSize poolSizes[] = { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10 }, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 10 } }; VkDescriptorPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.poolSizeCount = 2; poolInfo.pPoolSizes = poolSizes; poolInfo.maxSets = 10; VkDescriptorPool descriptorPool; if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } |