/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_graphite_Caps_DEFINED #define skgpu_graphite_Caps_DEFINED #include "include/core/SkImageInfo.h" #include "include/core/SkRefCnt.h" #include "include/private/base/SkAlign.h" #include "src/core/SkEnumBitMask.h" #include "src/gpu/ResourceKey.h" #include "src/gpu/Swizzle.h" #include "src/gpu/graphite/ResourceTypes.h" #include "src/text/gpu/SDFTControl.h" class SkCapabilities; namespace SkSL { struct ShaderCaps; } namespace skgpu { class ShaderErrorHandler; } namespace skgpu::graphite { enum class BufferType : int; struct ContextOptions; class ComputePipelineDesc; class GraphicsPipelineDesc; class GraphiteResourceKey; struct RenderPassDesc; class TextureInfo; class TextureProxy; struct ResourceBindingRequirements { // The required data layout rules for the contents of a uniform buffer. Layout fUniformBufferLayout = Layout::kInvalid; // The required data layout rules for the contents of a storage buffer. Layout fStorageBufferLayout = Layout::kInvalid; // Whether combined texture-sampler types are supported. Backends that do not support // combined image samplers (i.e. sampler2D) require a texture and sampler object to be bound // separately and their binding indices explicitly specified in the shader text. bool fSeparateTextureAndSamplerBinding = false; // Whether buffer, texture, and sampler resource bindings use distinct index ranges. bool fDistinctIndexRanges = false; }; class Caps { public: virtual ~Caps(); const SkSL::ShaderCaps* shaderCaps() const { return fShaderCaps.get(); } sk_sp capabilities() const; virtual TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) const = 0; virtual TextureInfo getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo, Discardable discardable) const = 0; virtual TextureInfo getDefaultDepthStencilTextureInfo(SkEnumBitMask, uint32_t sampleCount, Protected) const = 0; virtual UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc&, const RenderPassDesc&) const = 0; virtual UniqueKey makeComputePipelineKey(const ComputePipelineDesc&) const = 0; bool areColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const; bool isTexturable(const TextureInfo&) const; virtual bool isRenderable(const TextureInfo&) const = 0; int maxTextureSize() const { return fMaxTextureSize; } virtual void buildKeyForTexture(SkISize dimensions, const TextureInfo&, ResourceType, Shareable, GraphiteResourceKey*) const = 0; const ResourceBindingRequirements& resourceBindingRequirements() const { return fResourceBindingReqs; } // Returns the required alignment in bytes for the offset into a uniform buffer when binding it // to a draw. size_t requiredUniformBufferAlignment() const { return fRequiredUniformBufferAlignment; } // Returns the required alignment in bytes for the offset into a storage buffer when binding it // to a draw. size_t requiredStorageBufferAlignment() const { return fRequiredStorageBufferAlignment; } // Returns the required alignment in bytes for the offset and size of copies involving a buffer. size_t requiredTransferBufferAlignment() const { return fRequiredTransferBufferAlignment; } // Returns the aligned rowBytes when transfering to or from a Texture size_t getAlignedTextureDataRowBytes(size_t rowBytes) const { return SkAlignTo(rowBytes, fTextureDataRowBytesAlignment); } /** * Backends may have restrictions on what types of textures support Device::writePixels(). * If this returns false then the caller should implement a fallback where a temporary texture * is created, pixels are written to it, and then that is copied or drawn into the the surface. */ virtual bool supportsWritePixels(const TextureInfo& textureInfo) const = 0; /** * Backends may have restrictions on what types of textures support Device::readPixels(). * If this returns false then the caller should implement a fallback where a temporary texture * is created, the original texture is copied or drawn into it, and then pixels read from * the temporary texture. */ virtual bool supportsReadPixels(const TextureInfo& textureInfo) const = 0; /** * Given a dst pixel config and a src color type what color type must the caller coax the * the data into in order to use writePixels. */ virtual SkColorType supportedWritePixelsColorType(SkColorType dstColorType, const TextureInfo& dstTextureInfo, SkColorType srcColorType) const = 0; /** * Given a src surface's color type and its texture info as well as a color type the caller * would like read into, this provides a legal color type that the caller can use for * readPixels. The returned color type may differ from the passed dstColorType, in * which case the caller must convert the read pixel data (see GrConvertPixels). When converting * to dstColorType the swizzle in the returned struct should be applied. The caller must check * the returned color type for kUnknown. */ virtual SkColorType supportedReadPixelsColorType(SkColorType srcColorType, const TextureInfo& srcTextureInfo, SkColorType dstColorType) const = 0; bool clampToBorderSupport() const { return fClampToBorderSupport; } bool protectedSupport() const { return fProtectedSupport; } // Returns whether storage buffers are supported. bool storageBufferSupport() const { return fStorageBufferSupport; } // Returns whether storage buffers are preferred over uniform buffers, when both will yield // correct results. bool storageBufferPreferred() const { return fStorageBufferPreferred; } // Returns whether a draw buffer can be mapped. bool drawBufferCanBeMapped() const { return fDrawBufferCanBeMapped; } // Returns the skgpu::Swizzle to use when sampling or reading back from a texture with the // passed in SkColorType and TextureInfo. skgpu::Swizzle getReadSwizzle(SkColorType, const TextureInfo&) const; // Returns the skgpu::Swizzle to use when writing colors to a surface with the passed in // SkColorType and TextureInfo. skgpu::Swizzle getWriteSwizzle(SkColorType, const TextureInfo&) const; skgpu::ShaderErrorHandler* shaderErrorHandler() const { return fShaderErrorHandler; } float minDistanceFieldFontSize() const { return fMinDistanceFieldFontSize; } float glyphsAsPathsFontSize() const { return fGlyphsAsPathsFontSize; } size_t glyphCacheTextureMaximumBytes() const { return fGlyphCacheTextureMaximumBytes; } bool allowMultipleGlyphCacheTextures() const { return fAllowMultipleGlyphCacheTextures; } bool supportBilerpFromGlyphAtlas() const { return fSupportBilerpFromGlyphAtlas; } sktext::gpu::SDFTControl getSDFTControl(bool useSDFTForSmallText) const; protected: Caps(); // Subclasses must call this at the end of their init method in order to do final processing on // the caps. void finishInitialization(const ContextOptions&); // TODO: This value should be set by some context option. For now just making it 4. uint32_t defaultMSAASamples() const { return 4; } // There are only a few possible valid sample counts (1, 2, 4, 8, 16). So we can key on those 5 // options instead of the actual sample value. static inline uint32_t SamplesToKey(uint32_t numSamples) { switch (numSamples) { case 1: return 0; case 2: return 1; case 4: return 2; case 8: return 3; case 16: return 4; default: SkUNREACHABLE; } } // ColorTypeInfo for a specific format. // Used in format tables. struct ColorTypeInfo { SkColorType fColorType = kUnknown_SkColorType; SkColorType fTransferColorType = kUnknown_SkColorType; enum { kUploadData_Flag = 0x1, // Does Graphite itself support rendering to this colorType & format pair. Renderability // still additionally depends on if the format itself is renderable. kRenderable_Flag = 0x2, }; uint32_t fFlags = 0; skgpu::Swizzle fReadSwizzle; skgpu::Swizzle fWriteSwizzle; }; int fMaxTextureSize = 0; size_t fRequiredUniformBufferAlignment = 0; size_t fRequiredStorageBufferAlignment = 0; size_t fRequiredTransferBufferAlignment = 0; size_t fTextureDataRowBytesAlignment = 1; std::unique_ptr fShaderCaps; bool fClampToBorderSupport = true; bool fProtectedSupport = false; bool fStorageBufferSupport = false; bool fStorageBufferPreferred = false; bool fDrawBufferCanBeMapped = true; ResourceBindingRequirements fResourceBindingReqs; ////////////////////////////////////////////////////////////////////////////////////////// // Client-provided Caps /** * If present, use this object to report shader compilation failures. If not, report failures * via SkDebugf and assert. */ ShaderErrorHandler* fShaderErrorHandler = nullptr; #if GRAPHITE_TEST_UTILS int fMaxTextureAtlasSize = 2048; #endif size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4; float fMinDistanceFieldFontSize = 18; float fGlyphsAsPathsFontSize = 324; bool fAllowMultipleGlyphCacheTextures = true; bool fSupportBilerpFromGlyphAtlas = false; private: virtual bool onIsTexturable(const TextureInfo&) const = 0; virtual const ColorTypeInfo* getColorTypeInfo(SkColorType, const TextureInfo&) const = 0; sk_sp fCapabilities; }; } // namespace skgpu::graphite #endif // skgpu_graphite_Caps_DEFINED