| /* |
| * 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/SkColorType.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkSize.h" |
| #include "include/gpu/GpuTypes.h" |
| #include "include/private/base/SkAlign.h" |
| #include "include/private/base/SkAssert.h" |
| #include "src/base/SkEnumBitMask.h" |
| #include "src/gpu/ResourceKey.h" |
| #include "src/gpu/Swizzle.h" |
| #include "src/gpu/graphite/ResourceTypes.h" |
| #include "src/text/gpu/SubRunControl.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| class SkCapabilities; |
| enum class SkTextureCompressionType; |
| |
| namespace SkSL { struct ShaderCaps; } |
| |
| namespace skgpu { class ShaderErrorHandler; } |
| |
| namespace skgpu::graphite { |
| |
| class ComputePipelineDesc; |
| class GraphicsPipelineDesc; |
| class GraphiteResourceKey; |
| class RendererProvider; |
| class TextureInfo; |
| enum class DepthStencilFlags : int; |
| enum class PathRendererStrategy; |
| enum class TextureFormat : uint8_t; |
| struct AttachmentDesc; |
| struct ContextOptions; |
| struct RenderPassDesc; |
| |
| struct ResourceBindingRequirements { |
| /* The API of the backend currently in use. */ |
| BackendApi fBackendApi = BackendApi::kUnsupported; |
| |
| /* 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 intrinsic constant information is stored as push constants (rather than normal UBO). |
| * Currently only relevant or possibly true for Dawn or Vulkan. |
| */ |
| bool fUsePushConstantsForIntrinsicConstants = false; |
| |
| /** |
| * Whether compute shader textures use separate index ranges from other resources (i.e. buffers) |
| */ |
| bool fComputeUsesDistinctIdxRangesForTextures = false; |
| |
| /** |
| * Define set indices. We assume that even if textures and samplers must be bound separately, |
| * they will still be contained within the same set/group. |
| */ |
| static constexpr int kUnassigned = -1; |
| int fUniformsSetIdx = kUnassigned; |
| int fTextureSamplerSetIdx = kUnassigned; |
| int fInputAttachmentSetIdx = kUnassigned; |
| /* Define uniform buffer bindings */ |
| int fIntrinsicBufferBinding = kUnassigned; |
| int fRenderStepBufferBinding = kUnassigned; |
| int fPaintParamsBufferBinding = kUnassigned; |
| int fGradientBufferBinding = kUnassigned; |
| }; |
| |
| class Caps { |
| public: |
| virtual ~Caps(); |
| |
| const SkSL::ShaderCaps* shaderCaps() const { return fShaderCaps.get(); } |
| |
| sk_sp<SkCapabilities> capabilities() const; |
| |
| #if defined(GPU_TEST_UTILS) |
| std::string_view deviceName() const { return fDeviceName; } |
| |
| PathRendererStrategy requestedPathRendererStrategy() const { |
| return fRequestedPathRendererStrategy; |
| } |
| #endif |
| |
| /** |
| * TODO(b/390473370): Once backends initialize a Caps-level format table, these will not need |
| * to be virtual anymore: |
| */ |
| virtual bool isSampleCountSupported(TextureFormat, uint8_t requestedSampleCount) const = 0; |
| /* Return the TextureFormat that satisfies `dsFlags`. */ |
| virtual TextureFormat getDepthStencilFormat(SkEnumBitMask<DepthStencilFlags>) const = 0; |
| |
| virtual TextureInfo getDefaultAttachmentTextureInfo(AttachmentDesc, |
| Protected, |
| Discardable) const = 0; |
| |
| virtual TextureInfo getDefaultSampledTextureInfo(SkColorType, |
| Mipmapped, |
| Protected, |
| Renderable) const = 0; |
| |
| virtual TextureInfo getTextureInfoForSampledCopy(const TextureInfo&, |
| Mipmapped) const = 0; |
| |
| virtual TextureInfo getDefaultCompressedTextureInfo(SkTextureCompressionType, |
| Mipmapped, |
| Protected) const = 0; |
| |
| virtual TextureInfo getDefaultStorageTextureInfo(SkColorType) const = 0; |
| |
| /* Get required depth attachment dimensions for a givin color attachment info and dimensions. */ |
| virtual SkISize getDepthAttachmentDimensions(const TextureInfo&, |
| const SkISize colorAttachmentDimensions) const; |
| |
| virtual UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc&, |
| const RenderPassDesc&) const = 0; |
| virtual UniqueKey makeComputePipelineKey(const ComputePipelineDesc&) const = 0; |
| |
| |
| virtual bool extractGraphicsDescs(const UniqueKey&, |
| GraphicsPipelineDesc*, |
| RenderPassDesc*, |
| const RendererProvider*) const { return false; } |
| |
| bool areColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const; |
| |
| bool isTexturable(const TextureInfo&) const; |
| virtual bool isRenderable(const TextureInfo&) const = 0; |
| virtual bool isStorage(const TextureInfo&) const = 0; |
| |
| virtual bool loadOpAffectsMSAAPipelines() const { return false; } |
| |
| int maxTextureSize() const { return fMaxTextureSize; } |
| uint8_t defaultMSAASamplesCount() const { return fDefaultMSAASamples; } |
| |
| /** |
| * Returns the maximum number of varyings allowed in a render pipeline. Note that this is the |
| * number of varying variables, not the total number of varying scalars. |
| */ |
| int maxVaryings() const { return fMaxVaryings; } |
| |
| virtual void buildKeyForTexture(SkISize dimensions, |
| const TextureInfo&, |
| ResourceType, |
| 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 can optionally override this method to return meaningful sampler conversion info. |
| * By default, simply return a default ImmutableSamplerInfo (e.g. no immutable sampler). |
| */ |
| virtual ImmutableSamplerInfo getImmutableSamplerInfo(const TextureInfo&) const { |
| return {}; |
| } |
| |
| /** |
| * 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&) 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&) 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. |
| * |
| * We currently don't have an SkColorType for a 3 channel RGB format. Additionally the current |
| * implementation of raster pipeline requires power of 2 channels, so it is not easy to add such |
| * an SkColorType. Thus we need to check for data that is 3 channels using the isRGBFormat |
| * return value and handle it manually |
| */ |
| virtual std::pair<SkColorType, bool /*isRGB888Format*/> 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. |
| * |
| * We currently don't have an SkColorType for a 3 channel RGB format. Additionally the current |
| * implementation of raster pipeline requires power of 2 channels, so it is not easy to add such |
| * an SkColorType. Thus we need to check for data that is 3 channels using the isRGBFormat |
| * return value and handle it manually |
| */ |
| virtual std::pair<SkColorType, bool /*isRGBFormat*/> supportedReadPixelsColorType( |
| SkColorType srcColorType, |
| const TextureInfo& srcTextureInfo, |
| SkColorType dstColorType) const = 0; |
| |
| /** |
| * Checks whether the passed color type is renderable. If so, the same color type is passed |
| * back. If not, provides an alternative (perhaps lower bit depth and/or unorm instead of float) |
| * color type that is supported or kUnknown if there no renderable fallback format. |
| */ |
| SkColorType getRenderableColorType(SkColorType) const; |
| |
| /** |
| * Determines the orientation of the NDC coordinates emitted by the vertex stage relative to |
| * both Skia's presumed top-left Y-down system and the viewport coordinates (which are also |
| * always top-left, Y-down for all supported backends).) |
| * |
| * If true is returned, then (-1,-1) in normalized device coords maps to the top-left of the |
| * configured viewport and positive Y points down. This aligns with Skia's conventions. |
| * If false is returned, then (-1,-1) in NDC maps to the bottom-left of the viewport and |
| * positive Y points up (so NDC is flipped relative to sk_Position and the viewport coords). |
| * |
| * There is no backend difference in handling the X axis so it's assumed -1 maps to the left |
| * edge and +1 maps to the right edge. |
| */ |
| bool ndcYAxisPointsDown() const { return fNDCYAxisPointsDown; } |
| |
| bool clampToBorderSupport() const { return fClampToBorderSupport; } |
| |
| bool protectedSupport() const { return fProtectedSupport; } |
| |
| /* Supports BackendSemaphores */ |
| bool semaphoreSupport() const { return fSemaphoreSupport; } |
| |
| /* If false then calling Context::submit with SyncToCpu::kYes is an error. */ |
| bool allowCpuSync() const { return fAllowCpuSync; } |
| |
| /* Returns whether storage buffers are supported and to be preferred over uniform buffers. */ |
| bool storageBufferSupport() const { return fStorageBufferSupport; } |
| |
| /** |
| * The gradient buffer is an unsized float array so it is only optimal memory-wise to use it if |
| * the storage buffer memory layout is std430 or in metal, which is also the only supported |
| * way the data is packed. |
| */ |
| bool gradientBufferSupport() const { |
| return fStorageBufferSupport && |
| (fResourceBindingReqs.fStorageBufferLayout == Layout::kStd430 || |
| fResourceBindingReqs.fStorageBufferLayout == Layout::kMetal); |
| } |
| |
| /* Returns whether a draw buffer can be mapped. */ |
| bool drawBufferCanBeMapped() const { return fDrawBufferCanBeMapped; } |
| |
| #if defined(GPU_TEST_UTILS) |
| bool drawBufferCanBeMappedForReadback() const { return fDrawBufferCanBeMappedForReadback; } |
| #endif |
| |
| /** |
| * Returns whether using Buffer::asyncMap() must be used to map buffers. map() may only be |
| * called after asyncMap() is called and will fail if the asynchronous map is not complete. This |
| * excludes premapped buffers for which map() can be called freely until the first unmap() call. |
| */ |
| bool bufferMapsAreAsync() const { return fBufferMapsAreAsync; } |
| |
| /* Returns whether multisampled render to single sampled is supported. */ |
| bool msaaRenderToSingleSampledSupport() const { return fMSAARenderToSingleSampledSupport; } |
| |
| /* Returns whether multisampled render to single sampled is supported for a given texture. */ |
| virtual bool msaaTextureRenderToSingleSampledSupport(const TextureInfo& info) const { |
| return this->msaaRenderToSingleSampledSupport(); |
| } |
| |
| /** |
| * Returns whether a render pass can have MSAA/depth/stencil attachments and a resolve |
| * attachment with mismatched sizes. Note: the MSAA attachment and the depth/stencil attachment |
| * still need to match their sizes. |
| * This also implies supporting partial load/resolve. |
| */ |
| bool differentResolveAttachmentSizeSupport() const { |
| return fDifferentResolveAttachmentSizeSupport; |
| } |
| |
| /* Returns whether compute shaders are supported. */ |
| bool computeSupport() const { return fComputeSupport; } |
| |
| /** |
| * Returns true if the given backend supports importing AHardwareBuffers. This will only |
| * ever be supported on Android devices with API level >= 26. |
| */ |
| bool supportsAHardwareBufferImages() const { return fSupportsAHardwareBufferImages; } |
| |
| /** |
| * Enum representing the capabilities of the fixed function blend unit. |
| */ |
| enum BlendEquationSupport : uint8_t { |
| kBasic = 0, /* Default bare minimum support. Allows selecting the operator that |
| combines src + dst terms.*/ |
| kAdvancedNoncoherent, /* Additional fixed function support for specific SVG/PDF blend modes. |
| Requires blend barriers.*/ |
| kAdvancedCoherent /* Advanced blend equation support that does not require blend |
| barriers and permits overlap.*/ |
| }; |
| /** |
| * Return the level of hardware advanced blend mode support. |
| */ |
| BlendEquationSupport blendEquationSupport() const { return fBlendEqSupport; } |
| /** |
| * Simple helper for indicating whether the hardware supports advanced blend modes at all |
| * (coherent or noncoherent). |
| */ |
| bool supportsHardwareAdvancedBlending() const { |
| return fBlendEqSupport > BlendEquationSupport::kBasic; |
| } |
| |
| /** |
| * 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; |
| |
| /** |
| * Includes the following dynamic state: |
| * |
| * * Line width, depth bias, depth bounds, stencil compare mask, stencil write mask and stencil |
| * reference. |
| * This set corresponds to Vulkan 1.0 dynamic state. Blend constants does not depend on this |
| * flag as it is always dynamic with all graphite backends. |
| * |
| * * Depth test enable, depth write enable, depth compare op, depth bounds test enable, depth |
| * bias enable, stencil test enable and stencil op. |
| * This set corresponds to depth and stencil related state from VK_EXT_extended_dynamic_state |
| * and VK_EXT_extended_dynamic_state2. |
| * |
| * * Primitive topology and primitive restart enable. |
| * Note that the primitive topology _class_ is not dynamic. |
| * This set corresponds to input assembly state from VK_EXT_extended_dynamic_state and |
| * VK_EXT_extended_dynamic_state2. |
| * |
| * * Cull mode, front face and rasterizer discard. |
| * This set corresponds to rasterizer state from VK_EXT_extended_dynamic_state and |
| * VK_EXT_extended_dynamic_state2. |
| */ |
| bool useBasicDynamicState() const { return fUseBasicDynamicState; } |
| /** |
| * Whether all vertex input state is dynamic. |
| * This set corresponds to state from VK_EXT_vertex_input_dynamic_state. This state is |
| * equivalently pulled out of the shaders pipeline via VK_EXT_graphics_pipeline_library |
| * (usePipelineLibraries()). |
| */ |
| bool useVertexInputDynamicState() const { return fUseVertexInputDynamicState; } |
| /** |
| * Whether VK_EXT_graphics_pipeline_library should be used. In this case, the "shaders" subset |
| * of the pipeline is compiled separately, then fast-linked with the vertex input and fragment |
| * output state to create the final library. Currently, this is a detail of the Vulkan backend, |
| * which helps VkPipelineCache hits (because the shaders pipeline hits the cache, and blend |
| * state is patched in). However, this is most useful once exposed to the front-end, such that |
| * it can track the (fewer) shaders pipeline separately, have the complete pipelines point to |
| * the shaders pipeline, avoid unnecessary cache look ups, and more. (skbug.com/414645289) |
| */ |
| bool usePipelineLibraries() const { return fUsePipelineLibraries; } |
| |
| bool supportsHostImageCopy() const { return fSupportsHostImageCopy; } |
| |
| skgpu::ShaderErrorHandler* shaderErrorHandler() const { return fShaderErrorHandler; } |
| |
| /** |
| * Returns what method of dst read a draw should use for obtaining the dst color. Backends can |
| * use the default implementation or override this method as needed. |
| */ |
| virtual DstReadStrategy getDstReadStrategy() const; |
| |
| float minPathSizeForMSAA() const { return fMinMSAAPathSize; } |
| float minDistanceFieldFontSize() const { return fMinDistanceFieldFontSize; } |
| float glyphsAsPathsFontSize() const { return fGlyphsAsPathsFontSize; } |
| |
| size_t glyphCacheTextureMaximumBytes() const { return fGlyphCacheTextureMaximumBytes; } |
| int maxPathAtlasTextureSize() const { return fMaxPathAtlasTextureSize; } |
| |
| bool allowMultipleAtlasTextures() const { return fAllowMultipleAtlasTextures; } |
| bool supportBilerpFromGlyphAtlas() const { return fSupportBilerpFromGlyphAtlas; } |
| |
| bool requireOrderedRecordings() const { return fRequireOrderedRecordings; } |
| |
| /** |
| * When uploading to a full compressed texture do we need to pad the size out to a multiple of |
| * the block width and height. |
| */ |
| bool fullCompressedUploadSizeMustAlignToBlockDims() const { |
| return fFullCompressedUploadSizeMustAlignToBlockDims; |
| } |
| |
| sktext::gpu::SubRunControl getSubRunControl(bool useSDFTForSmallText) const; |
| |
| bool setBackendLabels() const { return fSetBackendLabels; } |
| |
| GpuStatsFlags supportedGpuStats() const { return fSupportedGpuStats; } |
| |
| 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&); |
| |
| #if defined(GPU_TEST_UTILS) |
| void setDeviceName(std::string n) { |
| fDeviceName = std::move(n); |
| } |
| #endif |
| |
| /** |
| * 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 { |
| ColorTypeInfo() = default; |
| ColorTypeInfo(SkColorType ct, SkColorType transferCt, uint32_t flags, |
| skgpu::Swizzle readSwizzle, skgpu::Swizzle writeSwizzle) |
| : fColorType(ct) |
| , fTransferColorType(transferCt) |
| , fFlags(flags) |
| , fReadSwizzle(readSwizzle) |
| , fWriteSwizzle(writeSwizzle) {} |
| |
| 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; |
| uint8_t fDefaultMSAASamples = 4; |
| size_t fRequiredUniformBufferAlignment = 0; |
| size_t fRequiredStorageBufferAlignment = 0; |
| size_t fRequiredTransferBufferAlignment = 0; |
| size_t fTextureDataRowBytesAlignment = 1; |
| |
| int fMaxVaryings = 0; |
| |
| std::unique_ptr<SkSL::ShaderCaps> fShaderCaps; |
| |
| bool fNDCYAxisPointsDown = false; // Most backends have NDC +Y pointing up |
| bool fClampToBorderSupport = true; |
| bool fProtectedSupport = false; |
| bool fSemaphoreSupport = false; |
| bool fAllowCpuSync = true; |
| bool fStorageBufferSupport = false; |
| bool fDrawBufferCanBeMapped = true; |
| bool fBufferMapsAreAsync = false; |
| bool fMSAARenderToSingleSampledSupport = false; |
| bool fDifferentResolveAttachmentSizeSupport = false; |
| |
| bool fComputeSupport = false; |
| bool fSupportsAHardwareBufferImages = false; |
| BlendEquationSupport fBlendEqSupport = BlendEquationSupport::kBasic; |
| bool fFullCompressedUploadSizeMustAlignToBlockDims = false; |
| |
| #if defined(GPU_TEST_UTILS) |
| bool fDrawBufferCanBeMappedForReadback = true; |
| #endif |
| |
| ResourceBindingRequirements fResourceBindingReqs; |
| |
| GpuStatsFlags fSupportedGpuStats = GpuStatsFlags::kNone; |
| |
| ////////////////////////////////////////////////////////////////////////////////////////// |
| // 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 defined(GPU_TEST_UTILS) |
| std::string fDeviceName; |
| int fMaxTextureAtlasSize = 2048; |
| PathRendererStrategy fRequestedPathRendererStrategy; |
| #endif |
| size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4; |
| |
| float fMinMSAAPathSize = 0; |
| float fMinDistanceFieldFontSize = 18; |
| float fGlyphsAsPathsFontSize = 324; |
| |
| int fMaxPathAtlasTextureSize = 8192; |
| |
| bool fAllowMultipleAtlasTextures = true; |
| bool fSupportBilerpFromGlyphAtlas = false; |
| |
| bool fRequireOrderedRecordings = false; |
| |
| bool fSetBackendLabels = false; |
| |
| // Dynamic state. The granularity is less fine than Vulkan's, but there is still some |
| // granularity to allow for some dynamic state to be disabled due to driver bugs without having |
| // to disable everything. Eventually, these can be used to create fewer pipelines in the first |
| // place (b/414645289). |
| bool fUseBasicDynamicState = false; |
| bool fUseVertexInputDynamicState = false; |
| bool fUsePipelineLibraries = false; |
| |
| // Whether it's possible to upload data to images using the CPU (host) instead of the device. |
| // Under certain circumstances, it's more efficient to upload data in this way instead of |
| // through a staging buffer. |
| bool fSupportsHostImageCopy = false; |
| |
| private: |
| virtual bool onIsTexturable(const TextureInfo&) const = 0; |
| virtual const ColorTypeInfo* getColorTypeInfo(SkColorType, const TextureInfo&) const = 0; |
| |
| sk_sp<SkCapabilities> fCapabilities; |
| }; |
| |
| } // namespace skgpu::graphite |
| |
| #endif // skgpu_graphite_Caps_DEFINED |