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