• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
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 #ifndef skgpu_graphite_Caps_DEFINED
9 #define skgpu_graphite_Caps_DEFINED
10 
11 #include <optional>
12 #include <string>
13 #include <string_view>
14 #include <utility>
15 
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/private/base/SkAlign.h"
19 #include "src/base/SkEnumBitMask.h"
20 #include "src/gpu/ResourceKey.h"
21 #include "src/gpu/Swizzle.h"
22 #include "src/gpu/graphite/ResourceTypes.h"
23 #include "src/gpu/graphite/TextureProxy.h"
24 #include "src/text/gpu/SubRunControl.h"
25 
26 #if defined(GPU_TEST_UTILS)
27 #include "src/gpu/graphite/ContextOptionsPriv.h"
28 #endif
29 
30 enum class SkBlendMode;
31 enum class SkTextureCompressionType;
32 class SkCapabilities;
33 class SkStream;
34 class SkWStream;
35 
36 namespace SkSL { struct ShaderCaps; }
37 
38 namespace skgpu { class ShaderErrorHandler; }
39 
40 namespace skgpu::graphite {
41 
42 enum class BufferType : int;
43 struct ContextOptions;
44 class ComputePipelineDesc;
45 class GraphicsPipelineDesc;
46 class GraphiteResourceKey;
47 class RendererProvider;
48 struct RenderPassDesc;
49 class TextureInfo;
50 
51 struct ResourceBindingRequirements {
52     // The required data layout rules for the contents of a uniform buffer.
53     Layout fUniformBufferLayout = Layout::kInvalid;
54 
55     // The required data layout rules for the contents of a storage buffer.
56     Layout fStorageBufferLayout = Layout::kInvalid;
57 
58     // Whether combined texture-sampler types are supported. Backends that do not support
59     // combined image samplers (i.e. sampler2D) require a texture and sampler object to be bound
60     // separately and their binding indices explicitly specified in the shader text.
61     bool fSeparateTextureAndSamplerBinding = false;
62 
63     // Whether intrinsic constant information is stored as push constants (rather than normal UBO).
64     // Currently only relevant or possibly true for Vulkan.
65     bool fUseVulkanPushConstantsForIntrinsicConstants = false;
66 
67     // Whether compute shader textures use separate index ranges from other resources (i.e. buffers)
68     bool fComputeUsesDistinctIdxRangesForTextures = false;
69 
70     // Define set indices. We assume that even if textures and samplers must be bound separately,
71     // they will still be contained within the same set/group.
72     static constexpr int kUnassigned = -1;
73     int fUniformsSetIdx              = kUnassigned;
74     int fTextureSamplerSetIdx        = kUnassigned;
75     int fInputAttachmentSetIdx       = kUnassigned;
76     // Define uniform buffer bindings
77     int fIntrinsicBufferBinding      = kUnassigned;
78     int fRenderStepBufferBinding     = kUnassigned;
79     int fPaintParamsBufferBinding    = kUnassigned;
80     int fGradientBufferBinding       = kUnassigned;
81 };
82 
83 class Caps {
84 public:
85     virtual ~Caps();
86 
shaderCaps()87     const SkSL::ShaderCaps* shaderCaps() const { return fShaderCaps.get(); }
88 
89     sk_sp<SkCapabilities> capabilities() const;
90 
91 #if defined(GPU_TEST_UTILS)
deviceName()92     std::string_view deviceName() const { return fDeviceName; }
93 
requestedPathRendererStrategy()94     PathRendererStrategy requestedPathRendererStrategy() const {
95         return fRequestedPathRendererStrategy;
96     }
97 #endif
98 
99     virtual TextureInfo getDefaultSampledTextureInfo(SkColorType,
100                                                      Mipmapped mipmapped,
101                                                      Protected,
102                                                      Renderable) const = 0;
103 
104     virtual TextureInfo getTextureInfoForSampledCopy(const TextureInfo& textureInfo,
105                                                      Mipmapped mipmapped) const = 0;
106 
107     virtual TextureInfo getDefaultCompressedTextureInfo(SkTextureCompressionType,
108                                                         Mipmapped mipmapped,
109                                                         Protected) const = 0;
110 
111     virtual TextureInfo getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
112                                                   Discardable discardable) const = 0;
113 
114     // Currently the uses of this API always are asking for a discardable DepthStencil attachment.
115     // However, we still pass in the parameter here because we don't want the backend caps to be
116     // making decisons on if a thing should be discardable or not. This also allows us to eventual
117     // use non discardable DS attachments, but there aren't any current plans to do so. If we find
118     // out over time that we really will only ever use discardable ones, we could rename this
119     // function to be getDefaultDiscardableDepthStencilTextureInfo.
120     virtual TextureInfo getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags>,
121                                                           uint32_t sampleCount,
122                                                           Protected,
123                                                           Discardable discardable) const = 0;
124 
125     virtual TextureInfo getDefaultStorageTextureInfo(SkColorType) const = 0;
126 
127     // Get required depth attachment dimensions for a givin color attachment info and dimensions.
128     virtual SkISize getDepthAttachmentDimensions(const TextureInfo&,
129                                                  const SkISize colorAttachmentDimensions) const;
130 
131     virtual UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc&,
132                                               const RenderPassDesc&) const = 0;
133     virtual UniqueKey makeComputePipelineKey(const ComputePipelineDesc&) const = 0;
134 
135 
extractGraphicsDescs(const UniqueKey &,GraphicsPipelineDesc *,RenderPassDesc *,const RendererProvider *)136     virtual bool extractGraphicsDescs(const UniqueKey&,
137                                       GraphicsPipelineDesc*,
138                                       RenderPassDesc*,
139                                       const RendererProvider*) const { return false; }
140 
141     virtual bool serializeTextureInfo(const TextureInfo&, SkWStream*) const = 0;
142     virtual bool deserializeTextureInfo(SkStream*, TextureInfo*) const = 0;
143 
144     bool areColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const;
145 
146     bool isTexturable(const TextureInfo&) const;
147     virtual bool isRenderable(const TextureInfo&) const = 0;
148     virtual bool isStorage(const TextureInfo&) const = 0;
149 
loadOpAffectsMSAAPipelines()150     virtual bool loadOpAffectsMSAAPipelines() const { return false; }
151 
maxTextureSize()152     int maxTextureSize() const { return fMaxTextureSize; }
defaultMSAASamplesCount()153     int defaultMSAASamplesCount() const { return fDefaultMSAASamples; }
154 
155     virtual void buildKeyForTexture(SkISize dimensions,
156                                     const TextureInfo&,
157                                     ResourceType,
158                                     GraphiteResourceKey*) const = 0;
159 
resourceBindingRequirements()160     const ResourceBindingRequirements& resourceBindingRequirements() const {
161         return fResourceBindingReqs;
162     }
163 
164     // Returns the required alignment in bytes for the offset into a uniform buffer when binding it
165     // to a draw.
requiredUniformBufferAlignment()166     size_t requiredUniformBufferAlignment() const { return fRequiredUniformBufferAlignment; }
167 
168     // Returns the required alignment in bytes for the offset into a storage buffer when binding it
169     // to a draw.
requiredStorageBufferAlignment()170     size_t requiredStorageBufferAlignment() const { return fRequiredStorageBufferAlignment; }
171 
172     // Returns the required alignment in bytes for the offset and size of copies involving a buffer.
requiredTransferBufferAlignment()173     size_t requiredTransferBufferAlignment() const { return fRequiredTransferBufferAlignment; }
174 
175     // Returns the aligned rowBytes when transfering to or from a Texture
getAlignedTextureDataRowBytes(size_t rowBytes)176     size_t getAlignedTextureDataRowBytes(size_t rowBytes) const {
177         return SkAlignTo(rowBytes, fTextureDataRowBytesAlignment);
178     }
179 
180     // Backends can optionally override this method to return meaningful sampler conversion info.
181     // By default, simply return a default ImmutableSamplerInfo (e.g. no immutable sampler).
getImmutableSamplerInfo(const TextureInfo &)182     virtual ImmutableSamplerInfo getImmutableSamplerInfo(const TextureInfo&) const {
183         return {};
184     }
185 
186     /**
187      * Backends may have restrictions on what types of textures support Device::writePixels().
188      * If this returns false then the caller should implement a fallback where a temporary texture
189      * is created, pixels are written to it, and then that is copied or drawn into the the surface.
190      */
191     virtual bool supportsWritePixels(const TextureInfo& textureInfo) const = 0;
192 
193     /**
194      * Backends may have restrictions on what types of textures support Device::readPixels().
195      * If this returns false then the caller should implement a fallback where a temporary texture
196      * is created, the original texture is copied or drawn into it, and then pixels read from
197      * the temporary texture.
198      */
199     virtual bool supportsReadPixels(const TextureInfo& textureInfo) const = 0;
200 
201     /**
202      * Given a dst pixel config and a src color type what color type must the caller coax the
203      * the data into in order to use writePixels.
204      *
205      * We currently don't have an SkColorType for a 3 channel RGB format. Additionally the current
206      * implementation of raster pipeline requires power of 2 channels, so it is not easy to add such
207      * an SkColorType. Thus we need to check for data that is 3 channels using the isRGBFormat
208      * return value and handle it manually
209      */
210     virtual std::pair<SkColorType, bool /*isRGB888Format*/> supportedWritePixelsColorType(
211             SkColorType dstColorType,
212             const TextureInfo& dstTextureInfo,
213             SkColorType srcColorType) const = 0;
214 
215     /**
216      * Given a src surface's color type and its texture info as well as a color type the caller
217      * would like read into, this provides a legal color type that the caller can use for
218      * readPixels. The returned color type may differ from the passed dstColorType, in
219      * which case the caller must convert the read pixel data (see GrConvertPixels). When converting
220      * to dstColorType the swizzle in the returned struct should be applied. The caller must check
221      * the returned color type for kUnknown.
222      *
223      * We currently don't have an SkColorType for a 3 channel RGB format. Additionally the current
224      * implementation of raster pipeline requires power of 2 channels, so it is not easy to add such
225      * an SkColorType. Thus we need to check for data that is 3 channels using the isRGBFormat
226      * return value and handle it manually
227      */
228     virtual std::pair<SkColorType, bool /*isRGBFormat*/> supportedReadPixelsColorType(
229             SkColorType srcColorType,
230             const TextureInfo& srcTextureInfo,
231             SkColorType dstColorType) const = 0;
232 
233     /**
234      * Checks whether the passed color type is renderable. If so, the same color type is passed
235      * back. If not, provides an alternative (perhaps lower bit depth and/or unorm instead of float)
236      * color type that is supported or kUnknown if there no renderable fallback format.
237      */
238     SkColorType getRenderableColorType(SkColorType) const;
239 
240     // Determines the orientation of the NDC coordinates emitted by the vertex stage relative to
241     // both Skia's presumed top-left Y-down system and the viewport coordinates (which are also
242     // always top-left, Y-down for all supported backends).)
243     //
244     // If true is returned, then (-1,-1) in normalized device coords maps to the top-left of the
245     // configured viewport and positive Y points down. This aligns with Skia's conventions.
246     // If false is returned, then (-1,-1) in NDC maps to the bottom-left of the viewport and
247     // positive Y points up (so NDC is flipped relative to sk_Position and the viewport coords).
248     //
249     // There is no backend difference in handling the X axis so it's assumed -1 maps to the left
250     // edge and +1 maps to the right edge.
ndcYAxisPointsDown()251     bool ndcYAxisPointsDown() const { return fNDCYAxisPointsDown; }
252 
clampToBorderSupport()253     bool clampToBorderSupport() const { return fClampToBorderSupport; }
254 
protectedSupport()255     bool protectedSupport() const { return fProtectedSupport; }
256 
257     // Supports BackendSemaphores
semaphoreSupport()258     bool semaphoreSupport() const { return fSemaphoreSupport; }
259 
260     // If false then calling Context::submit with SyncToCpu::kYes is an error.
allowCpuSync()261     bool allowCpuSync() const { return fAllowCpuSync; }
262 
263     // Returns whether storage buffers are supported and to be preferred over uniform buffers.
storageBufferSupport()264     bool storageBufferSupport() const { return fStorageBufferSupport; }
265 
266     // The gradient buffer is an unsized float array so it is only optimal memory-wise to use it if
267     // the storage buffer memory layout is std430 or in metal, which is also the only supported
268     // way the data is packed.
gradientBufferSupport()269     bool gradientBufferSupport() const {
270         return fStorageBufferSupport &&
271                (fResourceBindingReqs.fStorageBufferLayout == Layout::kStd430 ||
272                 fResourceBindingReqs.fStorageBufferLayout == Layout::kMetal);
273     }
274 
275     // Returns whether a draw buffer can be mapped.
drawBufferCanBeMapped()276     bool drawBufferCanBeMapped() const { return fDrawBufferCanBeMapped; }
277 
278 #if defined(GPU_TEST_UTILS)
drawBufferCanBeMappedForReadback()279     bool drawBufferCanBeMappedForReadback() const { return fDrawBufferCanBeMappedForReadback; }
280 #endif
281 
282     // Returns whether using Buffer::asyncMap() must be used to map buffers. map() may only be
283     // called after asyncMap() is called and will fail if the asynchronous map is not complete. This
284     // excludes premapped buffers for which map() can be called freely until the first unmap() call.
bufferMapsAreAsync()285     bool bufferMapsAreAsync() const { return fBufferMapsAreAsync; }
286 
287     // Returns whether multisampled render to single sampled is supported.
msaaRenderToSingleSampledSupport()288     bool msaaRenderToSingleSampledSupport() const { return fMSAARenderToSingleSampledSupport; }
289 
290     // Returns whether a render pass can have MSAA/depth/stencil attachments and a resolve
291     // attachment with mismatched sizes. Note: the MSAA attachment and the depth/stencil attachment
292     // still need to match their sizes.
differentResolveAttachmentSizeSupport()293     bool differentResolveAttachmentSizeSupport() const {
294         return fDifferentResolveAttachmentSizeSupport;
295     }
296 
297     // Returns whether compute shaders are supported.
computeSupport()298     bool computeSupport() const { return fComputeSupport; }
299 
300     /**
301      * Returns true if the given backend supports importing AHardwareBuffers. This will only
302      * ever be supported on Android devices with API level >= 26.
303      */
supportsAHardwareBufferImages()304     bool supportsAHardwareBufferImages() const { return fSupportsAHardwareBufferImages; }
305 
306     // Returns the skgpu::Swizzle to use when sampling or reading back from a texture with the
307     // passed in SkColorType and TextureInfo.
308     skgpu::Swizzle getReadSwizzle(SkColorType, const TextureInfo&) const;
309 
310     // Returns the skgpu::Swizzle to use when writing colors to a surface with the passed in
311     // SkColorType and TextureInfo.
312     skgpu::Swizzle getWriteSwizzle(SkColorType, const TextureInfo&) const;
313 
shaderErrorHandler()314     skgpu::ShaderErrorHandler* shaderErrorHandler() const { return fShaderErrorHandler; }
315 
316     // Returns what method of dst read a draw should use for obtaining the dst color. Backends can
317     // use the default implementation or override this method as needed.
318     // TODO(b/390458117): Once the Vulkan backend supports DstReadStrategy::kReadFromInput for
319     // MSAA textures (and if we are comfortable assuming by this point that all render targets, at
320     // least on Android, support input attachment usage) then the TextureInfo argument can be
321     // removed and backend Caps implementations can report kReadFromInput support some other way
322     // (such as a simple member attribute bool). For now, we must check each render target's info.
323     virtual DstReadStrategy getDstReadStrategy(const TextureInfo&) const;
324 
minDistanceFieldFontSize()325     float minDistanceFieldFontSize() const { return fMinDistanceFieldFontSize; }
glyphsAsPathsFontSize()326     float glyphsAsPathsFontSize() const { return fGlyphsAsPathsFontSize; }
327 
glyphCacheTextureMaximumBytes()328     size_t glyphCacheTextureMaximumBytes() const { return fGlyphCacheTextureMaximumBytes; }
maxPathAtlasTextureSize()329     int maxPathAtlasTextureSize() const { return fMaxPathAtlasTextureSize; }
330 
allowMultipleAtlasTextures()331     bool allowMultipleAtlasTextures() const { return fAllowMultipleAtlasTextures; }
supportBilerpFromGlyphAtlas()332     bool supportBilerpFromGlyphAtlas() const { return fSupportBilerpFromGlyphAtlas; }
333 
requireOrderedRecordings()334     bool requireOrderedRecordings() const { return fRequireOrderedRecordings; }
335 
336     // When uploading to a full compressed texture do we need to pad the size out to a multiple of
337     // the block width and height.
fullCompressedUploadSizeMustAlignToBlockDims()338     bool fullCompressedUploadSizeMustAlignToBlockDims() const {
339         return fFullCompressedUploadSizeMustAlignToBlockDims;
340     }
341 
342     sktext::gpu::SubRunControl getSubRunControl(bool useSDFTForSmallText) const;
343 
setBackendLabels()344     bool setBackendLabels() const { return fSetBackendLabels; }
345 
supportedGpuStats()346     GpuStatsFlags supportedGpuStats() const { return fSupportedGpuStats; }
347 
348 protected:
349     Caps();
350 
351     // Subclasses must call this at the end of their init method in order to do final processing on
352     // the caps.
353     void finishInitialization(const ContextOptions&);
354 
355 #if defined(GPU_TEST_UTILS)
setDeviceName(std::string n)356     void setDeviceName(std::string n) {
357         fDeviceName = std::move(n);
358     }
359 #endif
360 
361     // There are only a few possible valid sample counts (1, 2, 4, 8, 16). So we can key on those 5
362     // options instead of the actual sample value.
SamplesToKey(uint32_t numSamples)363     static inline uint32_t SamplesToKey(uint32_t numSamples) {
364         switch (numSamples) {
365             case 1:
366                 return 0;
367             case 2:
368                 return 1;
369             case 4:
370                 return 2;
371             case 8:
372                 return 3;
373             case 16:
374                 return 4;
375             default:
376                 SkUNREACHABLE;
377         }
378     }
379 
380     // ColorTypeInfo for a specific format. Used in format tables.
381     struct ColorTypeInfo {
382         ColorTypeInfo() = default;
ColorTypeInfoColorTypeInfo383         ColorTypeInfo(SkColorType ct, SkColorType transferCt, uint32_t flags,
384                       skgpu::Swizzle readSwizzle, skgpu::Swizzle writeSwizzle)
385                 : fColorType(ct)
386                 , fTransferColorType(transferCt)
387                 , fFlags(flags)
388                 , fReadSwizzle(readSwizzle)
389                 , fWriteSwizzle(writeSwizzle) {}
390 
391         SkColorType fColorType = kUnknown_SkColorType;
392         SkColorType fTransferColorType = kUnknown_SkColorType;
393         enum {
394             kUploadData_Flag = 0x1,
395             // Does Graphite itself support rendering to this colorType & format pair. Renderability
396             // still additionally depends on if the format itself is renderable.
397             kRenderable_Flag = 0x2,
398         };
399         uint32_t fFlags = 0;
400 
401         skgpu::Swizzle fReadSwizzle;
402         skgpu::Swizzle fWriteSwizzle;
403     };
404 
405     int fMaxTextureSize = 0;
406     int fDefaultMSAASamples = 4;
407     size_t fRequiredUniformBufferAlignment = 0;
408     size_t fRequiredStorageBufferAlignment = 0;
409     size_t fRequiredTransferBufferAlignment = 0;
410     size_t fTextureDataRowBytesAlignment = 1;
411 
412     std::unique_ptr<SkSL::ShaderCaps> fShaderCaps;
413 
414     bool fNDCYAxisPointsDown = false; // Most backends have NDC +Y pointing up
415     bool fClampToBorderSupport = true;
416     bool fProtectedSupport = false;
417     bool fSemaphoreSupport = false;
418     bool fAllowCpuSync = true;
419     bool fStorageBufferSupport = false;
420     bool fDrawBufferCanBeMapped = true;
421     bool fBufferMapsAreAsync = false;
422     bool fMSAARenderToSingleSampledSupport = false;
423     bool fDifferentResolveAttachmentSizeSupport = false;
424 
425     bool fComputeSupport = false;
426     bool fSupportsAHardwareBufferImages = false;
427     bool fFullCompressedUploadSizeMustAlignToBlockDims = false;
428 
429 #if defined(GPU_TEST_UTILS)
430     bool fDrawBufferCanBeMappedForReadback = true;
431 #endif
432 
433     ResourceBindingRequirements fResourceBindingReqs;
434 
435     GpuStatsFlags fSupportedGpuStats = GpuStatsFlags::kNone;
436 
437     //////////////////////////////////////////////////////////////////////////////////////////
438     // Client-provided Caps
439 
440     /**
441      * If present, use this object to report shader compilation failures. If not, report failures
442      * via SkDebugf and assert.
443      */
444     ShaderErrorHandler* fShaderErrorHandler = nullptr;
445 
446 #if defined(GPU_TEST_UTILS)
447     std::string fDeviceName;
448     int fMaxTextureAtlasSize = 2048;
449     PathRendererStrategy fRequestedPathRendererStrategy;
450 #endif
451     size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
452 
453     float fMinDistanceFieldFontSize = 18;
454     float fGlyphsAsPathsFontSize = 324;
455 
456     int fMaxPathAtlasTextureSize = 8192;
457 
458     bool fAllowMultipleAtlasTextures = true;
459     bool fSupportBilerpFromGlyphAtlas = false;
460 
461     bool fRequireOrderedRecordings = false;
462 
463     bool fSetBackendLabels = false;
464 
465 private:
466     virtual bool onIsTexturable(const TextureInfo&) const = 0;
467     virtual const ColorTypeInfo* getColorTypeInfo(SkColorType, const TextureInfo&) const = 0;
468 
469     sk_sp<SkCapabilities> fCapabilities;
470 };
471 
472 } // namespace skgpu::graphite
473 
474 #endif // skgpu_graphite_Caps_DEFINED
475