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