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