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