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