/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrCaps_DEFINED #define GrCaps_DEFINED #include "include/core/SkImageInfo.h" #include "include/core/SkRefCnt.h" #include "include/core/SkString.h" #include "include/gpu/GrDriverBugWorkarounds.h" #include "include/private/GrTypesPriv.h" #include "src/core/SkCompressedDataUtils.h" #include "src/gpu/GrBlend.h" #include "src/gpu/GrSamplerState.h" #include "src/gpu/GrShaderCaps.h" #include "src/gpu/GrSurfaceProxy.h" class GrBackendFormat; class GrBackendRenderTarget; class GrBackendTexture; struct GrContextOptions; class GrProcessorKeyBuilder; class GrProgramDesc; class GrProgramInfo; class GrRenderTargetProxy; class GrSurface; class SkJSONWriter; /** * Represents the capabilities of a GrContext. */ class GrCaps : public SkRefCnt { public: GrCaps(const GrContextOptions&); void dumpJSON(SkJSONWriter*) const; const GrShaderCaps* shaderCaps() const { return fShaderCaps.get(); } sk_sp refShaderCaps() const { return fShaderCaps; } bool npotTextureTileSupport() const { return fNPOTTextureTileSupport; } /** To avoid as-yet-unnecessary complexity we don't allow any partial support of MIP Maps (e.g. only for POT textures) */ bool mipmapSupport() const { return fMipmapSupport; } bool gpuTracingSupport() const { return fGpuTracingSupport; } bool oversizedStencilSupport() const { return fOversizedStencilSupport; } bool textureBarrierSupport() const { return fTextureBarrierSupport; } bool sampleLocationsSupport() const { return fSampleLocationsSupport; } bool multisampleDisableSupport() const { return fMultisampleDisableSupport; } bool drawInstancedSupport() const { return fDrawInstancedSupport; } // Is there hardware support for indirect draws? (Ganesh always supports indirect draws as long // as it can polyfill them with instanced calls, but this cap tells us if they are supported // natively.) bool nativeDrawIndirectSupport() const { return fNativeDrawIndirectSupport; } bool useClientSideIndirectBuffers() const { #ifdef SK_DEBUG if (!fNativeDrawIndirectSupport || fNativeDrawIndexedIndirectIsBroken) { // We might implement indirect draws with a polyfill, so the commands need to reside in // CPU memory. SkASSERT(fUseClientSideIndirectBuffers); } #endif return fUseClientSideIndirectBuffers; } bool conservativeRasterSupport() const { return fConservativeRasterSupport; } bool wireframeSupport() const { return fWireframeSupport; } // This flag indicates that we never have to resolve MSAA. In practice, it means that we have // an MSAA-render-to-texture extension: Any render target we create internally will use the // extension, and any wrapped render target is the client's responsibility. bool msaaResolvesAutomatically() const { return fMSAAResolvesAutomatically; } bool halfFloatVertexAttributeSupport() const { return fHalfFloatVertexAttributeSupport; } // Primitive restart functionality is core in ES 3.0, but using it will cause slowdowns on some // systems. This cap is only set if primitive restart will improve performance. bool usePrimitiveRestart() const { return fUsePrimitiveRestart; } bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; } // On tilers, an initial fullscreen clear is an OPTIMIZATION. It allows the hardware to // initialize each tile with a constant value rather than loading each pixel from memory. bool preferFullscreenClears() const { return fPreferFullscreenClears; } // Should we discard stencil values after a render pass? (Tilers get better performance if we // always load stencil buffers with a "clear" op, and then discard the content when finished.) bool discardStencilValuesAfterRenderPass() const { // b/160958008 return false; #if 0 // This method is actually just a duplicate of preferFullscreenClears(), with a descriptive // name for the sake of readability. return this->preferFullscreenClears(); #endif } // D3D does not allow the refs or masks to differ on a two-sided stencil draw. bool twoSidedStencilRefsAndMasksMustMatch() const { return fTwoSidedStencilRefsAndMasksMustMatch; } bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; } bool avoidStencilBuffers() const { return fAvoidStencilBuffers; } bool avoidWritePixelsFastPath() const { return fAvoidWritePixelsFastPath; } // http://skbug.com/9739 bool requiresManualFBBarrierAfterTessellatedStencilDraw() const { return fRequiresManualFBBarrierAfterTessellatedStencilDraw; } // glDrawElementsIndirect fails GrMeshTest on every Win10 Intel bot. bool nativeDrawIndexedIndirectIsBroken() const { return fNativeDrawIndexedIndirectIsBroken; } /** * Indicates the capabilities of the fixed function blend unit. */ enum BlendEquationSupport { kBasic_BlendEquationSupport, //= kAdvanced_BlendEquationSupport; } bool advancedCoherentBlendEquationSupport() const { return kAdvancedCoherent_BlendEquationSupport == fBlendEquationSupport; } bool isAdvancedBlendEquationDisabled(GrBlendEquation equation) const { SkASSERT(GrBlendEquationIsAdvanced(equation)); SkASSERT(this->advancedBlendEquationSupport()); return SkToBool(fAdvBlendEqDisableFlags & (1 << equation)); } // On some GPUs it is a performance win to disable blending instead of doing src-over with a src // alpha equal to 1. To disable blending we collapse src-over to src and the backends will // handle the disabling of blending. bool shouldCollapseSrcOverToSrcWhenAble() const { return fShouldCollapseSrcOverToSrcWhenAble; } // When abandoning the GrDirectContext do we need to sync the GPU before we start abandoning // resources. bool mustSyncGpuDuringAbandon() const { return fMustSyncGpuDuringAbandon; } // Shortcut for shaderCaps()->reducedShaderMode(). bool reducedShaderMode() const { return this->shaderCaps()->reducedShaderMode(); } /** * Indicates whether GPU->CPU memory mapping for GPU resources such as vertex buffers and * textures allows partial mappings or full mappings. */ enum MapFlags { kNone_MapFlags = 0x0, //maxWindowRectangles() > 0 && this->onIsWindowRectanglesSupportedForRT(rt); } uint32_t maxPushConstantsSize() const { return fMaxPushConstantsSize; } virtual bool isFormatSRGB(const GrBackendFormat&) const = 0; bool isFormatCompressed(const GrBackendFormat& format) const; // Can a texture be made with the GrBackendFormat, and then be bound and sampled in a shader. virtual bool isFormatTexturable(const GrBackendFormat&) const = 0; // Returns whether a texture of the given format can be copied to a texture of the same format. virtual bool isFormatCopyable(const GrBackendFormat&) const = 0; // Returns the maximum supported sample count for a format. 0 means the format is not renderable // 1 means the format is renderable but doesn't support MSAA. virtual int maxRenderTargetSampleCount(const GrBackendFormat&) const = 0; // Returns the number of samples to use when performing draws to the given config with internal // MSAA. If 0, Ganesh should not attempt to use internal multisampling. int internalMultisampleCount(const GrBackendFormat& format) const { return std::min(fInternalMultisampleCount, this->maxRenderTargetSampleCount(format)); } virtual bool isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format, int sampleCount = 1) const = 0; virtual bool isFormatRenderable(const GrBackendFormat& format, int sampleCount) const = 0; // Find a sample count greater than or equal to the requested count which is supported for a // render target of the given format or 0 if no such sample count is supported. If the requested // sample count is 1 then 1 will be returned if non-MSAA rendering is supported, otherwise 0. // For historical reasons requestedCount==0 is handled identically to requestedCount==1. virtual int getRenderTargetSampleCount(int requestedCount, const GrBackendFormat&) const = 0; /** * Backends may have restrictions on what types of surfaces support GrGpu::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. */ bool surfaceSupportsWritePixels(const GrSurface*) const; /** * Indicates whether surface supports GrGpu::readPixels, must be copied, or cannot be read. */ enum class SurfaceReadPixelsSupport { /** GrGpu::readPixels is supported by the surface. */ kSupported, /** * GrGpu::readPixels is not supported by this surface but this surface can be drawn * or copied to a Ganesh-created GrTextureType::kTexture2D and then that surface will be * readable. */ kCopyToTexture2D, /** * Not supported */ kUnsupported, }; /** * Backends may have restrictions on what types of surfaces support GrGpu::readPixels(). We may * either be able to read directly from the surface, read from a copy of the surface, or not * read at all. */ virtual SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const = 0; struct SupportedWrite { GrColorType fColorType; // If the write is occurring using GrGpu::transferPixelsTo then this provides the // minimum alignment of the offset into the transfer buffer. size_t fOffsetAlignmentForTransferBuffer; }; /** * 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 GrGpu::writePixels(). */ virtual SupportedWrite supportedWritePixelsColorType(GrColorType surfaceColorType, const GrBackendFormat& surfaceFormat, GrColorType srcColorType) const = 0; struct SupportedRead { GrColorType fColorType; // If the read is occurring using GrGpu::transferPixelsFrom then this provides the // minimum alignment of the offset into the transfer buffer. size_t fOffsetAlignmentForTransferBuffer; }; /** * Given a src surface's color type and its backend format as well as a color type the caller * would like read into, this provides a legal color type that the caller may pass to * GrGpu::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. */ SupportedRead supportedReadPixelsColorType(GrColorType srcColorType, const GrBackendFormat& srcFormat, GrColorType dstColorType) const; /** * Do GrGpu::writePixels() and GrGpu::transferPixelsTo() support a src buffer where the row * bytes is not equal to bpp * w? */ bool writePixelsRowBytesSupport() const { return fWritePixelsRowBytesSupport; } /** * Does GrGpu::readPixels() support a dst buffer where the row bytes is not equal to bpp * w? */ bool readPixelsRowBytesSupport() const { return fReadPixelsRowBytesSupport; } bool transferFromSurfaceToBufferSupport() const { return fTransferFromSurfaceToBufferSupport; } bool transferFromBufferToTextureSupport() const { return fTransferFromBufferToTextureSupport; } bool suppressPrints() const { return fSuppressPrints; } size_t bufferMapThreshold() const { SkASSERT(fBufferMapThreshold >= 0); return fBufferMapThreshold; } /** True in environments that will issue errors if memory uploaded to buffers is not initialized (even if not read by draw calls). */ bool mustClearUploadedBufferData() const { return fMustClearUploadedBufferData; } /** For some environments, there is a performance or safety concern to not initializing textures. For example, with WebGL and Firefox, there is a large performance hit to not doing it. */ bool shouldInitializeTextures() const { return fShouldInitializeTextures; } /** Returns true if the given backend supports importing AHardwareBuffers via the * GrAHardwarebufferImageGenerator. This will only ever be supported on Android devices with API * level >= 26. * */ bool supportsAHardwareBufferImages() const { return fSupportsAHardwareBufferImages; } bool wireframeMode() const { return fWireframeMode; } /** Supports using GrFence. */ bool fenceSyncSupport() const { return fFenceSyncSupport; } /** Supports using GrSemaphore. */ bool semaphoreSupport() const { return fSemaphoreSupport; } bool crossContextTextureSupport() const { return fCrossContextTextureSupport; } /** * Returns whether or not we will be able to do a copy given the passed in params */ bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const; bool dynamicStateArrayGeometryProcessorTextureSupport() const { return fDynamicStateArrayGeometryProcessorTextureSupport; } // Not all backends support clearing with a scissor test (e.g. Metal), this will always // return true if performColorClearsAsDraws() returns true. bool performPartialClearsAsDraws() const { return fPerformColorClearsAsDraws || fPerformPartialClearsAsDraws; } // Many drivers have issues with color clears. bool performColorClearsAsDraws() const { return fPerformColorClearsAsDraws; } bool avoidLargeIndexBufferDraws() const { return fAvoidLargeIndexBufferDraws; } /// Adreno 4xx devices experience an issue when there are a large number of stencil clip bit /// clears. The minimal repro steps are not precisely known but drawing a rect with a stencil /// op instead of using glClear seems to resolve the issue. bool performStencilClearsAsDraws() const { return fPerformStencilClearsAsDraws; } // Should we disable the clip mask atlas due to a faulty driver? bool driverDisableMSAAClipAtlas() const { return fDriverDisableMSAAClipAtlas; } // Should we disable GrTessellationPathRenderer due to a faulty driver? bool disableTessellationPathRenderer() const { return fDisableTessellationPathRenderer; } // Returns how to sample the dst values for the passed in GrRenderTargetProxy. GrDstSampleType getDstSampleTypeForProxy(const GrRenderTargetProxy*) const; /** * This is used to try to ensure a successful copy a dst in order to perform shader-based * blending. * * fRectsMustMatch will be set to true if the copy operation must ensure that the src and dest * rects are identical. * * fMustCopyWholeSrc will be set to true if copy rect must equal src's bounds. * * Caller will detect cases when copy cannot succeed and try copy-as-draw as a fallback. */ struct DstCopyRestrictions { GrSurfaceProxy::RectsMustMatch fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kNo; bool fMustCopyWholeSrc = false; }; virtual DstCopyRestrictions getDstCopyRestrictions(const GrRenderTargetProxy* src, GrColorType ct) const { return {}; } bool validateSurfaceParams(const SkISize&, const GrBackendFormat&, GrRenderable renderable, int renderTargetSampleCnt, GrMipmapped) const; bool areColorTypeAndFormatCompatible(GrColorType grCT, const GrBackendFormat& format) const; /** These are used when creating a new texture internally. */ GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const; virtual GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const = 0; /** * The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and * GLES 3.2, but is also available in extensions. Vulkan and Metal always have support. */ bool clampToBorderSupport() const { return fClampToBorderSupport; } /** * Returns the GrSwizzle to use when sampling or reading back from a texture with the passed in * GrBackendFormat and GrColorType. */ GrSwizzle getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const; /** * Returns the GrSwizzle to use when writing colors to a surface with the passed in * GrBackendFormat and GrColorType. */ virtual GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const = 0; virtual uint64_t computeFormatKey(const GrBackendFormat&) const = 0; const GrDriverBugWorkarounds& workarounds() const { return fDriverBugWorkarounds; } /** * Adds fields to the key to represent the sampler that will be created for the passed * in parameters. Currently this extra keying is only needed when building a vulkan pipeline * with immutable samplers. */ virtual void addExtraSamplerKey(GrProcessorKeyBuilder*, GrSamplerState, const GrBackendFormat&) const {} enum class ProgramDescOverrideFlags { kNone = 0, // If using discardable msaa surfaces in vulkan, when we break up a render pass for an // inline upload, we must do a load msaa subpass for the second render pass. However, if the // original render pass did not have this load subpass (e.g. clear or discard load op), then // all the GrProgramInfos for draws that end up in the second render pass will have been // recorded thinking they will be in a render pass with only 1 subpass. Thus we add an // override flag to the makeDesc call to force the actually VkPipeline that gets created to // be created using a render pass with 2 subpasses. We do miss on the pre-compile with this // approach, but inline uploads are very rare and already slow. kVulkanHasResolveLoadSubpass = 0x1, }; GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(ProgramDescOverrideFlags); virtual GrProgramDesc makeDesc( GrRenderTarget*, const GrProgramInfo&, ProgramDescOverrideFlags overrideFlags = ProgramDescOverrideFlags::kNone) const = 0; // This method specifies, for each backend, the extra properties of a RT when Ganesh creates one // internally. For example, for Vulkan, Ganesh always creates RTs that can be used as input // attachments. virtual GrInternalSurfaceFlags getExtraSurfaceFlagsForDeferredRT() const { return GrInternalSurfaceFlags::kNone; } bool supportsDynamicMSAA(const GrRenderTargetProxy*) const; // skbug.com/11935. Task reordering is disabled for some GPUs on GL due to driver bugs. bool avoidReorderingRenderTasks() const { return fAvoidReorderingRenderTasks; } #if GR_TEST_UTILS struct TestFormatColorTypeCombination { GrColorType fColorType; GrBackendFormat fFormat; }; virtual std::vector getTestingCombinations() const = 0; #endif protected: // Subclasses must call this at the end of their init method in order to do final processing on // the caps (including overrides requested by the client). // NOTE: this method will only reduce the caps, never expand them. void finishInitialization(const GrContextOptions& options); virtual bool onSupportsDynamicMSAA(const GrRenderTargetProxy*) const { return false; } sk_sp fShaderCaps; bool fNPOTTextureTileSupport : 1; bool fMipmapSupport : 1; bool fReuseScratchTextures : 1; bool fReuseScratchBuffers : 1; bool fGpuTracingSupport : 1; bool fOversizedStencilSupport : 1; bool fTextureBarrierSupport : 1; bool fSampleLocationsSupport : 1; bool fMultisampleDisableSupport : 1; bool fDrawInstancedSupport : 1; bool fNativeDrawIndirectSupport : 1; bool fUseClientSideIndirectBuffers : 1; bool fConservativeRasterSupport : 1; bool fWireframeSupport : 1; bool fMSAAResolvesAutomatically : 1; bool fUsePrimitiveRestart : 1; bool fPreferClientSideDynamicBuffers : 1; bool fPreferFullscreenClears : 1; bool fTwoSidedStencilRefsAndMasksMustMatch : 1; bool fMustClearUploadedBufferData : 1; bool fShouldInitializeTextures : 1; bool fSupportsAHardwareBufferImages : 1; bool fHalfFloatVertexAttributeSupport : 1; bool fClampToBorderSupport : 1; bool fPerformPartialClearsAsDraws : 1; bool fPerformColorClearsAsDraws : 1; bool fAvoidLargeIndexBufferDraws : 1; bool fPerformStencilClearsAsDraws : 1; bool fTransferFromBufferToTextureSupport : 1; bool fTransferFromSurfaceToBufferSupport : 1; bool fWritePixelsRowBytesSupport : 1; bool fReadPixelsRowBytesSupport : 1; bool fShouldCollapseSrcOverToSrcWhenAble : 1; bool fMustSyncGpuDuringAbandon : 1; // Driver workaround bool fDriverDisableMSAAClipAtlas : 1; bool fDisableTessellationPathRenderer : 1; bool fAvoidStencilBuffers : 1; bool fAvoidWritePixelsFastPath : 1; bool fRequiresManualFBBarrierAfterTessellatedStencilDraw : 1; bool fNativeDrawIndexedIndirectIsBroken : 1; bool fAvoidReorderingRenderTasks : 1; // ANGLE performance workaround bool fPreferVRAMUseOverFlushes : 1; bool fFenceSyncSupport : 1; bool fSemaphoreSupport : 1; // Requires fence sync support in GL. bool fCrossContextTextureSupport : 1; // Not (yet) implemented in VK backend. bool fDynamicStateArrayGeometryProcessorTextureSupport : 1; BlendEquationSupport fBlendEquationSupport; uint32_t fAdvBlendEqDisableFlags; static_assert(kLast_GrBlendEquation < 32); uint32_t fMapBufferFlags; int fBufferMapThreshold; int fMaxRenderTargetSize; int fMaxPreferredRenderTargetSize; int fMaxVertexAttributes; int fMaxTextureSize; int fMaxWindowRectangles; int fInternalMultisampleCount; uint32_t fMaxPushConstantsSize = 0; GrDriverBugWorkarounds fDriverBugWorkarounds; private: void applyOptionsOverrides(const GrContextOptions& options); virtual void onApplyOptionsOverrides(const GrContextOptions&) {} virtual void onDumpJSON(SkJSONWriter*) const {} virtual bool onSurfaceSupportsWritePixels(const GrSurface*) const = 0; virtual bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const = 0; virtual GrBackendFormat onGetDefaultBackendFormat(GrColorType) const = 0; // Backends should implement this if they have any extra requirements for use of window // rectangles for a specific GrBackendRenderTarget outside of basic support. virtual bool onIsWindowRectanglesSupportedForRT(const GrBackendRenderTarget&) const { return true; } virtual bool onAreColorTypeAndFormatCompatible(GrColorType, const GrBackendFormat&) const = 0; virtual SupportedRead onSupportedReadPixelsColorType(GrColorType srcColorType, const GrBackendFormat& srcFormat, GrColorType dstColorType) const = 0; virtual GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const = 0; virtual GrDstSampleType onGetDstSampleTypeForProxy(const GrRenderTargetProxy*) const { return GrDstSampleType::kAsTextureCopy; } bool fSuppressPrints : 1; bool fWireframeMode : 1; using INHERITED = SkRefCnt; }; GR_MAKE_BITFIELD_CLASS_OPS(GrCaps::ProgramDescOverrideFlags); #endif