• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GrVkCaps(const GrContextOptions & contextOptions,const GrVkInterface * vkInterface,VkPhysicalDevice physDev,uint32_t featureFlags,uint32_t extensionFlags)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 
initDescForDstCopy(const GrRenderTargetProxy * src,GrSurfaceDesc * desc,bool * rectsMustMatch,bool * disallowSubrect) const54 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 
init(const GrContextOptions & contextOptions,const GrVkInterface * vkInterface,VkPhysicalDevice physDev,uint32_t featureFlags,uint32_t extensionFlags)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 
get_max_sample_count(VkSampleCountFlags flags)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 
initSampleCount(const VkPhysicalDeviceProperties & properties)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 
initGrCaps(const VkPhysicalDeviceProperties & properties,const VkPhysicalDeviceMemoryProperties & memoryProperties,uint32_t featureFlags)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 
initShaderCaps(const VkPhysicalDeviceProperties & properties,uint32_t featureFlags)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 
stencil_format_supported(const GrVkInterface * interface,VkPhysicalDevice physDev,VkFormat format)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 
initStencilFormat(const GrVkInterface * interface,VkPhysicalDevice physDev)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 
initConfigTable(const GrVkInterface * interface,VkPhysicalDevice physDev)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 
InitConfigFlags(VkFormatFeatureFlags vkFlags,uint16_t * flags)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 
initSampleCounts(const GrVkInterface * interface,VkPhysicalDevice physDev,VkFormat format)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 
init(const GrVkInterface * interface,VkPhysicalDevice physDev,VkFormat format)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 
getSampleCount(int requestedCount,GrPixelConfig config) const397 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