Buffer.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /**
  2. * Copyright (c) 2006-2023 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "Buffer.h"
  21. #include "Graphics.h"
  22. namespace love
  23. {
  24. namespace graphics
  25. {
  26. namespace vulkan
  27. {
  28. static VkBufferUsageFlags getUsageBit(BufferUsage mode)
  29. {
  30. switch (mode)
  31. {
  32. case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
  33. case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
  34. case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
  35. case BUFFERUSAGE_TEXEL: return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
  36. case BUFFERUSAGE_SHADER_STORAGE: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
  37. case BUFFERUSAGE_INDIRECT_ARGUMENTS: return VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
  38. default:
  39. throw love::Exception("unsupported BufferUsage mode");
  40. }
  41. }
  42. static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags)
  43. {
  44. VkBufferUsageFlags vkFlags = 0;
  45. for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++)
  46. {
  47. BufferUsageFlags flag = static_cast<BufferUsageFlags>(1u << i);
  48. if (flags & flag)
  49. vkFlags |= getUsageBit((BufferUsage)i);
  50. }
  51. return vkFlags;
  52. }
  53. Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector<DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
  54. : love::graphics::Buffer(gfx, settings, format, size, arraylength)
  55. , zeroInitialize(settings.zeroInitialize)
  56. , initialData(data)
  57. , vgfx(dynamic_cast<Graphics*>(gfx))
  58. , usageFlags(settings.usageFlags)
  59. {
  60. loadVolatile();
  61. }
  62. bool Buffer::loadVolatile()
  63. {
  64. allocator = vgfx->getVmaAllocator();
  65. VkBufferCreateInfo bufferInfo{};
  66. bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  67. bufferInfo.size = getSize();
  68. bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | getVulkanUsageFlags(usageFlags);
  69. VmaAllocationCreateInfo allocCreateInfo{};
  70. allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
  71. if (dataUsage == BUFFERDATAUSAGE_READBACK)
  72. allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
  73. else if ((bufferInfo.usage | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) || (bufferInfo.usage | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))
  74. allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
  75. auto result = vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo);
  76. if (result != VK_SUCCESS)
  77. throw love::Exception("failed to create buffer");
  78. if (zeroInitialize)
  79. vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, 0, VK_WHOLE_SIZE, 0);
  80. if (initialData)
  81. fill(0, size, initialData);
  82. if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
  83. {
  84. VkBufferViewCreateInfo bufferViewInfo{};
  85. bufferViewInfo.buffer = buffer;
  86. bufferViewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
  87. bufferViewInfo.format = Vulkan::getVulkanVertexFormat(getDataMember(0).decl.format);
  88. bufferViewInfo.range = VK_WHOLE_SIZE;
  89. if (vkCreateBufferView(vgfx->getDevice(), &bufferViewInfo, nullptr, &bufferView) != VK_SUCCESS)
  90. throw love::Exception("failed to create texel buffer view");
  91. }
  92. VkMemoryPropertyFlags memoryProperties;
  93. vmaGetAllocationMemoryProperties(allocator, allocation, &memoryProperties);
  94. if (memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
  95. coherent = true;
  96. else
  97. coherent = false;
  98. return true;
  99. }
  100. void Buffer::unloadVolatile()
  101. {
  102. if (buffer == VK_NULL_HANDLE)
  103. return;
  104. auto device = vgfx->getDevice();
  105. vgfx->queueCleanUp(
  106. [device=device, allocator=allocator, buffer=buffer, allocation=allocation, bufferView=bufferView](){
  107. vkDeviceWaitIdle(device);
  108. vmaDestroyBuffer(allocator, buffer, allocation);
  109. if (bufferView)
  110. vkDestroyBufferView(device, bufferView, nullptr);
  111. });
  112. buffer = VK_NULL_HANDLE;
  113. bufferView = VK_NULL_HANDLE;
  114. }
  115. Buffer::~Buffer()
  116. {
  117. unloadVolatile();
  118. }
  119. ptrdiff_t Buffer::getHandle() const
  120. {
  121. return (ptrdiff_t) buffer;
  122. }
  123. ptrdiff_t Buffer::getTexelBufferHandle() const
  124. {
  125. return (ptrdiff_t) bufferView;
  126. }
  127. void *Buffer::map(MapType map, size_t offset, size_t size)
  128. {
  129. if (size == 0)
  130. return nullptr;
  131. if (map == MAP_WRITE_INVALIDATE && (isImmutable() || dataUsage == BUFFERDATAUSAGE_READBACK))
  132. return nullptr;
  133. if (map == MAP_READ_ONLY && dataUsage != BUFFERDATAUSAGE_READBACK)
  134. return nullptr;
  135. mappedRange = Range(offset, size);
  136. if (!Range(0, getSize()).contains(mappedRange))
  137. return nullptr;
  138. if (dataUsage == BUFFERDATAUSAGE_READBACK)
  139. {
  140. if (!coherent)
  141. vmaInvalidateAllocation(allocator, allocation, offset, size);
  142. char *data = (char*)allocInfo.pMappedData;
  143. return (void*) (data + offset);
  144. }
  145. else
  146. {
  147. VkBufferCreateInfo bufferInfo{};
  148. bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  149. bufferInfo.size = size;
  150. bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  151. VmaAllocationCreateInfo allocInfo{};
  152. allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
  153. allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
  154. if (vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &stagingBuffer, &stagingAllocation, &stagingAllocInfo) != VK_SUCCESS)
  155. throw love::Exception("failed to create staging buffer");
  156. return stagingAllocInfo.pMappedData;
  157. }
  158. }
  159. bool Buffer::fill(size_t offset, size_t size, const void *data)
  160. {
  161. if (size == 0 || isImmutable() || dataUsage == BUFFERDATAUSAGE_READBACK)
  162. return false;
  163. if (!Range(0, getSize()).contains(Range(offset, size)))
  164. return false;
  165. VkBufferCreateInfo bufferInfo{};
  166. bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  167. bufferInfo.size = size;
  168. bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  169. VmaAllocationCreateInfo allocInfo{};
  170. allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
  171. allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
  172. VkBuffer fillBuffer;
  173. VmaAllocation fillAllocation;
  174. VmaAllocationInfo fillAllocInfo;
  175. if (vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &fillBuffer, &fillAllocation, &fillAllocInfo) != VK_SUCCESS)
  176. throw love::Exception("failed to create fill buffer");
  177. memcpy(fillAllocInfo.pMappedData, data, size);
  178. VkMemoryPropertyFlags memoryProperties;
  179. vmaGetAllocationMemoryProperties(allocator, fillAllocation, &memoryProperties);
  180. if (~memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
  181. vmaFlushAllocation(allocator, fillAllocation, 0, size);
  182. VkBufferCopy bufferCopy{};
  183. bufferCopy.srcOffset = 0;
  184. bufferCopy.dstOffset = offset;
  185. bufferCopy.size = size;
  186. vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), fillBuffer, buffer, 1, &bufferCopy);
  187. vgfx->queueCleanUp([allocator = allocator, fillBuffer = fillBuffer, fillAllocation = fillAllocation]() {
  188. vmaDestroyBuffer(allocator, fillBuffer, fillAllocation);
  189. });
  190. return true;
  191. }
  192. void Buffer::unmap(size_t usedoffset, size_t usedsize)
  193. {
  194. if (dataUsage != BUFFERDATAUSAGE_READBACK)
  195. {
  196. VkBufferCopy bufferCopy{};
  197. bufferCopy.srcOffset = usedoffset - mappedRange.getOffset();
  198. bufferCopy.dstOffset = usedoffset;
  199. bufferCopy.size = usedsize;
  200. VkMemoryPropertyFlags memoryProperties;
  201. vmaGetAllocationMemoryProperties(allocator, stagingAllocation, &memoryProperties);
  202. if (~memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
  203. vmaFlushAllocation(allocator, stagingAllocation, bufferCopy.srcOffset, usedsize);
  204. vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), stagingBuffer, buffer, 1, &bufferCopy);
  205. vgfx->queueCleanUp([allocator = allocator, stagingBuffer = stagingBuffer, stagingAllocation = stagingAllocation]() {
  206. vmaDestroyBuffer(allocator, stagingBuffer, stagingAllocation);
  207. });
  208. }
  209. }
  210. void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
  211. {
  212. auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
  213. VkBufferCopy bufferCopy{};
  214. bufferCopy.srcOffset = sourceoffset;
  215. bufferCopy.dstOffset = destoffset;
  216. bufferCopy.size = size;
  217. vkCmdCopyBuffer(commandBuffer, buffer, (VkBuffer) dest->getHandle(), 1, &bufferCopy);
  218. }
  219. } // vulkan
  220. } // graphics
  221. } // love