Add flag to avoid stencil buffers in Skia
Certain systems experience a leak in the GL driver associated with stencil buffers. Attempts to avoid the leak (while still using stencil buffers) dind't succeed. This patch adds a GrContextOption fAvoidStencilBuffers. This disables certain path rendering modes, as well as stencil based masking/clipping. Bug: 713854 Change-Id: Ifa6c0f2bd5ee395547bda9165d6c79d197ae8b8b Reviewed-on: https://skia-review.googlesource.com/15253 Commit-Queue: Eric Karl <ericrk@chromium.org> Reviewed-by: Eric Karl <ericrk@chromium.org> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
fda4600e41
commit
5c77975e4c
@ -79,6 +79,8 @@ public:
|
||||
|
||||
bool avoidInstancedDrawsToFPTargets() const { return fAvoidInstancedDrawsToFPTargets; }
|
||||
|
||||
bool avoidStencilBuffers() const { return fAvoidStencilBuffers; }
|
||||
|
||||
/**
|
||||
* Indicates the capabilities of the fixed function blend unit.
|
||||
*/
|
||||
@ -225,6 +227,7 @@ protected:
|
||||
bool fUseDrawInsteadOfPartialRenderTargetWrite : 1;
|
||||
bool fUseDrawInsteadOfAllRenderTargetWrites : 1;
|
||||
bool fAvoidInstancedDrawsToFPTargets : 1;
|
||||
bool fAvoidStencilBuffers : 1;
|
||||
|
||||
// ANGLE workaround
|
||||
bool fPreferVRAMUseOverFlushes : 1;
|
||||
|
@ -110,6 +110,12 @@ struct GrContextOptions {
|
||||
* The maximum size of cache textures used for Skia's Glyph cache.
|
||||
*/
|
||||
float fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
|
||||
|
||||
/**
|
||||
* Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid
|
||||
* allocating stencil buffers and use alternate rasterization paths, avoiding the leak.
|
||||
*/
|
||||
bool fAvoidStencilBuffers = false;
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(GrContextOptions::GpuPathRenderers)
|
||||
|
@ -77,6 +77,7 @@ GrCaps::GrCaps(const GrContextOptions& options) {
|
||||
fUseDrawInsteadOfPartialRenderTargetWrite = options.fUseDrawInsteadOfPartialRenderTargetWrite;
|
||||
fUseDrawInsteadOfAllRenderTargetWrites = false;
|
||||
fAvoidInstancedDrawsToFPTargets = false;
|
||||
fAvoidStencilBuffers = false;
|
||||
|
||||
fPreferVRAMUseOverFlushes = true;
|
||||
}
|
||||
@ -95,6 +96,7 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
|
||||
GrWindowRectangles::kMaxWindows, fMaxWindowRectangles);
|
||||
fMaxWindowRectangles = GrWindowRectangles::kMaxWindows;
|
||||
}
|
||||
fAvoidStencilBuffers = options.fAvoidStencilBuffers;
|
||||
}
|
||||
|
||||
static SkString map_flags_to_string(uint32_t flags) {
|
||||
|
@ -115,7 +115,7 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
|
||||
|
||||
GrShape shape(path, GrStyle::SimpleFill());
|
||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||
canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
|
||||
canDrawArgs.fCaps = context->caps();
|
||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||
canDrawArgs.fShape = &shape;
|
||||
if (!element->isAA()) {
|
||||
@ -152,6 +152,10 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
|
||||
// a clip gets complex enough it can just be done in SW regardless
|
||||
// of whether it would invoke the GrSoftwarePathRenderer.
|
||||
|
||||
// If we're avoiding stencils, always use SW:
|
||||
if (context->caps()->avoidStencilBuffers())
|
||||
return true;
|
||||
|
||||
// Set the matrix so that rendered clip elements are transformed to mask space from clip
|
||||
// space.
|
||||
SkMatrix translate;
|
||||
@ -283,6 +287,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
SkASSERT(rtIBounds.contains(clipIBounds)); // Mask shouldn't be larger than the RT.
|
||||
#endif
|
||||
|
||||
bool avoidStencilBuffers = context->caps()->avoidStencilBuffers();
|
||||
|
||||
// An element count of 4 was chosen because of the common pattern in Blink of:
|
||||
// isect RR
|
||||
// diff RR
|
||||
@ -294,7 +300,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
if (reducedClip.elements().count() <= kMaxAnalyticElements) {
|
||||
// When there are multiple samples we want to do per-sample clipping, not compute a
|
||||
// fractional pixel coverage.
|
||||
bool disallowAnalyticAA = renderTargetContext->isStencilBufferMultisampled();
|
||||
bool disallowAnalyticAA = renderTargetContext->isStencilBufferMultisampled() &&
|
||||
!avoidStencilBuffers;
|
||||
if (disallowAnalyticAA && !renderTargetContext->numColorSamples()) {
|
||||
// With a single color sample, any coverage info is lost from color once it hits the
|
||||
// color buffer anyway, so we may as well use coverage AA if nothing else in the pipe
|
||||
@ -302,7 +309,7 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
disallowAnalyticAA = useHWAA || hasUserStencilSettings;
|
||||
}
|
||||
sk_sp<GrFragmentProcessor> clipFP;
|
||||
if (reducedClip.requiresAA() &&
|
||||
if ((reducedClip.requiresAA() || avoidStencilBuffers) &&
|
||||
get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA, devBounds,
|
||||
&clipFP)) {
|
||||
out->addCoverageFP(std::move(clipFP));
|
||||
@ -311,7 +318,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
}
|
||||
|
||||
// If the stencil buffer is multisampled we can use it to do everything.
|
||||
if (!renderTargetContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) {
|
||||
if ((!renderTargetContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) ||
|
||||
avoidStencilBuffers) {
|
||||
sk_sp<GrTextureProxy> result;
|
||||
if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
|
||||
// The clip geometry is complex enough that it will be more efficient to create it
|
||||
@ -328,7 +336,13 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
reducedClip.ibounds()));
|
||||
return true;
|
||||
}
|
||||
// if alpha clip mask creation fails fall through to the non-AA code paths
|
||||
|
||||
// If alpha or software clip mask creation fails, fall through to the stencil code paths,
|
||||
// unless stencils are disallowed.
|
||||
if (context->caps()->avoidStencilBuffers()) {
|
||||
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. Clip will be ignored.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GrRenderTarget* rt = renderTargetContext->accessRenderTarget();
|
||||
|
@ -197,10 +197,13 @@ sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
|
||||
if (!tex) {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: defer this and attach dynamically
|
||||
GrRenderTarget* tgt = tex->asRenderTarget();
|
||||
if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) {
|
||||
return nullptr;
|
||||
|
||||
if (!this->caps()->avoidStencilBuffers()) {
|
||||
// TODO: defer this and attach dynamically
|
||||
GrRenderTarget* tgt = tex->asRenderTarget();
|
||||
if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
@ -74,14 +74,14 @@ public:
|
||||
|
||||
/** Args to canDrawPath()
|
||||
*
|
||||
* fShaderCaps The shader caps
|
||||
* fCaps The context caps
|
||||
* fPipelineBuilder The pipelineBuilder
|
||||
* fViewMatrix The viewMatrix
|
||||
* fShape The shape to draw
|
||||
* fAntiAlias The type of anti aliasing required.
|
||||
*/
|
||||
struct CanDrawPathArgs {
|
||||
const GrShaderCaps* fShaderCaps;
|
||||
const GrCaps* fCaps;
|
||||
const SkMatrix* fViewMatrix;
|
||||
const GrShape* fShape;
|
||||
GrAAType fAAType;
|
||||
@ -91,7 +91,7 @@ public:
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void validate() const {
|
||||
SkASSERT(fShaderCaps);
|
||||
SkASSERT(fCaps);
|
||||
SkASSERT(fViewMatrix);
|
||||
SkASSERT(fShape);
|
||||
}
|
||||
@ -153,7 +153,7 @@ public:
|
||||
SkDEBUGCODE(args.validate();)
|
||||
#ifdef SK_DEBUG
|
||||
CanDrawPathArgs canArgs;
|
||||
canArgs.fShaderCaps = args.fContext->caps()->shaderCaps();
|
||||
canArgs.fCaps = args.fContext->caps();
|
||||
canArgs.fViewMatrix = args.fViewMatrix;
|
||||
canArgs.fShape = args.fShape;
|
||||
canArgs.fAAType = args.fAAType;
|
||||
|
@ -730,7 +730,7 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context,
|
||||
|
||||
GrShape shape(clipPath, GrStyle::SimpleFill());
|
||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||
canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
|
||||
canDrawArgs.fCaps = context->caps();
|
||||
canDrawArgs.fViewMatrix = &SkMatrix::I();
|
||||
canDrawArgs.fShape = &shape;
|
||||
canDrawArgs.fAAType = aaType;
|
||||
|
@ -1425,8 +1425,7 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrClip& clip,
|
||||
|
||||
GrShape shape(path, GrStyle::SimpleFill());
|
||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||
canDrawArgs.fShaderCaps =
|
||||
fRenderTargetContext->drawingManager()->getContext()->caps()->shaderCaps();
|
||||
canDrawArgs.fCaps = fRenderTargetContext->drawingManager()->getContext()->caps();
|
||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||
canDrawArgs.fShape = &shape;
|
||||
canDrawArgs.fAAType = aaType;
|
||||
@ -1487,7 +1486,7 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
|
||||
aaType = GrAAType::kCoverage;
|
||||
}
|
||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||
canDrawArgs.fShaderCaps = this->drawingManager()->getContext()->caps()->shaderCaps();
|
||||
canDrawArgs.fCaps = this->drawingManager()->getContext()->caps();
|
||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||
canDrawArgs.fShape = &shape;
|
||||
canDrawArgs.fHasUserStencilSettings = false;
|
||||
|
@ -136,7 +136,9 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
bool inverseFilled = false;
|
||||
SkTLazy<GrShape> tmpShape;
|
||||
SkASSERT(!args.fShape->style().applies());
|
||||
inverseFilled = args.fShape->inverseFilled();
|
||||
// If the path is hairline, ignore inverse fill.
|
||||
inverseFilled = args.fShape->inverseFilled() &&
|
||||
!IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr);
|
||||
|
||||
SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds;
|
||||
// To prevent overloading the cache with entries during animations we limit the cache of masks
|
||||
|
@ -344,23 +344,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
* GrCaps fields
|
||||
**************************************************************************/
|
||||
|
||||
// We need dual source blending and the ability to disable multisample in order to support mixed
|
||||
// samples in every corner case. We only use mixed samples if the stencil-and-cover path
|
||||
// renderer is available and enabled; no other path renderers support this feature.
|
||||
if (fMultisampleDisableSupport &&
|
||||
shaderCaps->dualSourceBlendingSupport() &&
|
||||
fShaderCaps->pathRenderingSupport() &&
|
||||
(contextOptions.fGpuPathRenderers & GrContextOptions::GpuPathRenderers::kStencilAndCover)) {
|
||||
fUsesMixedSamples = ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") ||
|
||||
ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_mixed_samples");
|
||||
// Workaround NVIDIA bug related to glInvalidateFramebuffer and mixed samples.
|
||||
if (fUsesMixedSamples && (kNVIDIA_GrGLDriver == ctxInfo.driver() ||
|
||||
kChromium_GrGLDriver == ctxInfo.driver())) {
|
||||
fDiscardRenderTargetSupport = false;
|
||||
fInvalidateFBType = kNone_InvalidateFBType;
|
||||
}
|
||||
}
|
||||
|
||||
// SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with
|
||||
// frequently changing VBOs. We've measured a performance increase using non-VBO vertex
|
||||
// data for dynamic content on these GPUs. Perhaps we should read the renderer string and
|
||||
@ -373,11 +356,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
fPreferClientSideDynamicBuffers = true;
|
||||
}
|
||||
|
||||
// fUsesMixedSamples must be set before calling initFSAASupport.
|
||||
this->initFSAASupport(ctxInfo, gli);
|
||||
if (!contextOptions.fAvoidStencilBuffers) {
|
||||
// To reduce surface area, if we avoid stencil buffers, we also disable MSAA.
|
||||
this->initFSAASupport(contextOptions, ctxInfo, gli);
|
||||
this->initStencilSupport(ctxInfo);
|
||||
}
|
||||
this->initBlendEqationSupport(ctxInfo);
|
||||
this->initStencilFormats(ctxInfo);
|
||||
|
||||
|
||||
if (kGL_GrGLStandard == standard) {
|
||||
fMapBufferFlags = kCanMap_MapFlag; // we require VBO support and the desktop VBO
|
||||
@ -464,21 +448,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
kQualcomm_GrGLVendor != ctxInfo.vendor();
|
||||
#endif
|
||||
|
||||
// initFSAASupport() must have been called before this point
|
||||
if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &fMaxStencilSampleCount);
|
||||
} else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &fMaxStencilSampleCount);
|
||||
}
|
||||
// We only have a use for raster multisample if there is coverage modulation from mixed samples.
|
||||
if (fUsesMixedSamples && ctxInfo.hasExtension("GL_EXT_raster_multisample")) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_RASTER_SAMPLES, &fMaxRasterSamples);
|
||||
// This is to guard against platforms that may not support as many samples for
|
||||
// glRasterSamples as they do for framebuffers.
|
||||
fMaxStencilSampleCount = SkTMin(fMaxStencilSampleCount, fMaxRasterSamples);
|
||||
}
|
||||
fMaxColorSampleCount = fMaxStencilSampleCount;
|
||||
|
||||
if (ctxInfo.hasExtension("GL_EXT_window_rectangles")) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_WINDOW_RECTANGLES, &fMaxWindowRectangles);
|
||||
}
|
||||
@ -982,7 +951,25 @@ bool GrGLCaps::readPixelsSupported(GrPixelConfig surfaceConfig,
|
||||
fConfigTable[surfaceConfig].fSecondReadPixelsFormat.fType == readType;
|
||||
}
|
||||
|
||||
void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
void GrGLCaps::initFSAASupport(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo,
|
||||
const GrGLInterface* gli) {
|
||||
// We need dual source blending and the ability to disable multisample in order to support mixed
|
||||
// samples in every corner case. We only use mixed samples if the stencil-and-cover path
|
||||
// renderer is available and enabled; no other path renderers support this feature.
|
||||
if (fMultisampleDisableSupport &&
|
||||
this->shaderCaps()->dualSourceBlendingSupport() &&
|
||||
this->shaderCaps()->pathRenderingSupport() &&
|
||||
(contextOptions.fGpuPathRenderers & GrContextOptions::GpuPathRenderers::kStencilAndCover)) {
|
||||
fUsesMixedSamples = ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") ||
|
||||
ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_mixed_samples");
|
||||
// Workaround NVIDIA bug related to glInvalidateFramebuffer and mixed samples.
|
||||
if (fUsesMixedSamples && (kNVIDIA_GrGLDriver == ctxInfo.driver() ||
|
||||
kChromium_GrGLDriver == ctxInfo.driver())) {
|
||||
fDiscardRenderTargetSupport = false;
|
||||
fInvalidateFBType = kNone_InvalidateFBType;
|
||||
}
|
||||
}
|
||||
|
||||
if (kGL_GrGLStandard != ctxInfo.standard()) {
|
||||
// We prefer the EXT/IMG extension over ES3 MSAA because we've observed
|
||||
// ES3 driver bugs on at least one device with a tiled GPU (N10).
|
||||
@ -1030,6 +1017,20 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa
|
||||
fBlitFramebufferFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &fMaxStencilSampleCount);
|
||||
} else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &fMaxStencilSampleCount);
|
||||
}
|
||||
// We only have a use for raster multisample if there is coverage modulation from mixed samples.
|
||||
if (fUsesMixedSamples && ctxInfo.hasExtension("GL_EXT_raster_multisample")) {
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_RASTER_SAMPLES, &fMaxRasterSamples);
|
||||
// This is to guard against platforms that may not support as many samples for
|
||||
// glRasterSamples as they do for framebuffers.
|
||||
fMaxStencilSampleCount = SkTMin(fMaxStencilSampleCount, fMaxRasterSamples);
|
||||
}
|
||||
fMaxColorSampleCount = fMaxStencilSampleCount;
|
||||
}
|
||||
|
||||
void GrGLCaps::initBlendEqationSupport(const GrGLContextInfo& ctxInfo) {
|
||||
@ -1084,7 +1085,7 @@ namespace {
|
||||
const GrGLuint kUnknownBitCount = GrGLStencilAttachment::kUnknownBitCount;
|
||||
}
|
||||
|
||||
void GrGLCaps::initStencilFormats(const GrGLContextInfo& ctxInfo) {
|
||||
void GrGLCaps::initStencilSupport(const GrGLContextInfo& ctxInfo) {
|
||||
|
||||
// Build up list of legal stencil formats (though perhaps not supported on
|
||||
// the particular gpu/driver) from most preferred to least.
|
||||
|
@ -380,9 +380,10 @@ private:
|
||||
|
||||
void onApplyOptionsOverrides(const GrContextOptions& options) override;
|
||||
|
||||
void initFSAASupport(const GrGLContextInfo&, const GrGLInterface*);
|
||||
void initFSAASupport(const GrContextOptions& contextOptions, const GrGLContextInfo&,
|
||||
const GrGLInterface*);
|
||||
void initBlendEqationSupport(const GrGLContextInfo&);
|
||||
void initStencilFormats(const GrGLContextInfo&);
|
||||
void initStencilSupport(const GrGLContextInfo&);
|
||||
// This must be called after initFSAASupport().
|
||||
void initConfigTable(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*,
|
||||
GrShaderCaps*);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GrGLRenderTarget.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrGLGpu.h"
|
||||
#include "GrGLUtil.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
@ -170,6 +171,10 @@ GrGLGpu* GrGLRenderTarget::getGLGpu() const {
|
||||
}
|
||||
|
||||
bool GrGLRenderTarget::canAttemptStencilAttachment() const {
|
||||
if (this->getGpu()->getContext()->caps()->avoidStencilBuffers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
|
||||
// allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
|
||||
// Skia created it.
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GrGLTextureRenderTarget.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "SkTraceMemoryDump.h"
|
||||
|
||||
// GrGLTextureRenderTarget must dump both of its superclasses.
|
||||
@ -40,8 +41,8 @@ void GrGLTextureRenderTarget::dumpMemoryStatistics(
|
||||
|
||||
bool GrGLTextureRenderTarget::canAttemptStencilAttachment() const {
|
||||
// The RT FBO of GrGLTextureRenderTarget is never created from a
|
||||
// wrapped FBO.
|
||||
return true;
|
||||
// wrapped FBO, so we only care about the flag.
|
||||
return !this->getGpu()->getContext()->caps()->avoidStencilBuffers();
|
||||
}
|
||||
|
||||
sk_sp<GrGLTextureRenderTarget> GrGLTextureRenderTarget::MakeWrapped(
|
||||
|
@ -667,9 +667,9 @@ sk_sp<GrGeometryProcessor> QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
return (args.fShaderCaps->shaderDerivativeSupport() && (GrAAType::kCoverage == args.fAAType) &&
|
||||
args.fShape->style().isSimpleFill() && !args.fShape->inverseFilled() &&
|
||||
args.fShape->knownToBeConvex());
|
||||
return (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
|
||||
(GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
|
||||
!args.fShape->inverseFilled() && args.fShape->knownToBeConvex());
|
||||
}
|
||||
|
||||
// extract the result vertices and indices from the GrAAConvexTessellator
|
||||
|
@ -624,7 +624,7 @@ bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const
|
||||
}
|
||||
|
||||
if (SkPath::kLine_SegmentMask == args.fShape->segmentMask() ||
|
||||
args.fShaderCaps->shaderDerivativeSupport()) {
|
||||
args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -548,10 +548,14 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget
|
||||
}
|
||||
|
||||
bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
bool isHairline = IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr);
|
||||
// If we aren't a single_pass_shape or hairline, we require stencil buffers.
|
||||
if (!(single_pass_shape(*args.fShape) || isHairline) && args.fCaps->avoidStencilBuffers()) {
|
||||
return false;
|
||||
}
|
||||
// This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
|
||||
return GrAAType::kCoverage != args.fAAType &&
|
||||
(args.fShape->style().isSimpleFill() ||
|
||||
IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr));
|
||||
(args.fShape->style().isSimpleFill() || isHairline);
|
||||
}
|
||||
|
||||
bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
|
@ -677,6 +677,10 @@ bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetCon
|
||||
}
|
||||
|
||||
bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
// If we aren't a single_pass_shape, we require stencil buffers.
|
||||
if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) {
|
||||
return false;
|
||||
}
|
||||
// This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
|
||||
// handled by passing on the original shape and letting the caller compute the stroked shape
|
||||
// which will have a fill style.
|
||||
|
@ -87,7 +87,7 @@ GrSmallPathRenderer::~GrSmallPathRenderer() {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
if (!args.fShaderCaps->shaderDerivativeSupport()) {
|
||||
if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
|
||||
return false;
|
||||
}
|
||||
// If the shape has no key then we won't get any reuse.
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
|
||||
const GrCaps& caps) {
|
||||
if (caps.shaderCaps()->pathRenderingSupport()) {
|
||||
if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) {
|
||||
return new GrStencilAndCoverPathRenderer(resourceProvider);
|
||||
} else {
|
||||
return nullptr;
|
||||
|
@ -251,7 +251,11 @@ static bool set_random_state(GrPaint* paint, SkRandom* random) {
|
||||
}
|
||||
|
||||
// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
|
||||
static const GrUserStencilSettings* get_random_stencil(SkRandom* random) {
|
||||
static const GrUserStencilSettings* get_random_stencil(SkRandom* random, GrContext* context) {
|
||||
if (context->caps()->avoidStencilBuffers()) {
|
||||
return &GrUserStencilSettings::kUnused;
|
||||
}
|
||||
|
||||
static constexpr GrUserStencilSettings kDoesWriteStencil(
|
||||
GrUserStencilSettings::StaticInit<
|
||||
0xffff,
|
||||
@ -332,7 +336,7 @@ bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) {
|
||||
set_random_color_coverage_stages(&grPaint, &ptd, maxStages);
|
||||
set_random_xpf(&grPaint, &ptd);
|
||||
bool snapToCenters = set_random_state(&grPaint, &random);
|
||||
const GrUserStencilSettings* uss = get_random_stencil(&random);
|
||||
const GrUserStencilSettings* uss = get_random_stencil(&random, context);
|
||||
// We don't use kHW because we will hit an assertion if the render target is not
|
||||
// multisampled
|
||||
static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kCoverage};
|
||||
|
@ -190,6 +190,11 @@ private:
|
||||
DEF_GPUTEST(GLSampleLocations, reporter, /*factory*/) {
|
||||
GLTestSampleLocationsInterface testInterface;
|
||||
sk_sp<GrContext> ctx(GrContext::Create(kOpenGL_GrBackend, testInterface));
|
||||
|
||||
// This test relies on at least 2 samples.
|
||||
if (ctx->caps()->maxSampleCount() < 2) {
|
||||
return;
|
||||
}
|
||||
test_sampleLocations(reporter, &testInterface, ctx.get());
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,9 @@ DEF_GPUTEST_FOR_CONTEXTS(ResourceCacheStencilBuffers, &is_rendering_and_not_angl
|
||||
smallDesc.fHeight = 4;
|
||||
smallDesc.fSampleCnt = 0;
|
||||
|
||||
if (context->caps()->avoidStencilBuffers()) {
|
||||
return;
|
||||
}
|
||||
GrResourceProvider* resourceProvider = context->resourceProvider();
|
||||
// Test that two budgeted RTs with the same desc share a stencil buffer.
|
||||
sk_sp<GrTexture> smallRT0(resourceProvider->createTexture(smallDesc, SkBudgeted::kYes));
|
||||
|
@ -781,6 +781,9 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceAttachStencil_Gpu, reporter, ctxInf
|
||||
if (!gpu) {
|
||||
return;
|
||||
}
|
||||
if (gpu->caps()->avoidStencilBuffers()) {
|
||||
return;
|
||||
}
|
||||
static const uint32_t kOrigColor = 0xFFAABBCC;
|
||||
|
||||
for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
|
||||
|
@ -80,7 +80,7 @@ DEF_TEST(ParseConfigs_DefaultConfigs, reporter) {
|
||||
"pdf", "skp", "svg", "xps", "angle_d3d11_es2", "angle_gl_es2", "commandbuffer", "mesa",
|
||||
"hwui", "glf16", "glessrgb", "gl", "glnvpr4", "glnvprdit4", "glsrgb", "glmsaa4", "vk",
|
||||
"glinst", "glinst4", "glinstdit4", "glinst8", "glinstdit8", "glesinst", "glesinst4",
|
||||
"glesinstdit4", "glwide", "glnarrow"
|
||||
"glesinstdit4", "glwide", "glnarrow", "glnostencils"
|
||||
});
|
||||
|
||||
SkCommandLineConfigArray configs;
|
||||
|
@ -64,6 +64,7 @@ static const struct {
|
||||
{ "glsrgb", "gpu", "api=gl,color=srgb" },
|
||||
{ "glwide", "gpu", "api=gl,color=f16_wide" },
|
||||
{ "glnarrow", "gpu", "api=gl,color=f16_narrow" },
|
||||
{ "glnostencils", "gpu", "api=gl,stencils=false" },
|
||||
{ "glessrgb", "gpu", "api=gles,color=srgb" },
|
||||
{ "gleswide", "gpu", "api=gles,color=f16_wide" },
|
||||
{ "glesnarrow", "gpu", "api=gles,color=f16_narrow" },
|
||||
@ -151,6 +152,8 @@ static const char configExtendedHelp[] =
|
||||
"\t Use NV_path_rendering OpenGL and OpenGL ES extension.\n"
|
||||
"\tsamples\ttype: int\tdefault: 0.\n"
|
||||
"\t Use multisampling with N samples.\n"
|
||||
"\tstencils\ttype: bool\tdefault: true.\n"
|
||||
"\t Allow the use of stencil buffers.\n"
|
||||
"\n"
|
||||
"Predefined configs:\n\n"
|
||||
// Help text for pre-defined configs is auto-generated from gPredefinedConfigs
|
||||
@ -181,7 +184,7 @@ SkCommandLineConfig::~SkCommandLineConfig() {
|
||||
SkCommandLineConfigGpu::SkCommandLineConfigGpu(
|
||||
const SkString& tag, const SkTArray<SkString>& viaParts, ContextType contextType, bool useNVPR,
|
||||
bool useInstanced, bool useDIText, int samples, SkColorType colorType,
|
||||
sk_sp<SkColorSpace> colorSpace)
|
||||
sk_sp<SkColorSpace> colorSpace, bool useStencilBuffers)
|
||||
: SkCommandLineConfig(tag, SkString("gpu"), viaParts)
|
||||
, fContextType(contextType)
|
||||
, fContextOverrides(ContextOverrides::kNone)
|
||||
@ -210,6 +213,9 @@ SkCommandLineConfigGpu::SkCommandLineConfigGpu(
|
||||
fContextOverrides |= ContextOverrides::kRequireSRGBSupport;
|
||||
fContextOverrides |= ContextOverrides::kAllowSRGBWithoutDecodeControl;
|
||||
}
|
||||
if (!useStencilBuffers) {
|
||||
fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
|
||||
}
|
||||
}
|
||||
static bool parse_option_int(const SkString& value, int* outInt) {
|
||||
if (value.isEmpty()) {
|
||||
@ -370,6 +376,8 @@ SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
|
||||
bool seenColor = false;
|
||||
SkColorType colorType = kRGBA_8888_SkColorType;
|
||||
sk_sp<SkColorSpace> colorSpace = nullptr;
|
||||
bool seenUseStencils = false;
|
||||
bool useStencils = true;
|
||||
|
||||
SkTArray<SkString> optionParts;
|
||||
SkStrSplit(options.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
|
||||
@ -400,6 +408,9 @@ SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
|
||||
} else if (key.equals("color") && !seenColor) {
|
||||
valueOk = parse_option_gpu_color(value, &colorType, &colorSpace);
|
||||
seenColor = true;
|
||||
} else if (key.equals("stencils") && !seenUseStencils) {
|
||||
valueOk = parse_option_bool(value, &useStencils);
|
||||
seenUseStencils = true;
|
||||
}
|
||||
if (!valueOk) {
|
||||
return nullptr;
|
||||
@ -409,7 +420,7 @@ SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
|
||||
return nullptr;
|
||||
}
|
||||
return new SkCommandLineConfigGpu(tag, vias, contextType, useNVPR, useInstanced, useDIText,
|
||||
samples, colorType, colorSpace);
|
||||
samples, colorType, colorSpace, useStencils);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -55,7 +55,8 @@ class SkCommandLineConfigGpu : public SkCommandLineConfig {
|
||||
typedef sk_gpu_test::GrContextFactory::ContextOverrides ContextOverrides;
|
||||
SkCommandLineConfigGpu(const SkString& tag, const SkTArray<SkString>& viaParts,
|
||||
ContextType contextType, bool useNVPR, bool useInstanced, bool useDIText,
|
||||
int samples, SkColorType colorType, sk_sp<SkColorSpace> colorSpace);
|
||||
int samples, SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
|
||||
bool useStencilBuffers);
|
||||
const SkCommandLineConfigGpu* asConfigGpu() const override { return this; }
|
||||
ContextType getContextType() const { return fContextType; }
|
||||
ContextOverrides getContextOverrides() const { return fContextOverrides; }
|
||||
|
@ -230,6 +230,9 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv
|
||||
if (ContextOverrides::kAllowSRGBWithoutDecodeControl & overrides) {
|
||||
grOptions.fRequireDecodeDisableForSRGB = false;
|
||||
}
|
||||
if (ContextOverrides::kAvoidStencilBuffers & overrides) {
|
||||
grOptions.fAvoidStencilBuffers = true;
|
||||
}
|
||||
sk_sp<GrContext> grCtx(GrContext::Create(backend, backendContext, grOptions));
|
||||
if (!grCtx.get()) {
|
||||
return ContextInfo();
|
||||
|
@ -94,9 +94,10 @@ public:
|
||||
kDisableNVPR = 0x1,
|
||||
kUseInstanced = 0x2,
|
||||
kAllowSRGBWithoutDecodeControl = 0x4,
|
||||
kAvoidStencilBuffers = 0x8,
|
||||
|
||||
kRequireNVPRSupport = 0x8,
|
||||
kRequireSRGBSupport = 0x10
|
||||
kRequireNVPRSupport = 0x10,
|
||||
kRequireSRGBSupport = 0x20,
|
||||
};
|
||||
|
||||
static bool IsRenderingContext(ContextType type) {
|
||||
|
Loading…
Reference in New Issue
Block a user