当前位置: 首页 > news >正文

Vulkan 学习(6)---- vkBuffer 创建

目录

        • Overview
        • VkBuffer 创建
        • VkBufferRequirement 查询
        • 参考代码

Overview

Vulkan中的缓存资源通过VkBuffer对象来表示,是一种用于存储通用数据的资源,可以用来存储顶点数据,索引数据,Uniforms 数据块等

VkBuffer 表示的是一个线性内存块,这说明它的内存布局是连续的,类似于数组
这种布局适合存储顺序访问的数据,比如 顶点数据和索引数据,也支持随机访问

VkBuffer 创建

创建 VkBuffer 时,可以通过设置 VkBufferCreateInfo 不同的 usage 标志来指定 VkBuffer 的用途
vkCreateBuffer 的函数原型是:

VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice                                    device,const VkBufferCreateInfo*                   pCreateInfo,const VkAllocationCallbacks*                pAllocator,VkBuffer*                                   pBuffer);

其中的关键配置信息是pCreateInfo,其类型VkBufferCreateInfo定义如下:

typedef struct VkBufferCreateInfo {VkStructureType        sType; // 必须为 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFOconst void*            pNext; // nullptrVkBufferCreateFlags    flags; // 0VkDeviceSize           size; // 缓存大小,单位为字节VkBufferUsageFlags     usage; // usage ,importantVkSharingMode          sharingMode; // 缓存的共享模式uint32_t               queueFamilyIndexCount; // 指定 pQueueFamilyIndices 数组中元素数量const uint32_t*        pQueueFamilyIndices;// 指定将会访问该缓存的设备队列
} VkBufferCreateInfo;

其中需要重点关注的是 VkBufferUsageFlags,定义如下:

typedef enum VkBufferUsageFlagBits {VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001,VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002,VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004,VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008,VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020,VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
}
  • VK_BUFFER_USAGE_TRANSFER_SRC_BIT 该缓存用于数据传输的数据源
  • VK_BUFFER_USAGE_TRANSFER_DST_BIT 该缓存用于数据传输的目的数据
  • VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT 该缓存用于传输统一纹理像素
  • VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT 该缓存用于保存纹理像素数据
  • VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 该缓存用于传输任意统一数据
  • VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 该缓存用于存储任意格式数据。用于设备读取和存
  • VK_BUFFER_USAGE_INDEX_BUFFER_BIT 该缓存用于存储整型索引数据
  • VK_BUFFER_USAGE_VERTEX_BUFFER_BIT该缓存用于存储具有相同结构的顶点数据
  • VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT 该缓存用于间接数据。用于存储指令参数,设备可一次性读取这些参数

资源共享类型 vkSharingMode

typedef enum VkSharingMode {VK_SHARING_MODE_EXCLUSIVE = 0,VK_SHARING_MODE_CONCURRENT = 1,VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF
} VkSharingMode;
  • VK_SHARING_MODE_EXCLUSIVE 设备队列独享资源,该资源一次只能被一种设备队列族中的队列访问

  • VK_SHARING_MODE_CONCURRENT 设备队列共享资源,该资源只能一次被多种设备队列族中的队列访问

需要注意的是,在Vulkan中创建的所有资源(VkBuffer, VkImage等)都是虚资源
也就是说,创建的资源只是占用了一个位置,创建了一个句柄,并没有对应存储资源数据的内存,后续要通过 vkBindBufferMemory 将资源绑定到相应的设备内存 VkDeviceMemory,所以数据实际存储在设备内存
一旦设备内存绑定到一个资源对象(VkBuffer, VkImage)上,这个内存绑定就不能再次改变了

VkBufferRequirement 查询

在设备内存绑定到资源上之前,需要确定使用什么类型的内存,以及资源需要多少内存
这个时候,可以使用vkGetBufferMemoryRequirements获取缓冲区的内存需求,包括内存大小,对齐要求以及适合的内存类型,注意此API 是查询已经创建的 VkBuffer 的信息

vkGetBufferMemoryRequirements 的函数原型:

VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(VkDevice                                    device,VkBuffer                                    buffer,VkMemoryRequirements*                       pMemoryRequirements);

其中的 VkMemoryRequirements 包含了缓冲区的内存需求信息:

typedef struct VkMemoryRequirements {VkDeviceSize    size; // 缓冲区所需的内存大小(以自己为单位)VkDeviceSize    alignment; // 缓冲区的内存对齐要求uint32_t        memoryTypeBits; // 缓冲区的可用内存类型掩码
} VkMemoryRequirements;
参考代码

参考代码实现如下:

uint32_t vulkanBasicDemo::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {VkPhysicalDeviceMemoryProperties memProperties;vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {return i;}}throw std::runtime_error("failed to find suitable memory type!");
}void vulkanBasicDemo::vulkanCreateVulkanBuffer() {std::vector<float> vertices = {1.0f,  1.0f, 0.0f,1.0f,  1.0f, 0.0f,1.0f, -1.0f, 0.0f,1.0f, -1.0f, 0.0f,};// 创建 VkBuffer 用于存储顶点数据VkBufferCreateInfo bufferInfo = {};bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;bufferInfo.pNext = nullptr;bufferInfo.flags = 0;bufferInfo.size = sizeof(vertices); // 设置缓冲区大小bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; // 设置缓冲区用途bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // 共享模式bufferInfo.queueFamilyIndexCount = 1;bufferInfo.pQueueFamilyIndices = &graphicsQueueFamilyIndex;//设备队列索引VkBuffer vertexBuffer;if (vkCreateBuffer(device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) {throw std::runtime_error("failed to create vertex buffer!");}std::cout << "Create VkBuffer Success!!" << std::endl;// 获取内存需求, 包含 Vulkan 内存对齐信息,以及内存对齐之后,内存的 size\memoryTypeBitsVkMemoryRequirements memRequirements;vkGetBufferMemoryRequirements(device, vertexBuffer, &memRequirements);// 分配设备内存VkMemoryAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;// 获取到对CPU可见且自动同步的设备内存类型allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);VkDeviceMemory vertexBufferMemory;if (vkAllocateMemory(device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) {throw std::runtime_error("failed to allocate vertex buffer memory!");}// 绑定内存vkBindBufferMemory(device, vertexBuffer, vertexBufferMemory, 0);std::cout << "VkBuffer Bind Memory Success!!" << std::endl;// 内存映射,填充数据void* data;vkMapMemory(device, vertexBufferMemory, 0, bufferInfo.size, 0, &data);//获取设备内存映射的内存地址memcpy(data, vertices.data(), (size_t)bufferInfo.size);//将顶点数据拷贝到设备内存映射的内存地址// 内存解映射vkUnmapMemory(device, vertexBufferMemory);
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Flask-SQLAlchemy 和 Alembic 的结合
  • dubbo:dubbo整合nacos实现服务注册中心、配置中心(二)
  • GUI编程之PyQt5入门详解(01)
  • SSRF以及CSRF
  • 自行车制造5G智能工厂工业物联数字孪生平台,推进制造业数字化
  • FPGA时序约束
  • 【qt】windows下qt连接数据库
  • 《AI办公类工具PPT系列之五——ChatBA》
  • day_50
  • Vue3 组件 10
  • 使用密钥文件 SSH 登录服务器:Windows、macOS使用终端或连接工具
  • 日期类的实现
  • iptables: Chain Already Exists:完美解决方法
  • 通过因子分析识别消费者偏好的潜在因素的案例
  • 【异常错误】pycharm可以在terminal中运行,但是无法在run中运行(没有输出错误就停止了)
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • Codepen 每日精选(2018-3-25)
  • HTTP请求重发
  • Koa2 之文件上传下载
  • Redis 中的布隆过滤器
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • ucore操作系统实验笔记 - 重新理解中断
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 前端面试之闭包
  • 如何进阶一名有竞争力的程序员?
  • 使用API自动生成工具优化前端工作流
  • 小程序 setData 学问多
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • Java数据解析之JSON
  • # 飞书APP集成平台-数字化落地
  • #define,static,const,三种常量的区别
  • #微信小程序:微信小程序常见的配置传值
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (1)Jupyter Notebook 下载及安装
  • (6)添加vue-cookie
  • (java)关于Thread的挂起和恢复
  • (MATLAB)第五章-矩阵运算
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (贪心) LeetCode 45. 跳跃游戏 II
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • .dwp和.webpart的区别
  • .Family_物联网
  • .NET CORE Aws S3 使用
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .net 调用php,php 调用.net com组件 --
  • .NET 直连SAP HANA数据库
  • @RequestMapping用法详解
  • [ C++ ] STL---stack与queue
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [04]Web前端进阶—JS伪数组
  • [Android]常见的数据传递方式
  • [Deep Learning] 神经网络基础
  • [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-controller-manager失败