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