Vulkan中绘制操作和present是如何保证同步的
时间: 2024-04-23 20:25:14 浏览: 23
在Vulkan中,绘制操作和present是通过同步对象来保证同步的。同步对象有两种类型:栅栏和信号量。栅栏用于同步CPU和GPU之间的操作,信号量用于同步GPU内部的操作。
在绘制操作执行之前,我们需要创建一个栅栏,并在提交命令缓冲时将栅栏插入到队列中。当GPU完成命令缓冲中的所有操作时,它会自动触发栅栏,这样CPU就可以等待栅栏的触发来确保GPU完成了所有绘制操作。
而在present操作中,我们需要创建一个信号量,并在提交命令缓冲时将信号量插入到队列中。当GPU完成所有的绘制操作后,它会将信号量发送给present操作,present操作会等待信号量的到达来确保绘制操作完成后再进行present操作。
因此,通过使用栅栏和信号量,Vulkan可以保证绘制操作和present操作的同步。
相关问题
Vulkan 实现绘制到纹理的操作,给出简单的demo
以下是一个简单的Vulkan实现绘制到纹理的demo:
```c++
// 初始化Vulkan设备和图像
// ...
// 创建纹理图像
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageCreateInfo.extent.width = 512;
imageCreateInfo.extent.height = 512;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
vkCreateImage(device, &imageCreateInfo, nullptr, &textureImage);
// 分配内存并绑定纹理图像
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, textureImage, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(device, &allocInfo, nullptr, &textureImageMemory);
vkBindImageMemory(device, textureImage, textureImageMemory, 0);
// 创建图像视图
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.image = textureImage;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.subresourceRange.baseMipLevel = 0;
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.baseArrayLayer = 0;
viewCreateInfo.subresourceRange.layerCount = 1;
vkCreateImageView(device, &viewCreateInfo, nullptr, &textureImageView);
// 创建帧缓冲区
VkFramebufferCreateInfo framebufferCreateInfo = {};
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 1;
framebufferCreateInfo.pAttachments = &textureImageView;
framebufferCreateInfo.width = 512;
framebufferCreateInfo.height = 512;
framebufferCreateInfo.layers = 1;
vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer);
// 创建命令池和命令缓冲区
// ...
// 开始记录命令缓冲区
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
// 转换图像布局
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = textureImage;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
// 绑定渲染目标为纹理图像
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffer;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = 512;
renderPassBeginInfo.renderArea.extent.height = 512;
VkClearValue clearValue = {0.0f, 0.0f, 0.0f, 1.0f};
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// 绘制场景
// ...
// 结束渲染
vkCmdEndRenderPass(commandBuffer);
// 转换图像布局
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
// 完成命令缓冲区
vkEndCommandBuffer(commandBuffer);
// 提交命令
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(queue);
```
在这个demo中,我们创建了一个大小为512x512的纹理图像,并且将其绑定到帧缓冲区。然后我们使用命令缓冲区将场景渲染到帧缓冲区,最后将帧缓冲区中的图像拷贝到纹理图像中。注意,在拷贝之前,我们需要将纹理图像的布局从未定义的状态转换为可写入的状态,拷贝结束后,我们需要将纹理图像的布局从可写入的状态转换为只读状态。
vulkan 绘制三角形
要使用Vulkan绘制一个三角形,需要经过以下步骤:
1. 创建一个Vulkan实例
2. 创建一个逻辑设备
3. 创建一个窗口表面
4. 创建一个交换链
5. 创建渲染通道和帧缓冲区
6. 创建着色器模块
7. 创建管线布局和管线
8. 分配顶点缓冲区
9. 开始绘制
下面是一个简单的示例代码,用于绘制一个三角形:
```
// 顶点数据
std::vector<Vertex> vertices = {
{ { 0.0f, -0.5f },{ 1.0f, 0.0f, 0.0f } },
{ { 0.5f, 0.5f },{ 0.0f, 1.0f, 0.0f } },
{ { -0.5f, 0.5f },{ 0.0f, 0.0f, 1.0f } }
};
// 创建顶点缓冲区
VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
createBuffer(sizeof(vertices[0]) * vertices.size(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vertexBuffer, vertexBufferMemory);
// 在CPU上填充顶点缓冲区
void* data;
vkMapMemory(device, vertexBufferMemory, 0, sizeof(vertices[0]) * vertices.size(), 0, &data);
memcpy(data, vertices.data(), sizeof(vertices[0]) * vertices.size());
vkUnmapMemory(device, vertexBufferMemory);
// 创建渲染通道和帧缓冲区
VkRenderPass renderPass;
createRenderPass(renderPass);
VkFramebuffer framebuffer;
createFramebuffer(framebuffer);
// 创建着色器模块
VkShaderModule vertShaderModule;
VkShaderModule fragShaderModule;
createShaderModule("vert.spv", vertShaderModule);
createShaderModule("frag.spv", fragShaderModule);
// 创建管线布局和管线
VkPipelineLayout pipelineLayout;
VkPipeline pipeline;
createPipelineLayout(pipelineLayout);
createPipeline(pipeline, pipelineLayout, renderPass, vertShaderModule, fragShaderModule);
// 开始绘制
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
VkRenderPassBeginInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = framebuffer;
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtent;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
VkBuffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
vkCmdEndRenderPass(commandBuffer);
endSingleTimeCommands(commandBuffer);
```
这段代码中,我们首先创建一个包含三个顶点的顶点缓冲区,然后使用着色器模块、管线布局和管线来定义如何渲染这些顶点。最后,我们通过调用`vkCmdDraw`函数来绘制三角形。
相关推荐
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)