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