Add fixes & test for isConfigTexturable and isConfigRenderable
[platform/upstream/libSkiaSharp.git] / src / gpu / vk / GrVkCaps.cpp
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     fCompressedTexSubImageSupport = false; //TODO: figure this out
35     fOversizedStencilSupport = false; //TODO: figure this out
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
196 void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint32_t featureFlags) {
197     GrShaderCaps* shaderCaps = fShaderCaps.get();
198     shaderCaps->fVersionDeclString = "#version 330\n";
199
200
201     // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
202     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
203         GrPixelConfig config = static_cast<GrPixelConfig>(i);
204         if (GrPixelConfigIsAlphaOnly(config)) {
205             shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
206             shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
207         } else {
208             if (kGray_8_GrPixelConfig == config) {
209                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
210             } else if (kRGBA_4444_GrPixelConfig == config) {
211                 // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we
212                 // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads
213                 // or writing to outputs. Since we're not actually changing the data at all, the
214                 // only extra work is the swizzle in the shader for all operations.
215                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA();
216                 shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA();
217             } else {
218                 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
219             }
220         }
221     }
222
223     if (kImagination_VkVendor == properties.vendorID) {
224         shaderCaps->fAtan2ImplementedAsAtanYOverX = true;
225     }
226
227     // Vulkan is based off ES 3.0 so the following should all be supported
228     shaderCaps->fUsesPrecisionModifiers = true;
229     shaderCaps->fFlatInterpolationSupport = true;
230
231     // GrShaderCaps
232
233     shaderCaps->fShaderDerivativeSupport = true;
234     shaderCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);
235
236     shaderCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);
237     if (kAMD_VkVendor == properties.vendorID) {
238         // Currently DualSourceBlending is not working on AMD. vkCreateGraphicsPipeline fails when
239         // using a draw with dual source. Looking into whether it is driver bug or issue with our
240         // SPIR-V. Bug skia:6405
241         shaderCaps->fDualSourceBlendingSupport = false;
242     }
243
244     shaderCaps->fIntegerSupport = true;
245
246     // Assume the minimum precisions mandated by the SPIR-V spec.
247     shaderCaps->fShaderPrecisionVaries = true;
248     for (int s = 0; s < kGrShaderTypeCount; ++s) {
249         auto& highp = shaderCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
250         highp.fLogRangeLow = highp.fLogRangeHigh = 127;
251         highp.fBits = 23;
252
253         auto& mediump = shaderCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
254         mediump.fLogRangeLow = mediump.fLogRangeHigh = 14;
255         mediump.fBits = 10;
256
257         shaderCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
258     }
259     shaderCaps->initSamplerPrecisionTable();
260
261     shaderCaps->fMaxVertexSamplers =
262     shaderCaps->fMaxGeometrySamplers =
263     shaderCaps->fMaxFragmentSamplers = SkTMin(
264                                        SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
265                                               properties.limits.maxPerStageDescriptorSamplers),
266                                               (uint32_t)INT_MAX);
267     shaderCaps->fMaxCombinedSamplers = SkTMin(
268                                        SkTMin(properties.limits.maxDescriptorSetSampledImages,
269                                               properties.limits.maxDescriptorSetSamplers),
270                                               (uint32_t)INT_MAX);
271 }
272
273 bool stencil_format_supported(const GrVkInterface* interface,
274                               VkPhysicalDevice physDev,
275                               VkFormat format) {
276     VkFormatProperties props;
277     memset(&props, 0, sizeof(VkFormatProperties));
278     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
279     return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & props.optimalTilingFeatures);
280 }
281
282 void GrVkCaps::initStencilFormat(const GrVkInterface* interface, VkPhysicalDevice physDev) {
283     // List of legal stencil formats (though perhaps not supported on
284     // the particular gpu/driver) from most preferred to least. We are guaranteed to have either
285     // VK_FORMAT_D24_UNORM_S8_UINT or VK_FORMAT_D32_SFLOAT_S8_UINT. VK_FORMAT_D32_SFLOAT_S8_UINT
286     // can optionally have 24 unused bits at the end so we assume the total bits is 64.
287     static const StencilFormat
288                   // internal Format             stencil bits      total bits        packed?
289         gS8    = { VK_FORMAT_S8_UINT,            8,                 8,               false },
290         gD24S8 = { VK_FORMAT_D24_UNORM_S8_UINT,  8,                32,               true },
291         gD32S8 = { VK_FORMAT_D32_SFLOAT_S8_UINT, 8,                64,               true };
292
293     if (stencil_format_supported(interface, physDev, VK_FORMAT_S8_UINT)) {
294         fPreferedStencilFormat = gS8;
295     } else if (stencil_format_supported(interface, physDev, VK_FORMAT_D24_UNORM_S8_UINT)) {
296         fPreferedStencilFormat = gD24S8;
297     } else {
298         SkASSERT(stencil_format_supported(interface, physDev, VK_FORMAT_D32_SFLOAT_S8_UINT));
299         fPreferedStencilFormat = gD32S8;
300     }
301 }
302
303 void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice physDev) {
304     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
305         VkFormat format;
306         if (GrPixelConfigToVkFormat(static_cast<GrPixelConfig>(i), &format)) {
307             fConfigTable[i].init(interface, physDev, format);
308         }
309     }
310
311     // We currently do not support compressed textures in Vulkan
312     const uint16_t kFlagsToRemove = ConfigInfo::kTextureable_Flag|ConfigInfo::kRenderable_Flag;
313     fConfigTable[kETC1_GrPixelConfig].fOptimalFlags &= ~kFlagsToRemove;
314     fConfigTable[kETC1_GrPixelConfig].fLinearFlags &= ~kFlagsToRemove;
315 }
316
317 void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) {
318     if (SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & vkFlags) &&
319         SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & vkFlags)) {
320         *flags = *flags | kTextureable_Flag;
321
322         // Ganesh assumes that all renderable surfaces are also texturable
323         if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags)) {
324             *flags = *flags | kRenderable_Flag;
325         }
326     }
327
328     if (SkToBool(VK_FORMAT_FEATURE_BLIT_SRC_BIT & vkFlags)) {
329         *flags = *flags | kBlitSrc_Flag;
330     }
331
332     if (SkToBool(VK_FORMAT_FEATURE_BLIT_DST_BIT & vkFlags)) {
333         *flags = *flags | kBlitDst_Flag;
334     }
335 }
336
337 void GrVkCaps::ConfigInfo::init(const GrVkInterface* interface,
338                                 VkPhysicalDevice physDev,
339                                 VkFormat format) {
340     VkFormatProperties props;
341     memset(&props, 0, sizeof(VkFormatProperties));
342     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
343     InitConfigFlags(props.linearTilingFeatures, &fLinearFlags);
344     InitConfigFlags(props.optimalTilingFeatures, &fOptimalFlags);
345 }