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