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 "GrVkCaps.h"
      9 #include "GrBackendSurface.h"
     10 #include "GrRenderTargetProxy.h"
     11 #include "GrRenderTarget.h"
     12 #include "GrShaderCaps.h"
     13 #include "GrVkUtil.h"
     14 #include "vk/GrVkBackendContext.h"
     15 #include "vk/GrVkInterface.h"
     16 
     17 GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
     18                    VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags)
     19     : INHERITED(contextOptions) {
     20     fCanUseGLSLForShaderModule = false;
     21     fMustDoCopiesFromOrigin = false;
     22     fSupportsCopiesAsDraws = true;
     23     fMustSubmitCommandsBeforeCopyOp = false;
     24     fMustSleepOnTearDown  = false;
     25     fNewCBOnPipelineChange = false;
     26     fCanUseWholeSizeOnFlushMappedMemory = true;
     27 
     28     /**************************************************************************
     29     * GrDrawTargetCaps fields
     30     **************************************************************************/
     31     fMipMapSupport = true;   // always available in Vulkan
     32     fSRGBSupport = true;   // always available in Vulkan
     33     fSRGBDecodeDisableSupport = true;  // always available in Vulkan
     34     fNPOTTextureTileSupport = true;  // always available in Vulkan
     35     fDiscardRenderTargetSupport = true;
     36     fReuseScratchTextures = true; //TODO: figure this out
     37     fGpuTracingSupport = false; //TODO: figure this out
     38     fOversizedStencilSupport = false; //TODO: figure this out
     39     fInstanceAttribSupport = true;
     40 
     41     fBlacklistCoverageCounting = true; // blacklisting ccpr until we work through a few issues.
     42     fFenceSyncSupport = true;   // always available in Vulkan
     43     fCrossContextTextureSupport = true;
     44 
     45     fMapBufferFlags = kNone_MapFlags; //TODO: figure this out
     46     fBufferMapThreshold = SK_MaxS32;  //TODO: figure this out
     47 
     48     fMaxRenderTargetSize = 4096; // minimum required by spec
     49     fMaxTextureSize = 4096; // minimum required by spec
     50 
     51     fShaderCaps.reset(new GrShaderCaps(contextOptions));
     52 
     53     this->init(contextOptions, vkInterface, physDev, featureFlags, extensionFlags);
     54 }
     55 
     56 bool GrVkCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
     57                                   bool* rectsMustMatch, bool* disallowSubrect) const {
     58     // Vk doesn't use rectsMustMatch or disallowSubrect. Always return false.
     59     *rectsMustMatch = false;
     60     *disallowSubrect = false;
     61 
     62     // We can always succeed here with either a CopyImage (none msaa src) or ResolveImage (msaa).
     63     // For CopyImage we can make a simple texture, for ResolveImage we require the dst to be a
     64     // render target as well.
     65     desc->fOrigin = src->origin();
     66     desc->fConfig = src->config();
     67     if (src->numColorSamples() > 1 || (src->asTextureProxy() && this->supportsCopiesAsDraws())) {
     68         desc->fFlags = kRenderTarget_GrSurfaceFlag;
     69     } else {
     70         // Just going to use CopyImage here
     71         desc->fFlags = kNone_GrSurfaceFlags;
     72     }
     73 
     74     return true;
     75 }
     76 
     77 void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
     78                     VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) {
     79 
     80     VkPhysicalDeviceProperties properties;
     81     GR_VK_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &properties));
     82 
     83     VkPhysicalDeviceMemoryProperties memoryProperties;
     84     GR_VK_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &memoryProperties));
     85 
     86     this->initGrCaps(properties, memoryProperties, featureFlags);
     87     this->initShaderCaps(properties, featureFlags);
     88 
     89     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
     90 #if defined(SK_CPU_X86)
     91         // We need to do this before initing the config table since it uses fSRGBSupport
     92         if (kImagination_VkVendor == properties.vendorID) {
     93             fSRGBSupport = false;
     94         }
     95 #endif
     96     }
     97 
     98     this->initConfigTable(vkInterface, physDev, properties);
     99     this->initStencilFormat(vkInterface, physDev);
    100 
    101     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
    102         this->applyDriverCorrectnessWorkarounds(properties);
    103     }
    104 
    105     this->applyOptionsOverrides(contextOptions);
    106     fShaderCaps->applyOptionsOverrides(contextOptions);
    107 }
    108 
    109 void GrVkCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
    110     if (kQualcomm_VkVendor == properties.vendorID) {
    111         fMustDoCopiesFromOrigin = true;
    112     }
    113 
    114     if (kNvidia_VkVendor == properties.vendorID) {
    115         fMustSubmitCommandsBeforeCopyOp = true;
    116     }
    117 
    118     if (kQualcomm_VkVendor == properties.vendorID ||
    119         kARM_VkVendor == properties.vendorID) {
    120         fSupportsCopiesAsDraws = false;
    121         // We require copies as draws to support cross context textures.
    122         fCrossContextTextureSupport = false;
    123     }
    124 
    125 #if defined(SK_BUILD_FOR_WIN)
    126     if (kNvidia_VkVendor == properties.vendorID) {
    127         fMustSleepOnTearDown = true;
    128     }
    129 #elif defined(SK_BUILD_FOR_ANDROID)
    130     if (kImagination_VkVendor == properties.vendorID) {
    131         fMustSleepOnTearDown = true;
    132     }
    133 #endif
    134 
    135     // AMD seems to have issues binding new VkPipelines inside a secondary command buffer.
    136     // Current workaround is to use a different secondary command buffer for each new VkPipeline.
    137     if (kAMD_VkVendor == properties.vendorID) {
    138         fNewCBOnPipelineChange = true;
    139     }
    140 
    141     ////////////////////////////////////////////////////////////////////////////
    142     // GrCaps workarounds
    143     ////////////////////////////////////////////////////////////////////////////
    144 
    145     if (kARM_VkVendor == properties.vendorID) {
    146         fInstanceAttribSupport = false;
    147     }
    148 
    149     // AMD advertises support for MAX_UINT vertex input attributes, but in reality only supports 32.
    150     if (kAMD_VkVendor == properties.vendorID) {
    151         fMaxVertexAttributes = SkTMin(fMaxVertexAttributes, 32);
    152     }
    153 
    154     if (kIntel_VkVendor == properties.vendorID) {
    155         fCanUseWholeSizeOnFlushMappedMemory = false;
    156     }
    157 
    158     ////////////////////////////////////////////////////////////////////////////
    159     // GrShaderCaps workarounds
    160     ////////////////////////////////////////////////////////////////////////////
    161 
    162     if (kImagination_VkVendor == properties.vendorID) {
    163         fShaderCaps->fAtan2ImplementedAsAtanYOverX = true;
    164     }
    165 
    166 }
    167 
    168 int get_max_sample_count(VkSampleCountFlags flags) {
    169     SkASSERT(flags & VK_SAMPLE_COUNT_1_BIT);
    170     if (!(flags & VK_SAMPLE_COUNT_2_BIT)) {
    171         return 0;
    172     }
    173     if (!(flags & VK_SAMPLE_COUNT_4_BIT)) {
    174         return 2;
    175     }
    176     if (!(flags & VK_SAMPLE_COUNT_8_BIT)) {
    177         return 4;
    178     }
    179     if (!(flags & VK_SAMPLE_COUNT_16_BIT)) {
    180         return 8;
    181     }
    182     if (!(flags & VK_SAMPLE_COUNT_32_BIT)) {
    183         return 16;
    184     }
    185     if (!(flags & VK_SAMPLE_COUNT_64_BIT)) {
    186         return 32;
    187     }
    188     return 64;
    189 }
    190 
    191 void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties,
    192                           const VkPhysicalDeviceMemoryProperties& memoryProperties,
    193                           uint32_t featureFlags) {
    194     // So GPUs, like AMD, are reporting MAX_INT support vertex attributes. In general, there is no
    195     // need for us ever to support that amount, and it makes tests which tests all the vertex
    196     // attribs timeout looping over that many. For now, we'll cap this at 64 max and can raise it if
    197     // we ever find that need.
    198     static const uint32_t kMaxVertexAttributes = 64;
    199     fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes);
    200 
    201     // We could actually query and get a max size for each config, however maxImageDimension2D will
    202     // give the minimum max size across all configs. So for simplicity we will use that for now.
    203     fMaxRenderTargetSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
    204     fMaxTextureSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
    205 
    206     // TODO: check if RT's larger than 4k incur a performance cost on ARM.
    207     fMaxPreferredRenderTargetSize = fMaxRenderTargetSize;
    208 
    209     // Assuming since we will always map in the end to upload the data we might as well just map
    210     // from the get go. There is no hard data to suggest this is faster or slower.
    211     fBufferMapThreshold = 0;
    212 
    213     fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag;
    214 
    215     fOversizedStencilSupport = true;
    216     fSampleShadingSupport = SkToBool(featureFlags & kSampleRateShading_GrVkFeatureFlag);
    217 
    218 
    219 }
    220 
    221 void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint32_t featureFlags) {
    222     GrShaderCaps* shaderCaps = fShaderCaps.get();
    223     shaderCaps->fVersionDeclString = "#version 330\n";
    224 
    225 
    226     // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
    227     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
    228         GrPixelConfig config = static_cast<GrPixelConfig>(i);
    229         // Vulkan doesn't support a single channel format stored in alpha.
    230         if (GrPixelConfigIsAlphaOnly(config) &&
    231             kAlpha_8_as_Alpha_GrPixelConfig != config) {
    232             shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
    233             shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
    234         } else {
    235             if (kGray_8_GrPixelConfig == config ||
    236                 kGray_8_as_Red_GrPixelConfig == config) {
    237                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
    238             } else if (kRGBA_4444_GrPixelConfig == config) {
    239                 // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we
    240                 // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads
    241                 // or writing to outputs. Since we're not actually changing the data at all, the
    242                 // only extra work is the swizzle in the shader for all operations.
    243                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA();
    244                 shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA();
    245             } else {
    246                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
    247             }
    248         }
    249     }
    250 
    251     // Vulkan is based off ES 3.0 so the following should all be supported
    252     shaderCaps->fUsesPrecisionModifiers = true;
    253     shaderCaps->fFlatInterpolationSupport = true;
    254     // Flat interpolation appears to be slow on Qualcomm GPUs. This was tested in GL and is assumed
    255     // to be true with Vulkan as well.
    256     shaderCaps->fPreferFlatInterpolation = kQualcomm_VkVendor != properties.vendorID;
    257 
    258     // GrShaderCaps
    259 
    260     shaderCaps->fShaderDerivativeSupport = true;
    261 
    262     shaderCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);
    263     shaderCaps->fGSInvocationsSupport = shaderCaps->fGeometryShaderSupport;
    264 
    265     shaderCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);
    266 
    267     shaderCaps->fIntegerSupport = true;
    268     shaderCaps->fTexelBufferSupport = true;
    269     shaderCaps->fTexelFetchSupport = true;
    270     shaderCaps->fVertexIDSupport = true;
    271 
    272     // Assume the minimum precisions mandated by the SPIR-V spec.
    273     shaderCaps->fFloatIs32Bits = true;
    274     shaderCaps->fHalfIs32Bits = false;
    275 
    276     shaderCaps->fMaxVertexSamplers =
    277     shaderCaps->fMaxGeometrySamplers =
    278     shaderCaps->fMaxFragmentSamplers = SkTMin(
    279                                        SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
    280                                               properties.limits.maxPerStageDescriptorSamplers),
    281                                               (uint32_t)INT_MAX);
    282     shaderCaps->fMaxCombinedSamplers = SkTMin(
    283                                        SkTMin(properties.limits.maxDescriptorSetSampledImages,
    284                                               properties.limits.maxDescriptorSetSamplers),
    285                                               (uint32_t)INT_MAX);
    286 }
    287 
    288 bool stencil_format_supported(const GrVkInterface* interface,
    289                               VkPhysicalDevice physDev,
    290                               VkFormat format) {
    291     VkFormatProperties props;
    292     memset(&props, 0, sizeof(VkFormatProperties));
    293     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
    294     return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & props.optimalTilingFeatures);
    295 }
    296 
    297 void GrVkCaps::initStencilFormat(const GrVkInterface* interface, VkPhysicalDevice physDev) {
    298     // List of legal stencil formats (though perhaps not supported on
    299     // the particular gpu/driver) from most preferred to least. We are guaranteed to have either
    300     // VK_FORMAT_D24_UNORM_S8_UINT or VK_FORMAT_D32_SFLOAT_S8_UINT. VK_FORMAT_D32_SFLOAT_S8_UINT
    301     // can optionally have 24 unused bits at the end so we assume the total bits is 64.
    302     static const StencilFormat
    303                   // internal Format             stencil bits      total bits        packed?
    304         gS8    = { VK_FORMAT_S8_UINT,            8,                 8,               false },
    305         gD24S8 = { VK_FORMAT_D24_UNORM_S8_UINT,  8,                32,               true },
    306         gD32S8 = { VK_FORMAT_D32_SFLOAT_S8_UINT, 8,                64,               true };
    307 
    308     if (stencil_format_supported(interface, physDev, VK_FORMAT_S8_UINT)) {
    309         fPreferedStencilFormat = gS8;
    310     } else if (stencil_format_supported(interface, physDev, VK_FORMAT_D24_UNORM_S8_UINT)) {
    311         fPreferedStencilFormat = gD24S8;
    312     } else {
    313         SkASSERT(stencil_format_supported(interface, physDev, VK_FORMAT_D32_SFLOAT_S8_UINT));
    314         fPreferedStencilFormat = gD32S8;
    315     }
    316 }
    317 
    318 void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice physDev,
    319                                const VkPhysicalDeviceProperties& properties) {
    320     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
    321         VkFormat format;
    322         if (GrPixelConfigToVkFormat(static_cast<GrPixelConfig>(i), &format)) {
    323             if (!GrPixelConfigIsSRGB(static_cast<GrPixelConfig>(i)) || fSRGBSupport) {
    324                 fConfigTable[i].init(interface, physDev, properties, format);
    325             }
    326         }
    327     }
    328 }
    329 
    330 void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) {
    331     if (SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & vkFlags) &&
    332         SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & vkFlags)) {
    333         *flags = *flags | kTextureable_Flag;
    334 
    335         // Ganesh assumes that all renderable surfaces are also texturable
    336         if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags)) {
    337             *flags = *flags | kRenderable_Flag;
    338         }
    339     }
    340 
    341     if (SkToBool(VK_FORMAT_FEATURE_BLIT_SRC_BIT & vkFlags)) {
    342         *flags = *flags | kBlitSrc_Flag;
    343     }
    344 
    345     if (SkToBool(VK_FORMAT_FEATURE_BLIT_DST_BIT & vkFlags)) {
    346         *flags = *flags | kBlitDst_Flag;
    347     }
    348 }
    349 
    350 void GrVkCaps::ConfigInfo::initSampleCounts(const GrVkInterface* interface,
    351                                             VkPhysicalDevice physDev,
    352                                             const VkPhysicalDeviceProperties& physProps,
    353                                             VkFormat format) {
    354     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
    355                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
    356                               VK_IMAGE_USAGE_SAMPLED_BIT |
    357                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    358     VkImageCreateFlags createFlags = GrVkFormatIsSRGB(format, nullptr)
    359         ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0;
    360     VkImageFormatProperties properties;
    361     GR_VK_CALL(interface, GetPhysicalDeviceImageFormatProperties(physDev,
    362                                                                  format,
    363                                                                  VK_IMAGE_TYPE_2D,
    364                                                                  VK_IMAGE_TILING_OPTIMAL,
    365                                                                  usage,
    366                                                                  createFlags,
    367                                                                  &properties));
    368     VkSampleCountFlags flags = properties.sampleCounts;
    369     if (flags & VK_SAMPLE_COUNT_1_BIT) {
    370         fColorSampleCounts.push(1);
    371     }
    372     if (kImagination_VkVendor == physProps.vendorID) {
    373         // MSAA does not work on imagination
    374         return;
    375     }
    376     if (flags & VK_SAMPLE_COUNT_2_BIT) {
    377         fColorSampleCounts.push(2);
    378     }
    379     if (flags & VK_SAMPLE_COUNT_4_BIT) {
    380         fColorSampleCounts.push(4);
    381     }
    382     if (flags & VK_SAMPLE_COUNT_8_BIT) {
    383         fColorSampleCounts.push(8);
    384     }
    385     if (flags & VK_SAMPLE_COUNT_16_BIT) {
    386         fColorSampleCounts.push(16);
    387     }
    388     if (flags & VK_SAMPLE_COUNT_32_BIT) {
    389         fColorSampleCounts.push(32);
    390     }
    391     if (flags & VK_SAMPLE_COUNT_64_BIT) {
    392         fColorSampleCounts.push(64);
    393     }
    394 }
    395 
    396 void GrVkCaps::ConfigInfo::init(const GrVkInterface* interface,
    397                                 VkPhysicalDevice physDev,
    398                                 const VkPhysicalDeviceProperties& properties,
    399                                 VkFormat format) {
    400     VkFormatProperties props;
    401     memset(&props, 0, sizeof(VkFormatProperties));
    402     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
    403     InitConfigFlags(props.linearTilingFeatures, &fLinearFlags);
    404     InitConfigFlags(props.optimalTilingFeatures, &fOptimalFlags);
    405     if (fOptimalFlags & kRenderable_Flag) {
    406         this->initSampleCounts(interface, physDev, properties, format);
    407     }
    408 }
    409 
    410 int GrVkCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
    411     requestedCount = SkTMax(1, requestedCount);
    412     int count = fConfigTable[config].fColorSampleCounts.count();
    413 
    414     if (!count) {
    415         return 0;
    416     }
    417 
    418     if (1 == requestedCount) {
    419         SkASSERT(fConfigTable[config].fColorSampleCounts.count() &&
    420                  fConfigTable[config].fColorSampleCounts[0] == 1);
    421         return 1;
    422     }
    423 
    424     for (int i = 0; i < count; ++i) {
    425         if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) {
    426             return fConfigTable[config].fColorSampleCounts[i];
    427         }
    428     }
    429     return 0;
    430 }
    431 
    432 int GrVkCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
    433     const auto& table = fConfigTable[config].fColorSampleCounts;
    434     if (!table.count()) {
    435         return 0;
    436     }
    437     return table[table.count() - 1];
    438 }
    439 
    440 bool GrVkCaps::surfaceSupportsWritePixels(const GrSurface* surface) const {
    441     if (auto rt = surface->asRenderTarget()) {
    442         return rt->numColorSamples() <= 1 && SkToBool(surface->asTexture());
    443     }
    444     return true;
    445 }
    446 
    447 bool validate_image_info(VkFormat format, SkColorType ct, GrPixelConfig* config) {
    448     *config = kUnknown_GrPixelConfig;
    449 
    450     switch (ct) {
    451         case kUnknown_SkColorType:
    452             return false;
    453         case kAlpha_8_SkColorType:
    454             if (VK_FORMAT_R8_UNORM == format) {
    455                 *config = kAlpha_8_as_Red_GrPixelConfig;
    456             }
    457             break;
    458         case kRGB_565_SkColorType:
    459             if (VK_FORMAT_R5G6B5_UNORM_PACK16 == format) {
    460                 *config = kRGB_565_GrPixelConfig;
    461             }
    462             break;
    463         case kARGB_4444_SkColorType:
    464             if (VK_FORMAT_B4G4R4A4_UNORM_PACK16 == format) {
    465                 *config = kRGBA_4444_GrPixelConfig;
    466             }
    467             break;
    468         case kRGBA_8888_SkColorType:
    469             if (VK_FORMAT_R8G8B8A8_UNORM == format) {
    470                 *config = kRGBA_8888_GrPixelConfig;
    471             } else if (VK_FORMAT_R8G8B8A8_SRGB == format) {
    472                 *config = kSRGBA_8888_GrPixelConfig;
    473             }
    474             break;
    475         case kRGB_888x_SkColorType:
    476             return false;
    477         case kBGRA_8888_SkColorType:
    478             if (VK_FORMAT_B8G8R8A8_UNORM == format) {
    479                 *config = kBGRA_8888_GrPixelConfig;
    480             } else if (VK_FORMAT_B8G8R8A8_SRGB == format) {
    481                 *config = kSBGRA_8888_GrPixelConfig;
    482             }
    483             break;
    484         case kRGBA_1010102_SkColorType:
    485             if (VK_FORMAT_A2B10G10R10_UNORM_PACK32 == format) {
    486                 *config = kRGBA_1010102_GrPixelConfig;
    487             }
    488             break;
    489         case kRGB_101010x_SkColorType:
    490             return false;
    491         case kGray_8_SkColorType:
    492             if (VK_FORMAT_R8_UNORM == format) {
    493                 *config = kGray_8_as_Red_GrPixelConfig;
    494             }
    495             break;
    496         case kRGBA_F16_SkColorType:
    497             if (VK_FORMAT_R16G16B16A16_SFLOAT == format) {
    498                 *config = kRGBA_half_GrPixelConfig;
    499             }
    500             break;
    501     }
    502 
    503     return kUnknown_GrPixelConfig != *config;
    504 }
    505 
    506 bool GrVkCaps::validateBackendTexture(const GrBackendTexture& tex, SkColorType ct,
    507                                       GrPixelConfig* config) const {
    508     const GrVkImageInfo* imageInfo = tex.getVkImageInfo();
    509     if (!imageInfo) {
    510         return false;
    511     }
    512 
    513     return validate_image_info(imageInfo->fFormat, ct, config);
    514 }
    515 
    516 bool GrVkCaps::validateBackendRenderTarget(const GrBackendRenderTarget& rt, SkColorType ct,
    517                                            GrPixelConfig* config) const {
    518     const GrVkImageInfo* imageInfo = rt.getVkImageInfo();
    519     if (!imageInfo) {
    520         return false;
    521     }
    522 
    523     return validate_image_info(imageInfo->fFormat, ct, config);
    524 }
    525 
    526 bool GrVkCaps::getConfigFromBackendFormat(const GrBackendFormat& format, SkColorType ct,
    527                                           GrPixelConfig* config) const {
    528     const VkFormat* vkFormat = format.getVkFormat();
    529     if (!vkFormat) {
    530         return false;
    531     }
    532     return validate_image_info(*vkFormat, ct, config);
    533 }
    534 
    535