GrVkBuffer.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/gpu/vk/GrVkBuffer.h"
  8. #include "src/gpu/vk/GrVkGpu.h"
  9. #include "src/gpu/vk/GrVkMemory.h"
  10. #include "src/gpu/vk/GrVkTransferBuffer.h"
  11. #include "src/gpu/vk/GrVkUtil.h"
  12. #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
  13. #ifdef SK_DEBUG
  14. #define VALIDATE() this->validate()
  15. #else
  16. #define VALIDATE() do {} while(false)
  17. #endif
  18. const GrVkBuffer::Resource* GrVkBuffer::Create(const GrVkGpu* gpu, const Desc& desc) {
  19. SkASSERT(!gpu->protectedContext() || (gpu->protectedContext() == desc.fDynamic));
  20. VkBuffer buffer;
  21. GrVkAlloc alloc;
  22. // create the buffer object
  23. VkBufferCreateInfo bufInfo;
  24. memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
  25. bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  26. bufInfo.flags = 0;
  27. bufInfo.size = desc.fSizeInBytes;
  28. switch (desc.fType) {
  29. case kVertex_Type:
  30. bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
  31. break;
  32. case kIndex_Type:
  33. bufInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
  34. break;
  35. case kUniform_Type:
  36. bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
  37. break;
  38. case kCopyRead_Type:
  39. bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  40. break;
  41. case kCopyWrite_Type:
  42. bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  43. break;
  44. case kTexel_Type:
  45. bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
  46. }
  47. if (!desc.fDynamic) {
  48. bufInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  49. }
  50. bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  51. bufInfo.queueFamilyIndexCount = 0;
  52. bufInfo.pQueueFamilyIndices = nullptr;
  53. VkResult err;
  54. err = VK_CALL(gpu, CreateBuffer(gpu->device(), &bufInfo, nullptr, &buffer));
  55. if (err) {
  56. return nullptr;
  57. }
  58. if (!GrVkMemory::AllocAndBindBufferMemory(gpu,
  59. buffer,
  60. desc.fType,
  61. desc.fDynamic,
  62. &alloc)) {
  63. return nullptr;
  64. }
  65. const GrVkBuffer::Resource* resource = new GrVkBuffer::Resource(buffer, alloc, desc.fType);
  66. if (!resource) {
  67. VK_CALL(gpu, DestroyBuffer(gpu->device(), buffer, nullptr));
  68. GrVkMemory::FreeBufferMemory(gpu, desc.fType, alloc);
  69. return nullptr;
  70. }
  71. return resource;
  72. }
  73. void GrVkBuffer::addMemoryBarrier(const GrVkGpu* gpu,
  74. VkAccessFlags srcAccessMask,
  75. VkAccessFlags dstAccesMask,
  76. VkPipelineStageFlags srcStageMask,
  77. VkPipelineStageFlags dstStageMask,
  78. bool byRegion) const {
  79. VkBufferMemoryBarrier bufferMemoryBarrier = {
  80. VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
  81. nullptr, // pNext
  82. srcAccessMask, // srcAccessMask
  83. dstAccesMask, // dstAccessMask
  84. VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
  85. VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex
  86. this->buffer(), // buffer
  87. 0, // offset
  88. fDesc.fSizeInBytes, // size
  89. };
  90. // TODO: restrict to area of buffer we're interested in
  91. gpu->addBufferMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion,
  92. &bufferMemoryBarrier);
  93. }
  94. void GrVkBuffer::Resource::freeGPUData(GrVkGpu* gpu) const {
  95. SkASSERT(fBuffer);
  96. SkASSERT(fAlloc.fMemory);
  97. VK_CALL(gpu, DestroyBuffer(gpu->device(), fBuffer, nullptr));
  98. GrVkMemory::FreeBufferMemory(gpu, fType, fAlloc);
  99. }
  100. void GrVkBuffer::vkRelease(const GrVkGpu* gpu) {
  101. VALIDATE();
  102. fResource->recycle(const_cast<GrVkGpu*>(gpu));
  103. fResource = nullptr;
  104. if (!fDesc.fDynamic) {
  105. delete[] (unsigned char*)fMapPtr;
  106. }
  107. fMapPtr = nullptr;
  108. VALIDATE();
  109. }
  110. void GrVkBuffer::vkAbandon() {
  111. fResource->unrefAndAbandon();
  112. fResource = nullptr;
  113. if (!fDesc.fDynamic) {
  114. delete[] (unsigned char*)fMapPtr;
  115. }
  116. fMapPtr = nullptr;
  117. VALIDATE();
  118. }
  119. VkAccessFlags buffer_type_to_access_flags(GrVkBuffer::Type type) {
  120. switch (type) {
  121. case GrVkBuffer::kIndex_Type:
  122. return VK_ACCESS_INDEX_READ_BIT;
  123. case GrVkBuffer::kVertex_Type:
  124. return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
  125. default:
  126. // This helper is only called for static buffers so we should only ever see index or
  127. // vertex buffers types
  128. SkASSERT(false);
  129. return 0;
  130. }
  131. }
  132. void GrVkBuffer::internalMap(GrVkGpu* gpu, size_t size, bool* createdNewBuffer) {
  133. VALIDATE();
  134. SkASSERT(!this->vkIsMapped());
  135. if (!fResource->unique()) {
  136. if (fDesc.fDynamic) {
  137. // in use by the command buffer, so we need to create a new one
  138. fResource->recycle(gpu);
  139. fResource = this->createResource(gpu, fDesc);
  140. if (createdNewBuffer) {
  141. *createdNewBuffer = true;
  142. }
  143. } else {
  144. SkASSERT(fMapPtr);
  145. this->addMemoryBarrier(gpu,
  146. buffer_type_to_access_flags(fDesc.fType),
  147. VK_ACCESS_TRANSFER_WRITE_BIT,
  148. VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
  149. VK_PIPELINE_STAGE_TRANSFER_BIT,
  150. false);
  151. }
  152. }
  153. if (fDesc.fDynamic) {
  154. const GrVkAlloc& alloc = this->alloc();
  155. SkASSERT(alloc.fSize > 0);
  156. SkASSERT(alloc.fSize >= size);
  157. SkASSERT(0 == fOffset);
  158. fMapPtr = GrVkMemory::MapAlloc(gpu, alloc);
  159. } else {
  160. if (!fMapPtr) {
  161. fMapPtr = new unsigned char[this->size()];
  162. }
  163. }
  164. VALIDATE();
  165. }
  166. void GrVkBuffer::copyCpuDataToGpuBuffer(GrVkGpu* gpu, const void* src, size_t size) {
  167. SkASSERT(src);
  168. // We should never call this method in protected contexts.
  169. SkASSERT(!gpu->protectedContext());
  170. // The vulkan api restricts the use of vkCmdUpdateBuffer to updates that are less than or equal
  171. // to 65536 bytes and a size the is 4 byte aligned.
  172. if ((size <= 65536) && (0 == (size & 0x3)) && !gpu->vkCaps().avoidUpdateBuffers()) {
  173. gpu->updateBuffer(this, src, this->offset(), size);
  174. } else {
  175. sk_sp<GrVkTransferBuffer> transferBuffer =
  176. GrVkTransferBuffer::Make(gpu, size, GrVkBuffer::kCopyRead_Type);
  177. if (!transferBuffer) {
  178. return;
  179. }
  180. char* buffer = (char*) transferBuffer->map();
  181. memcpy (buffer, src, size);
  182. transferBuffer->unmap();
  183. gpu->copyBuffer(transferBuffer.get(), this, 0, this->offset(), size);
  184. }
  185. this->addMemoryBarrier(gpu,
  186. VK_ACCESS_TRANSFER_WRITE_BIT,
  187. buffer_type_to_access_flags(fDesc.fType),
  188. VK_PIPELINE_STAGE_TRANSFER_BIT,
  189. VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
  190. false);
  191. }
  192. void GrVkBuffer::internalUnmap(GrVkGpu* gpu, size_t size) {
  193. VALIDATE();
  194. SkASSERT(this->vkIsMapped());
  195. if (fDesc.fDynamic) {
  196. const GrVkAlloc& alloc = this->alloc();
  197. SkASSERT(alloc.fSize > 0);
  198. SkASSERT(alloc.fSize >= size);
  199. // We currently don't use fOffset
  200. SkASSERT(0 == fOffset);
  201. GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, size);
  202. GrVkMemory::UnmapAlloc(gpu, alloc);
  203. fMapPtr = nullptr;
  204. } else {
  205. SkASSERT(fMapPtr);
  206. this->copyCpuDataToGpuBuffer(gpu, fMapPtr, size);
  207. }
  208. }
  209. bool GrVkBuffer::vkIsMapped() const {
  210. VALIDATE();
  211. return SkToBool(fMapPtr);
  212. }
  213. bool GrVkBuffer::vkUpdateData(GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
  214. bool* createdNewBuffer) {
  215. if (srcSizeInBytes > fDesc.fSizeInBytes) {
  216. return false;
  217. }
  218. if (fDesc.fDynamic) {
  219. this->internalMap(gpu, srcSizeInBytes, createdNewBuffer);
  220. if (!fMapPtr) {
  221. return false;
  222. }
  223. memcpy(fMapPtr, src, srcSizeInBytes);
  224. this->internalUnmap(gpu, srcSizeInBytes);
  225. } else {
  226. this->copyCpuDataToGpuBuffer(gpu, src, srcSizeInBytes);
  227. }
  228. return true;
  229. }
  230. void GrVkBuffer::validate() const {
  231. SkASSERT(!fResource || kVertex_Type == fDesc.fType || kIndex_Type == fDesc.fType
  232. || kTexel_Type == fDesc.fType || kCopyRead_Type == fDesc.fType
  233. || kCopyWrite_Type == fDesc.fType || kUniform_Type == fDesc.fType);
  234. }