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 "GrVkTexture.h"
      9 
     10 #include "GrTexturePriv.h"
     11 #include "GrVkGpu.h"
     12 #include "GrVkImageView.h"
     13 #include "GrVkTextureRenderTarget.h"
     14 #include "GrVkUtil.h"
     15 
     16 #include "vk/GrVkTypes.h"
     17 
     18 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
     19 
     20 // This method parallels GrTextureProxy::highestFilterMode
     21 static inline GrSamplerState::Filter highest_filter_mode(GrPixelConfig config) {
     22     return GrSamplerState::Filter::kMipMap;
     23 }
     24 
     25 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
     26 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
     27                          SkBudgeted budgeted,
     28                          const GrSurfaceDesc& desc,
     29                          const GrVkImageInfo& info,
     30                          const GrVkImageView* view,
     31                          GrMipMapsStatus mipMapsStatus)
     32     : GrSurface(gpu, desc)
     33     , GrVkImage(info, GrBackendObjectOwnership::kOwned)
     34     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
     35                 mipMapsStatus)
     36     , fTextureView(view)
     37     , fLinearTextureView(nullptr) {
     38     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
     39     this->registerWithCache(budgeted);
     40 }
     41 
     42 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
     43                          Wrapped,
     44                          const GrSurfaceDesc& desc,
     45                          const GrVkImageInfo& info,
     46                          const GrVkImageView* view,
     47                          GrMipMapsStatus mipMapsStatus,
     48                          GrBackendObjectOwnership ownership)
     49     : GrSurface(gpu, desc)
     50     , GrVkImage(info, ownership)
     51     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
     52                 mipMapsStatus)
     53     , fTextureView(view)
     54     , fLinearTextureView(nullptr) {
     55     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
     56     this->registerWithCacheWrapped();
     57 }
     58 
     59 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
     60 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
     61                          const GrSurfaceDesc& desc,
     62                          const GrVkImageInfo& info,
     63                          const GrVkImageView* view,
     64                          GrMipMapsStatus mipMapsStatus,
     65                          GrBackendObjectOwnership ownership)
     66     : GrSurface(gpu, desc)
     67     , GrVkImage(info, ownership)
     68     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
     69                 mipMapsStatus)
     70     , fTextureView(view)
     71     , fLinearTextureView(nullptr) {
     72     SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
     73 }
     74 
     75 sk_sp<GrVkTexture> GrVkTexture::CreateNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
     76                                                  const GrSurfaceDesc& desc,
     77                                                  const GrVkImage::ImageDesc& imageDesc,
     78                                                  GrMipMapsStatus mipMapsStatus) {
     79     SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
     80 
     81     GrVkImageInfo info;
     82     if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
     83         return nullptr;
     84     }
     85 
     86     const GrVkImageView* imageView = GrVkImageView::Create(gpu, info.fImage, info.fFormat,
     87                                                            GrVkImageView::kColor_Type,
     88                                                            info.fLevelCount);
     89     if (!imageView) {
     90         GrVkImage::DestroyImageInfo(gpu, &info);
     91         return nullptr;
     92     }
     93 
     94     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, desc, info, imageView,
     95                                               mipMapsStatus));
     96 }
     97 
     98 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
     99                                                    const GrSurfaceDesc& desc,
    100                                                    GrWrapOwnership wrapOwnership,
    101                                                    const GrVkImageInfo* info) {
    102     SkASSERT(info);
    103     // Wrapped textures require both image and allocation (because they can be mapped)
    104     SkASSERT(VK_NULL_HANDLE != info->fImage && VK_NULL_HANDLE != info->fAlloc.fMemory);
    105 
    106     const GrVkImageView* imageView = GrVkImageView::Create(gpu, info->fImage, info->fFormat,
    107                                                            GrVkImageView::kColor_Type,
    108                                                            info->fLevelCount);
    109     if (!imageView) {
    110         return nullptr;
    111     }
    112 
    113     GrMipMapsStatus mipMapsStatus = info->fLevelCount > 1 ? GrMipMapsStatus::kValid
    114                                                           : GrMipMapsStatus::kNotAllocated;
    115 
    116     GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
    117             ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
    118     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, kWrapped, desc, *info, imageView,
    119                                               mipMapsStatus, ownership));
    120 }
    121 
    122 GrVkTexture::~GrVkTexture() {
    123     // either release or abandon should have been called by the owner of this object.
    124     SkASSERT(!fTextureView);
    125     SkASSERT(!fLinearTextureView);
    126 }
    127 
    128 void GrVkTexture::onRelease() {
    129     // we create this and don't hand it off, so we should always destroy it
    130     if (fTextureView) {
    131         fTextureView->unref(this->getVkGpu());
    132         fTextureView = nullptr;
    133     }
    134 
    135     if (fLinearTextureView) {
    136         fLinearTextureView->unref(this->getVkGpu());
    137         fLinearTextureView = nullptr;
    138     }
    139 
    140     this->releaseImage(this->getVkGpu());
    141 
    142     INHERITED::onRelease();
    143 }
    144 
    145 void GrVkTexture::onAbandon() {
    146     if (fTextureView) {
    147         fTextureView->unrefAndAbandon();
    148         fTextureView = nullptr;
    149     }
    150 
    151     if (fLinearTextureView) {
    152         fLinearTextureView->unrefAndAbandon();
    153         fLinearTextureView = nullptr;
    154     }
    155 
    156     this->abandonImage();
    157     INHERITED::onAbandon();
    158 }
    159 
    160 GrBackendObject GrVkTexture::getTextureHandle() const {
    161     return (GrBackendObject)&fInfo;
    162 }
    163 
    164 GrBackendTexture GrVkTexture::getBackendTexture() const {
    165     return GrBackendTexture(this->width(), this->height(), fInfo);
    166 }
    167 
    168 GrVkGpu* GrVkTexture::getVkGpu() const {
    169     SkASSERT(!this->wasDestroyed());
    170     return static_cast<GrVkGpu*>(this->getGpu());
    171 }
    172 
    173 const GrVkImageView* GrVkTexture::textureView(bool allowSRGB) {
    174     VkFormat linearFormat;
    175     if (allowSRGB || !GrVkFormatIsSRGB(fInfo.fFormat, &linearFormat)) {
    176         return fTextureView;
    177     }
    178 
    179     if (!fLinearTextureView) {
    180         fLinearTextureView = GrVkImageView::Create(this->getVkGpu(), fInfo.fImage,
    181                                                    linearFormat, GrVkImageView::kColor_Type,
    182                                                    fInfo.fLevelCount);
    183         SkASSERT(fLinearTextureView);
    184     }
    185 
    186     return fLinearTextureView;
    187 }
    188 
    189 bool GrVkTexture::reallocForMipmap(GrVkGpu* gpu, uint32_t mipLevels) {
    190     if (mipLevels == 1) {
    191         // don't need to do anything for a 1x1 texture
    192         return false;
    193     }
    194 
    195     const GrVkResource* oldResource = this->resource();
    196 
    197     // We shouldn't realloc something that doesn't belong to us
    198     if (fIsBorrowed) {
    199         return false;
    200     }
    201 
    202     bool renderTarget = SkToBool(this->asRenderTarget());
    203 
    204     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
    205     if (renderTarget) {
    206         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    207     }
    208     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    209 
    210     GrVkImage::ImageDesc imageDesc;
    211     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
    212     imageDesc.fFormat = fInfo.fFormat;
    213     imageDesc.fWidth = this->width();
    214     imageDesc.fHeight = this->height();
    215     imageDesc.fLevels = mipLevels;
    216     imageDesc.fSamples = 1;
    217     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
    218     imageDesc.fUsageFlags = usageFlags;
    219     imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    220 
    221     GrVkImageInfo info;
    222     if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
    223         return false;
    224     }
    225 
    226     // have to create a new image view for new resource
    227     const GrVkImageView* oldView = fTextureView;
    228     VkImage image = info.fImage;
    229     const GrVkImageView* textureView = GrVkImageView::Create(gpu, image, info.fFormat,
    230                                                              GrVkImageView::kColor_Type, mipLevels);
    231     if (!textureView) {
    232         GrVkImage::DestroyImageInfo(gpu, &info);
    233         return false;
    234     }
    235 
    236     if (renderTarget) {
    237         GrVkTextureRenderTarget* texRT = static_cast<GrVkTextureRenderTarget*>(this);
    238         if (!texRT->updateForMipmap(gpu, info)) {
    239             GrVkImage::DestroyImageInfo(gpu, &info);
    240             return false;
    241         }
    242     }
    243 
    244     oldResource->unref(gpu);
    245     oldView->unref(gpu);
    246     if (fLinearTextureView) {
    247         fLinearTextureView->unref(gpu);
    248         fLinearTextureView = nullptr;
    249     }
    250 
    251     this->setNewResource(info.fImage, info.fAlloc, info.fImageTiling);
    252     fTextureView = textureView;
    253     fInfo = info;
    254     // SetMaxMipMapLevel stores the max level not the number of levels
    255     this->texturePriv().setMaxMipMapLevel(mipLevels-1);
    256 
    257     return true;
    258 }
    259