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 "GrRenderTargetProxy.h"
     10 #include "GrShaderCaps.h"
     11 #include "GrVkUtil.h"
     12 #include "vk/GrVkBackendContext.h"
     13 #include "vk/GrVkInterface.h"
     14 
     15 GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
     16                    VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags)
     17     : INHERITED(contextOptions) {
     18     fCanUseGLSLForShaderModule = false;
     19     fMustDoCopiesFromOrigin = false;
     20     fSupportsCopiesAsDraws = false;
     21     fMustSubmitCommandsBeforeCopyOp = false;
     22     fMustSleepOnTearDown  = false;
     23     fNewCBOnPipelineChange = false;
     24 
     25     /**************************************************************************
     26     * GrDrawTargetCaps fields
     27     **************************************************************************/
     28     fMipMapSupport = true;   // always available in Vulkan
     29     fSRGBSupport = true;   // always available in Vulkan
     30     fNPOTTextureTileSupport = true;  // always available in Vulkan
     31     fDiscardRenderTargetSupport = true;
     32     fReuseScratchTextures = true; //TODO: figure this out
     33     fGpuTracingSupport = false; //TODO: figure this out
     34     fOversizedStencilSupport = false; //TODO: figure this out
     35     fInstanceAttribSupport = true;
     36 
     37     fUseDrawInsteadOfClear = false;
     38     fFenceSyncSupport = true;   // always available in Vulkan
     39     fCrossContextTextureSupport = false;
     40 
     41     fMapBufferFlags = kNone_MapFlags; //TODO: figure this out
     42     fBufferMapThreshold = SK_MaxS32;  //TODO: figure this out
     43 
     44     fMaxRenderTargetSize = 4096; // minimum required by spec
     45     fMaxTextureSize = 4096; // minimum required by spec
     46     fMaxColorSampleCount = 4; // minimum required by spec
     47     fMaxStencilSampleCount = 4; // minimum required by spec
     48 
     49     fShaderCaps.reset(new GrShaderCaps(contextOptions));
     50 
     51     this->init(contextOptions, vkInterface, physDev, featureFlags, extensionFlags);
     52 }
     53 
     54 bool GrVkCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
     55                                   bool* rectsMustMatch, bool* disallowSubrect) const {
     56     // Vk doesn't use rectsMustMatch or disallowSubrect. Always return false.
     57     *rectsMustMatch = false;
     58     *disallowSubrect = false;
     59 
     60     // We can always succeed here with either a CopyImage (none msaa src) or ResolveImage (msaa).
     61     // For CopyImage we can make a simple texture, for ResolveImage we require the dst to be a
     62     // render target as well.
     63     desc->fOrigin = src->origin();
     64     desc->fConfig = src->config();
     65     if (src->numColorSamples() > 1 || (src->asTextureProxy() && this->supportsCopiesAsDraws())) {
     66         desc->fFlags = kRenderTarget_GrSurfaceFlag;
     67     } else {
     68         // Just going to use CopyImage here
     69         desc->fFlags = kNone_GrSurfaceFlags;
     70     }
     71 
     72     return true;
     73 }
     74 
     75 void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
     76                     VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) {
     77 
     78     VkPhysicalDeviceProperties properties;
     79     GR_VK_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &properties));
     80 
     81     VkPhysicalDeviceMemoryProperties memoryProperties;
     82     GR_VK_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &memoryProperties));
     83 
     84     this->initGrCaps(properties, memoryProperties, featureFlags);
     85     this->initShaderCaps(properties, featureFlags);
     86     this->initConfigTable(vkInterface, physDev);
     87     this->initStencilFormat(vkInterface, physDev);
     88 
     89     if (SkToBool(extensionFlags & kNV_glsl_shader_GrVkExtensionFlag)) {
     90         // Currently disabling this feature since it does not play well with validation layers which
     91         // expect a SPIR-V shader
     92         // fCanUseGLSLForShaderModule = true;
     93     }
     94 
     95     if (kQualcomm_VkVendor == properties.vendorID) {
     96         fMustDoCopiesFromOrigin = true;
     97     }
     98 
     99     if (kNvidia_VkVendor == properties.vendorID) {
    100         fMustSubmitCommandsBeforeCopyOp = true;
    101     }
    102 
    103     if (kQualcomm_VkVendor != properties.vendorID) {
    104         fSupportsCopiesAsDraws = true;
    105     }
    106 
    107     if (fSupportsCopiesAsDraws) {
    108         fCrossContextTextureSupport = true;
    109     }
    110 
    111 #if defined(SK_BUILD_FOR_WIN)
    112     if (kNvidia_VkVendor == properties.vendorID) {
    113         fMustSleepOnTearDown = true;
    114     }
    115 #elif defined(SK_BUILD_FOR_ANDROID)
    116     if (kImagination_VkVendor == properties.vendorID) {
    117         fMustSleepOnTearDown = true;
    118     }
    119 #endif
    120 
    121     this->applyOptionsOverrides(contextOptions);
    122     fShaderCaps->applyOptionsOverrides(contextOptions);
    123 }
    124 
    125 int get_max_sample_count(VkSampleCountFlags flags) {
    126     SkASSERT(flags & VK_SAMPLE_COUNT_1_BIT);
    127     if (!(flags & VK_SAMPLE_COUNT_2_BIT)) {
    128         return 0;
    129     }
    130     if (!(flags & VK_SAMPLE_COUNT_4_BIT)) {
    131         return 2;
    132     }
    133     if (!(flags & VK_SAMPLE_COUNT_8_BIT)) {
    134         return 4;
    135     }
    136     if (!(flags & VK_SAMPLE_COUNT_16_BIT)) {
    137         return 8;
    138     }
    139     if (!(flags & VK_SAMPLE_COUNT_32_BIT)) {
    140         return 16;
    141     }
    142     if (!(flags & VK_SAMPLE_COUNT_64_BIT)) {
    143         return 32;
    144     }
    145     return 64;
    146 }
    147 
    148 void GrVkCaps::initSampleCount(const VkPhysicalDeviceProperties& properties) {
    149     VkSampleCountFlags colorSamples = properties.limits.framebufferColorSampleCounts;
    150     VkSampleCountFlags stencilSamples = properties.limits.framebufferStencilSampleCounts;
    151 
    152     fMaxColorSampleCount = get_max_sample_count(colorSamples);
    153     if (kImagination_VkVendor == properties.vendorID) {
    154         fMaxColorSampleCount = 0;
    155     }
    156     fMaxStencilSampleCount = get_max_sample_count(stencilSamples);
    157 }
    158 
    159 void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties,
    160                           const VkPhysicalDeviceMemoryProperties& memoryProperties,
    161                           uint32_t featureFlags) {
    162     // So GPUs, like AMD, are reporting MAX_INT support vertex attributes. In general, there is no
    163     // need for us ever to support that amount, and it makes tests which tests all the vertex
    164     // attribs timeout looping over that many. For now, we'll cap this at 64 max and can raise it if
    165     // we ever find that need.
    166     static const uint32_t kMaxVertexAttributes = 64;
    167     fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes);
    168     // AMD advertises support for MAX_UINT vertex input attributes, but in reality only supports 32.
    169     if (kAMD_VkVendor == properties.vendorID) {
    170         fMaxVertexAttributes = SkTMin(fMaxVertexAttributes, 32);
    171     }
    172 
    173     // We could actually query and get a max size for each config, however maxImageDimension2D will
    174     // give the minimum max size across all configs. So for simplicity we will use that for now.
    175     fMaxRenderTargetSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
    176     fMaxTextureSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
    177 
    178     this->initSampleCount(properties);
    179 
    180     // Assuming since we will always map in the end to upload the data we might as well just map
    181     // from the get go. There is no hard data to suggest this is faster or slower.
    182     fBufferMapThreshold = 0;
    183 
    184     fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag;
    185 
    186     fOversizedStencilSupport = true;
    187     fSampleShadingSupport = SkToBool(featureFlags & kSampleRateShading_GrVkFeatureFlag);
    188 
    189     // AMD seems to have issues binding new VkPipelines inside a secondary command buffer.
    190     // Current workaround is to use a different secondary command buffer for each new VkPipeline.
    191     if (kAMD_VkVendor == properties.vendorID) {
    192         fNewCBOnPipelineChange = true;
    193     }
    194 
    195 #if defined(SK_CPU_X86)
    196     if (kImagination_VkVendor == properties.vendorID) {
    197         fSRGBSupport = false;
    198     }
    199 #endif
    200 }
    201 
    202 void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint32_t featureFlags) {
    203     GrShaderCaps* shaderCaps = fShaderCaps.get();
    204     shaderCaps->fVersionDeclString = "#version 330\n";
    205 
    206 
    207     // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
    208     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
    209         GrPixelConfig config = static_cast<GrPixelConfig>(i);
    210         if (GrPixelConfigIsAlphaOnly(config)) {
    211             shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
    212             shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
    213         } else {
    214             if (kGray_8_GrPixelConfig == config) {
    215                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
    216             } else if (kRGBA_4444_GrPixelConfig == config) {
    217                 // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we
    218                 // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads
    219                 // or writing to outputs. Since we're not actually changing the data at all, the
    220                 // only extra work is the swizzle in the shader for all operations.
    221                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA();
    222                 shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA();
    223             } else {
    224                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
    225             }
    226         }
    227     }
    228 
    229     if (kImagination_VkVendor == properties.vendorID) {
    230         shaderCaps->fAtan2ImplementedAsAtanYOverX = true;
    231     }
    232 
    233     // Vulkan is based off ES 3.0 so the following should all be supported
    234     shaderCaps->fUsesPrecisionModifiers = true;
    235     shaderCaps->fFlatInterpolationSupport = true;
    236 
    237     // GrShaderCaps
    238 
    239     shaderCaps->fShaderDerivativeSupport = true;
    240     shaderCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);
    241 
    242     shaderCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);
    243     if (kAMD_VkVendor == properties.vendorID) {
    244         // Currently DualSourceBlending is not working on AMD. vkCreateGraphicsPipeline fails when
    245         // using a draw with dual source. Looking into whether it is driver bug or issue with our
    246         // SPIR-V. Bug skia:6405
    247         shaderCaps->fDualSourceBlendingSupport = false;
    248     }
    249 
    250     shaderCaps->fIntegerSupport = true;
    251     shaderCaps->fTexelBufferSupport = true;
    252     shaderCaps->fTexelFetchSupport = true;
    253     shaderCaps->fVertexIDSupport = true;
    254 
    255     // Assume the minimum precisions mandated by the SPIR-V spec.
    256     shaderCaps->fShaderPrecisionVaries = true;
    257     for (int s = 0; s < kGrShaderTypeCount; ++s) {
    258         auto& highp = shaderCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
    259         highp.fLogRangeLow = highp.fLogRangeHigh = 127;
    260         highp.fBits = 23;
    261 
    262         auto& mediump = shaderCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
    263         mediump.fLogRangeLow = mediump.fLogRangeHigh = 14;
    264         mediump.fBits = 10;
    265 
    266         shaderCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
    267     }
    268     shaderCaps->initSamplerPrecisionTable();
    269 
    270     shaderCaps->fMaxVertexSamplers =
    271     shaderCaps->fMaxGeometrySamplers =
    272     shaderCaps->fMaxFragmentSamplers = SkTMin(
    273                                        SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
    274                                               properties.limits.maxPerStageDescriptorSamplers),
    275                                               (uint32_t)INT_MAX);
    276     shaderCaps->fMaxCombinedSamplers = SkTMin(
    277                                        SkTMin(properties.limits.maxDescriptorSetSampledImages,
    278                                               properties.limits.maxDescriptorSetSamplers),
    279                                               (uint32_t)INT_MAX);
    280 }
    281 
    282 bool stencil_format_supported(const GrVkInterface* interface,
    283                               VkPhysicalDevice physDev,
    284                               VkFormat format) {
    285     VkFormatProperties props;
    286     memset(&props, 0, sizeof(VkFormatProperties));
    287     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
    288     return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & props.optimalTilingFeatures);
    289 }
    290 
    291 void GrVkCaps::initStencilFormat(const GrVkInterface* interface, VkPhysicalDevice physDev) {
    292     // List of legal stencil formats (though perhaps not supported on
    293     // the particular gpu/driver) from most preferred to least. We are guaranteed to have either
    294     // VK_FORMAT_D24_UNORM_S8_UINT or VK_FORMAT_D32_SFLOAT_S8_UINT. VK_FORMAT_D32_SFLOAT_S8_UINT
    295     // can optionally have 24 unused bits at the end so we assume the total bits is 64.
    296     static const StencilFormat
    297                   // internal Format             stencil bits      total bits        packed?
    298         gS8    = { VK_FORMAT_S8_UINT,            8,                 8,               false },
    299         gD24S8 = { VK_FORMAT_D24_UNORM_S8_UINT,  8,                32,               true },
    300         gD32S8 = { VK_FORMAT_D32_SFLOAT_S8_UINT, 8,                64,               true };
    301 
    302     if (stencil_format_supported(interface, physDev, VK_FORMAT_S8_UINT)) {
    303         fPreferedStencilFormat = gS8;
    304     } else if (stencil_format_supported(interface, physDev, VK_FORMAT_D24_UNORM_S8_UINT)) {
    305         fPreferedStencilFormat = gD24S8;
    306     } else {
    307         SkASSERT(stencil_format_supported(interface, physDev, VK_FORMAT_D32_SFLOAT_S8_UINT));
    308         fPreferedStencilFormat = gD32S8;
    309     }
    310 }
    311 
    312 void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice physDev) {
    313     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
    314         VkFormat format;
    315         if (GrPixelConfigToVkFormat(static_cast<GrPixelConfig>(i), &format)) {
    316             if (!GrPixelConfigIsSRGB(static_cast<GrPixelConfig>(i)) || fSRGBSupport) {
    317                 fConfigTable[i].init(interface, physDev, format);
    318             }
    319         }
    320     }
    321 }
    322 
    323 void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) {
    324     if (SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & vkFlags) &&
    325         SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & vkFlags)) {
    326         *flags = *flags | kTextureable_Flag;
    327 
    328         // Ganesh assumes that all renderable surfaces are also texturable
    329         if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags)) {
    330             *flags = *flags | kRenderable_Flag;
    331         }
    332     }
    333 
    334     if (SkToBool(VK_FORMAT_FEATURE_BLIT_SRC_BIT & vkFlags)) {
    335         *flags = *flags | kBlitSrc_Flag;
    336     }
    337 
    338     if (SkToBool(VK_FORMAT_FEATURE_BLIT_DST_BIT & vkFlags)) {
    339         *flags = *flags | kBlitDst_Flag;
    340     }
    341 }
    342 
    343 void GrVkCaps::ConfigInfo::initSampleCounts(const GrVkInterface* interface,
    344                                             VkPhysicalDevice physDev,
    345                                             VkFormat format) {
    346     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
    347                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
    348                               VK_IMAGE_USAGE_SAMPLED_BIT |
    349                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    350     VkImageCreateFlags createFlags = GrVkFormatIsSRGB(format, nullptr)
    351         ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0;
    352     VkImageFormatProperties properties;
    353     GR_VK_CALL(interface, GetPhysicalDeviceImageFormatProperties(physDev,
    354                                                                  format,
    355                                                                  VK_IMAGE_TYPE_2D,
    356                                                                  VK_IMAGE_TILING_OPTIMAL,
    357                                                                  usage,
    358                                                                  createFlags,
    359                                                                  &properties));
    360     VkSampleCountFlags flags = properties.sampleCounts;
    361     if (flags & VK_SAMPLE_COUNT_1_BIT) {
    362         fColorSampleCounts.push(0);
    363     }
    364     if (flags & VK_SAMPLE_COUNT_2_BIT) {
    365         fColorSampleCounts.push(2);
    366     }
    367     if (flags & VK_SAMPLE_COUNT_4_BIT) {
    368         fColorSampleCounts.push(4);
    369     }
    370     if (flags & VK_SAMPLE_COUNT_8_BIT) {
    371         fColorSampleCounts.push(8);
    372     }
    373     if (flags & VK_SAMPLE_COUNT_16_BIT) {
    374         fColorSampleCounts.push(16);
    375     }
    376     if (flags & VK_SAMPLE_COUNT_32_BIT) {
    377         fColorSampleCounts.push(32);
    378     }
    379     if (flags & VK_SAMPLE_COUNT_64_BIT) {
    380         fColorSampleCounts.push(64);
    381     }
    382 }
    383 
    384 void GrVkCaps::ConfigInfo::init(const GrVkInterface* interface,
    385                                 VkPhysicalDevice physDev,
    386                                 VkFormat format) {
    387     VkFormatProperties props;
    388     memset(&props, 0, sizeof(VkFormatProperties));
    389     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
    390     InitConfigFlags(props.linearTilingFeatures, &fLinearFlags);
    391     InitConfigFlags(props.optimalTilingFeatures, &fOptimalFlags);
    392     if (fOptimalFlags & kRenderable_Flag) {
    393         this->initSampleCounts(interface, physDev, format);
    394     }
    395 }
    396 
    397 int GrVkCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {
    398     int count = fConfigTable[config].fColorSampleCounts.count();
    399     if (!count || !this->isConfigRenderable(config, true)) {
    400         return 0;
    401     }
    402 
    403     for (int i = 0; i < count; ++i) {
    404         if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) {
    405             return fConfigTable[config].fColorSampleCounts[i];
    406         }
    407     }
    408     return fConfigTable[config].fColorSampleCounts[count-1];
    409 }
    410 
    411