GrClipMaskManager.cpp revision b0a8a377f832c59cee939ad721e1f87d378b7142
11e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 21e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com/* 31e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Copyright 2012 Google Inc. 41e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * 51e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be 61e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * found in the LICENSE file. 71e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com */ 81e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 91e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrClipMaskManager.h" 10c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAConvexPathRenderer.h" 11c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAHairLinePathRenderer.h" 12bfe2b9d3a290d0153b82617cd6b65a4814fe89e3jvanverth@google.com#include "GrAARectRenderer.h" 13c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h" 141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h" 15c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPaint.h" 16c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPathRenderer.h" 171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h" 181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h" 19c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrSWMaskHelper.h" 20907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org#include "effects/GrTextureDomain.h" 2165ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org#include "effects/GrConvexPolyEffect.h" 22c2f7824436d05da6e8514d06a54773538aace028commit-bot@chromium.org#include "effects/GrRRectEffect.h" 236b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h" 245f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h" 25c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com#include "SkTLazy.h" 26c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com 27ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com#define GR_AA_CLIP 1 28a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 298182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comtypedef SkClipStack::Element Element; 3051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comusing namespace GrReducedClip; 324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 3351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com//////////////////////////////////////////////////////////////////////////////// 34e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.comnamespace { 35fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the 3608283afc265f1153834256fc1012519813ba6b73bsalomon@google.com// stage matrix this also alters the vertex layout 37e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.comvoid setup_drawstate_aaclip(GrGpu* gpu, 38e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrTexture* result, 39e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkIRect &devBound) { 40a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com GrDrawState* drawState = gpu->drawState(); 41f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(drawState); 42a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 43b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix mat; 44c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com // We want to use device coords to compute the texture coordinates. We set our matrix to be 45c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com // equal to the view matrix followed by an offset to the devBound, and then a scaling matrix to 46c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com // normalized coords. We apply this matrix to the vertex positions rather than local coords. 47a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com mat.setIDiv(result->width(), result->height()); 48fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com mat.preTranslate(SkIntToScalar(-devBound.fLeft), 497b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com SkIntToScalar(-devBound.fTop)); 50a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com mat.preConcat(drawState->getViewMatrix()); 51a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 527b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); 534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // This could be a long-lived effect that is cached with the alpha-mask. 54b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt drawState->addCoverageProcessor( 55eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com GrTextureDomainEffect::Create(result, 567b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com mat, 57907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org GrTextureDomain::MakeTexelDomain(result, domainTexels), 58907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org GrTextureDomain::kDecal_Mode, 59b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com GrTextureParams::kNone_FilterMode, 6077af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com kPosition_GrCoordSet))->unref(); 61a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com} 62a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 63e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool path_needs_SW_renderer(GrContext* context, 64e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrGpu* gpu, 65e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkPath& origPath, 66e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkStrokeRec& stroke, 67e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com bool doAA) { 68e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer 69e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com SkTCopyOnFirstWrite<SkPath> path(origPath); 70e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (path->isInverseFillType()) { 71e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com path.writable()->toggleInverseFillType(); 72e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com } 73e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com // last (false) parameter disallows use of the SW path renderer 7445a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRendererChain::DrawType type = doAA ? 7545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRendererChain::kColorAntiAlias_DrawType : 7645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRendererChain::kColor_DrawType; 7745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com 78e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com return NULL == context->getPathRenderer(*path, stroke, gpu, false, type); 79e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com} 80e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com 816b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 83fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/* 84fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer 85fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the 86fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu. 87fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */ 884c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.combool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { 89a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com 908a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com // TODO: generalize this function so that when 91fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // a clip gets complex enough it can just be done in SW regardless 92fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // of whether it would invoke the GrSoftwarePathRenderer. 935f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 94d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com 954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { 964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const Element* element = iter.get(); 97f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com // rects can always be drawn directly w/o using the software path 98e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org // Skip rrects once we're drawing them directly. 99e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (Element::kRect_Type != element->getType()) { 100e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkPath path; 101e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org element->asPath(&path); 102e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (path_needs_SW_renderer(this->getContext(), fGpu, path, stroke, element->isAA())) { 103e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return true; 104e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org } 105fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 106fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return false; 108a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com} 109a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 110e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.orgbool GrClipMaskManager::installClipEffects(const ElementList& elements, 111e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org GrDrawState::AutoRestoreEffects* are, 112e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org const SkVector& clipToRTOffset, 113217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein const SkRect* drawBounds) { 114e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 115e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org GrDrawState* drawState = fGpu->drawState(); 116e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkRect boundsInClipSpace; 11749f085dddff10473b6ebf832a974288300224e60bsalomon if (drawBounds) { 118e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org boundsInClipSpace = *drawBounds; 119e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); 120e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 121e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 122e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org are->set(drawState); 123e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org GrRenderTarget* rt = drawState->getRenderTarget(); 124217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein ElementList::Iter iter(elements); 125e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 126e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org bool setARE = false; 127e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org bool failed = false; 128e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 12949f085dddff10473b6ebf832a974288300224e60bsalomon while (iter.get()) { 130e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkRegion::Op op = iter.get()->getOp(); 131e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org bool invert; 132e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org bool skip = false; 133e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org switch (op) { 134e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkRegion::kReplace_Op: 135e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkASSERT(iter.get() == elements.head()); 136e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // Fallthrough, handled same as intersect. 137e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkRegion::kIntersect_Op: 138e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org invert = false; 13949f085dddff10473b6ebf832a974288300224e60bsalomon if (drawBounds && iter.get()->contains(boundsInClipSpace)) { 140e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org skip = true; 141e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 142e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 143e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkRegion::kDifference_Op: 144e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org invert = true; 145e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // We don't currently have a cheap test for whether a rect is fully outside an 146e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // element's primitive, so don't attempt to set skip. 147e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 148e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org default: 149e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org failed = true; 150e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 151e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 152e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (failed) { 153e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 154e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 155e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 156e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (!skip) { 157b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrPrimitiveEdgeType edgeType; 158e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (GR_AA_CLIP && iter.get()->isAA()) { 159e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (rt->isMultisampled()) { 160217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein // Coverage based AA clips don't place nicely with MSAA. 161e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org failed = true; 162e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 163e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 164b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt edgeType = 165b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; 166e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } else { 167b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt edgeType = 168b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; 169e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 170b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt SkAutoTUnref<GrFragmentProcessor> fp; 171e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org switch (iter.get()->getType()) { 172e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkClipStack::Element::kPath_Type: 173b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), 174e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org &clipToRTOffset)); 175e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 176e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkClipStack::Element::kRRect_Type: { 177e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkRRect rrect = iter.get()->getRRect(); 178e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); 179b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt fp.reset(GrRRectEffect::Create(edgeType, rrect)); 180e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 181e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 182e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org case SkClipStack::Element::kRect_Type: { 183e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkRect rect = iter.get()->getRect(); 184e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); 185b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); 186e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 187e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 188e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org default: 189e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 190e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 191b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt if (fp) { 192e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (!setARE) { 193e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org are->set(fGpu->drawState()); 194e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org setARE = true; 195e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 196b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt fGpu->drawState()->addCoverageProcessor(fp); 197217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein } else { 198e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org failed = true; 199e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org break; 200e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 201e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 202217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein iter.next(); 203e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 204e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 205e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (failed) { 206e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org are->set(NULL); 207e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 208e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 209e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org return !failed; 210e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org} 211e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org 212f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 2136b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil, 2146b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software 215eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.combool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, 2163ae0e6c2b213d45c370846a4d4182a6754ca493ecommit-bot@chromium.org GrDrawState::AutoRestoreEffects* are, 2173ae0e6c2b213d45c370846a4d4182a6754ca493ecommit-bot@chromium.org const SkRect* devBounds) { 218c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kNone_ClipMaskType; 219a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 2204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com ElementList elements(16); 221d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org int32_t genID; 2224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com InitialState initialState; 2234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect clipSpaceIBounds; 2244c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com bool requiresAA; 2254c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 22613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 2271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const GrRenderTarget* rt = drawState->getRenderTarget(); 2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // GrDrawTarget should have filtered this for us 23049f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(rt); 2311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWideOpen(); 2334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 2344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (!ignoreClip) { 2354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); 2364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceRTIBounds.offset(clipDataIn->fOrigin); 2374c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com ReduceClipStack(*clipDataIn->fClipStack, 2384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceRTIBounds, 2394c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com &elements, 240d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org &genID, 2414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com &initialState, 2424c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com &clipSpaceIBounds, 2434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com &requiresAA); 2444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (elements.isEmpty()) { 2454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (kAllIn_InitialState == initialState) { 2464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds; 2474c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } else { 2484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return false; 2494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 2504c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 2514c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 2523e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com 2534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (ignoreClip) { 2544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com fGpu->disableScissor(); 2554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com this->setGpuStencil(); 2564c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return true; 257a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 258a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 259e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // An element count of 4 was chosen because of the common pattern in Blink of: 260e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // isect RR 261e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // diff RR 262e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // isect convex_poly 263e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // isect convex_poly 264e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // when drawing rounded div borders. This could probably be tuned based on a 265e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // configuration's relative costs of switching RTs to generate a mask vs 266e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org // longer shaders. 267e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (elements.count() <= 4) { 268e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), 269b21fac156d9287d6c0cfd446d707c4c7be6fae6ecommit-bot@chromium.org SkIntToScalar(-clipDataIn->fOrigin.fY) }; 270e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org if (elements.isEmpty() || 271217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein (requiresAA && this->installClipEffects(elements, are, clipToRTOffset, devBounds))) { 272217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein SkIRect scissorSpaceIBounds(clipSpaceIBounds); 273217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein scissorSpaceIBounds.offset(-clipDataIn->fOrigin); 274217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein if (NULL == devBounds || 275217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { 276217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein fGpu->enableScissor(scissorSpaceIBounds); 277e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } else { 278217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein fGpu->disableScissor(); 279e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org } 28065ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org this->setGpuStencil(); 28165ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org return true; 28265ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org } 28365ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org } 284d3066bd9b4a37cf4a39e7df7e1432f3df10dbc67bsalomon@google.com 28565ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org#if GR_AA_CLIP 286a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // If MSAA is enabled we can do everything in the stencil buffer. 2874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (0 == rt->numSamples() && requiresAA) { 2886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com GrTexture* result = NULL; 289a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com 2904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (this->useSWOnlyPath(elements)) { 2914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The clip geometry is complex enough that it will be more efficient to create it 2924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // entirely in software 2934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com result = this->createSoftwareClipMask(genID, 2944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com initialState, 2954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com elements, 2964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceIBounds); 2974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } else { 2984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com result = this->createAlphaClipMask(genID, 2994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com initialState, 3004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com elements, 3014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceIBounds); 3024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 3036b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 30449f085dddff10473b6ebf832a974288300224e60bsalomon if (result) { 3054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The mask's top left coord should be pinned to the rounded-out top left corner of 3064c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // clipSpace bounds. We determine the mask's position WRT to the render target here. 3074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect rtSpaceMaskBounds = clipSpaceIBounds; 3084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com rtSpaceMaskBounds.offset(-clipDataIn->fOrigin); 309eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com are->set(fGpu->drawState()); 3104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com setup_drawstate_aaclip(fGpu, result, rtSpaceMaskBounds); 311a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableScissor(); 312a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 313f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return true; 314f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 3154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // if alpha clip mask creation fails fall through to the non-AA code paths 316f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 317f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP 318f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 3194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // Either a hard (stencil buffer) clip was explicitly requested or an anti-aliased clip couldn't 3204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // be created. In either case, free up the texture in the anti-aliased mask cache. 3214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // TODO: this may require more investigation. Ganesh performs a lot of utility draws (e.g., 3224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. These may be 3234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // "incorrectly" clearing the AA cache. 3245acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com fAACache.reset(); 3255acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com 3261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // use the stencil clip if we can't represent the clip as a rectangle. 3274c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin; 328d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org this->createStencilClipMask(genID, 329d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org initialState, 3304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com elements, 3314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceIBounds, 3324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipSpaceToStencilSpaceOffset); 3334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 3344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // This must occur after createStencilClipMask. That function may change the scissor. Also, it 3354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // only guarantees that the stencil mask is correct within the bounds it was passed, so we must 3364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // use both stencil and scissor test to the bounds for the final draw. 3374c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect scissorSpaceIBounds(clipSpaceIBounds); 3384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); 3394c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com fGpu->enableScissor(scissorSpaceIBounds); 340a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 3411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return true; 3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 3431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 3441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0 3451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 3461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP 347223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org #include "SkRandom.h" 348223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org SkRandom gRandom; 3491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); 3501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else 3511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com #define SET_RANDOM_COLOR 3521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif 3531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 3541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace { 355f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 356f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 357fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the OpenGL blend function to perform the specified 358fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// boolean operation for alpha clip mask creation 3596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) { 360f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 361f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com switch (op) { 362f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kReplace_Op: 36347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); 364f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 365f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kIntersect_Op: 36647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); 367f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kUnion_Op: 36947059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 370f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 371f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kXOR_Op: 37247059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); 373f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 374f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kDifference_Op: 37547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); 376f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 377f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kReverseDifference_Op: 37847059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); 379f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 380f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com default: 381f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(false); 382f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 383f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 384f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 385f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 38672176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com} 387f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 388f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 389b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::drawElement(GrTexture* target, 390e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkClipStack::Element* element, 391e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRenderer* pr) { 39213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 393f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 394f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com drawState->setRenderTarget(target->asRenderTarget()); 395f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 396e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org // TODO: Draw rrects directly here. 3978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com switch (element->getType()) { 398e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org case Element::kEmpty_Type: 399e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkDEBUGFAIL("Should never get here with an empty element."); 400e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org break; 4018182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com case Element::kRect_Type: 402b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers 403b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt // the entire mask bounds and writes 0 outside the rect. 4048182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if (element->isAA()) { 405cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com getContext()->getAARectRenderer()->fillAARect(fGpu, 406cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com fGpu, 407cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com element->getRect(), 408b19cb7f36785f3ad3b1512c342fc662ab79e3fcarobertphillips@google.com SkMatrix::I(), 4099c0822a4150e23cec9f9b72bd1abc2c5f9ea5a3bbsalomon element->getRect()); 4108182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com } else { 41101c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon fGpu->drawSimpleRect(element->getRect()); 4128182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com } 4138182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com return true; 414e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org default: { 415e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkPath path; 416e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org element->asPath(&path); 417e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (path.isInverseFillType()) { 418e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org path.toggleInverseFillType(); 419e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com } 4205f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 421e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (NULL == pr) { 422e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRendererChain::DrawType type; 423e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType : 424e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRendererChain::kColor_DrawType; 425e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr = this->getContext()->getPathRenderer(path, stroke, fGpu, false, type); 426e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com } 427e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (NULL == pr) { 4284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return false; 4294c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 430e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr->drawPath(path, stroke, fGpu, element->isAA()); 4314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com break; 4324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 433f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 434f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return true; 435f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 436f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 437b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target, 438b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com const SkClipStack::Element* element, 439e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRenderer** pr) { 440b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 441b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->setRenderTarget(target->asRenderTarget()); 442b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 443e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (Element::kRect_Type == element->getType()) { 444e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return true; 445e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org } else { 446e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org // We shouldn't get here with an empty clip element. 447e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkASSERT(Element::kEmpty_Type != element->getType()); 448e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkPath path; 449e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org element->asPath(&path); 450e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (path.isInverseFillType()) { 451e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org path.toggleInverseFillType(); 452b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } 453e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 454e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org GrPathRendererChain::DrawType type = element->isAA() ? 455e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : 456e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org GrPathRendererChain::kStencilAndColor_DrawType; 457e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org *pr = this->getContext()->getPathRenderer(path, stroke, fGpu, false, type); 45849f085dddff10473b6ebf832a974288300224e60bsalomon return SkToBool(*pr); 459b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } 460b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com} 461b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 4627b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.comvoid GrClipMaskManager::mergeMask(GrTexture* dstMask, 4637b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTexture* srcMask, 4647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkRegion::Op op, 465fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org const SkIRect& dstBound, 466fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org const SkIRect& srcBound) { 467137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawState::AutoViewMatrixRestore avmr; 46813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 469137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkAssertResult(avmr.setIdentity(drawState)); 470eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com GrDrawState::AutoRestoreEffects are(drawState); 471f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4727b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->setRenderTarget(dstMask->asRenderTarget()); 473f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4747b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com setup_boolean_blendcoeffs(drawState, op); 47572b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com 476b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix sampleM; 4777b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com sampleM.setIDiv(srcMask->width(), srcMask->height()); 478956b310f13c7412c035406c658ff16ca85eac656skia.committer@gmail.com 479b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt drawState->addColorProcessor( 4807b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::Create(srcMask, 4817b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com sampleM, 482907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org GrTextureDomain::MakeTexelDomain(srcMask, srcBound), 483907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org GrTextureDomain::kDecal_Mode, 484b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com GrTextureParams::kNone_FilterMode))->unref(); 48501c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon fGpu->drawSimpleRect(SkRect::Make(dstBound)); 486f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 487f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4886d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations 4896d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too 4904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comvoid GrClipMaskManager::getTemp(int width, int height, GrAutoScratchTexture* temp) { 49149f085dddff10473b6ebf832a974288300224e60bsalomon if (temp->texture()) { 4926d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com // we've already allocated the temp texture 4936d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com return; 4946d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com } 4956d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 49675b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com GrTextureDesc desc; 49775b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit; 4984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com desc.fWidth = width; 4994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com desc.fHeight = height; 50075b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fConfig = kAlpha_8_GrPixelConfig; 5016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 5022c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com temp->set(this->getContext(), desc); 5036d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com} 5046d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 5056b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 506ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// Return the texture currently in the cache if it exists. Otherwise, return NULL 507ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevskiGrTexture* GrClipMaskManager::getCachedMaskTexture(int32_t elementsGenID, 508ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski const SkIRect& clipSpaceIBounds) { 509d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org bool cached = fAACache.canReuse(elementsGenID, clipSpaceIBounds); 5104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (!cached) { 511ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski return NULL; 512ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski } 5134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 514ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski return fAACache.getLastMask(); 515ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski} 516f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 517ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski//////////////////////////////////////////////////////////////////////////////// 518ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// Allocate a texture in the texture cache. This function returns the texture 519ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// allocated (or NULL on error). 520ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevskiGrTexture* GrClipMaskManager::allocMaskTexture(int32_t elementsGenID, 521ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski const SkIRect& clipSpaceIBounds, 522ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski bool willUpload) { 523ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // Since we are setting up the cache we should free up the 524ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // currently cached mask so it can be reused. 525ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski fAACache.reset(); 526a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 527ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski GrTextureDesc desc; 528ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski desc.fFlags = willUpload ? kNone_GrTextureFlags : kRenderTarget_GrTextureFlagBit; 529ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski desc.fWidth = clipSpaceIBounds.width(); 530ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski desc.fHeight = clipSpaceIBounds.height(); 531ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski desc.fConfig = kRGBA_8888_GrPixelConfig; 532ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski if (willUpload || this->getContext()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { 533ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // We would always like A8 but it isn't supported on all platforms 534ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski desc.fConfig = kAlpha_8_GrPixelConfig; 5358fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com } 5368fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com 537ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski fAACache.acquireMask(elementsGenID, desc, clipSpaceIBounds); 538ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski return fAACache.getLastMask(); 5396b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 540f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 5416b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 5426b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha 543d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgGrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, 5444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com InitialState initialState, 5454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const ElementList& elements, 5464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const SkIRect& clipSpaceIBounds) { 547f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); 548c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com 549ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // First, check for cached texture 550ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds); 55149f085dddff10473b6ebf832a974288300224e60bsalomon if (result) { 552c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 5534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return result; 5546b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 555f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 556ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // There's no texture in the cache. Let's try to allocate it then. 557ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, false); 5584c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (NULL == result) { 559f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.reset(); 5604c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return NULL; 561f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 562f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 5634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The top-left of the mask corresponds to the top-left corner of the bounds. 5647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkVector clipToMaskOffset = { 5654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIntToScalar(-clipSpaceIBounds.fLeft), 5664c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIntToScalar(-clipSpaceIBounds.fTop) 5677b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com }; 5684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The texture may be larger than necessary, this rect represents the part of the texture 5694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // we populate with a rasterization of the clip. 5704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height()); 571f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 572137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com // Set the matrix so that rendered clip elements are transformed to mask space from clip space. 573137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkMatrix translate; 574137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com translate.setTranslate(clipToMaskOffset); 575137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &translate); 576137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com 577137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 578137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com 579cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com // We're drawing a coverage mask and want coverage to be run through the blend function. 580cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com drawState->enableState(GrDrawState::kCoverageDrawing_StateBit); 581cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com 5827b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // The scratch texture that we are drawing into can be substantially larger than the mask. Only 5837b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // clear the part that we care about. 5844c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com fGpu->clear(&maskSpaceIBounds, 5854c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000, 58656ce48ade325f6f49acb0da31d6252806e4ed7efrobertphillips@google.com true, 5874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com result->asRenderTarget()); 588d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com 589b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // When we use the stencil in the below loop it is important to have this clip installed. 590b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first 591b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // pass must not set values outside of this bounds or stencil values outside the rect won't be 592b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // cleared. 593b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com GrDrawTarget::AutoClipRestore acr(fGpu, maskSpaceIBounds); 594b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->enableState(GrDrawState::kClip_StateBit); 595b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 596f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com GrAutoScratchTexture temp; 597f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // walk through each clip element and perform its set op 5984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) { 5994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const Element* element = iter.get(); 6008182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com SkRegion::Op op = element->getOp(); 601b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com bool invert = element->isInverseFilled(); 602f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 603b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { 604e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRenderer* pr = NULL; 605e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com bool useTemp = !this->canStencilAndDrawElement(result, element, &pr); 606b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com GrTexture* dst; 6074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // This is the bounds of the clip element in the space of the alpha-mask. The temporary 6087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // mask buffer can be substantially larger than the actually clip stack element. We 6097b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // touch the minimum number of pixels necessary and use decal mode to combine it with 610b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // the accumulator. 611fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkIRect maskSpaceElementIBounds; 612b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 613b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com if (useTemp) { 614b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com if (invert) { 615b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com maskSpaceElementIBounds = maskSpaceIBounds; 616b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } else { 617fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkRect elementBounds = element->getBounds(); 618b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com elementBounds.offset(clipToMaskOffset); 619b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com elementBounds.roundOut(&maskSpaceElementIBounds); 620b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } 621b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 622b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com this->getTemp(maskSpaceIBounds.fRight, maskSpaceIBounds.fBottom, &temp); 623b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com if (NULL == temp.texture()) { 624b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com fAACache.reset(); 625b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com return NULL; 626a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com } 627b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com dst = temp.texture(); 628b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // clear the temp target and set blend to replace 629b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com fGpu->clear(&maskSpaceElementIBounds, 630b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com invert ? 0xffffffff : 0x00000000, 63156ce48ade325f6f49acb0da31d6252806e4ed7efrobertphillips@google.com true, 632b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com dst->asRenderTarget()); 633b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); 634a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com 6354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } else { 636b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // draw directly into the result with the stencil set to make the pixels affected 637b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // by the clip shape be non-zero. 638b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com dst = result; 639b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com GR_STATIC_CONST_SAME_STENCIL(kStencilInElement, 640b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kReplace_StencilOp, 641b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kReplace_StencilOp, 642b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kAlways_StencilFunc, 643b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0xffff, 644b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0xffff, 645b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0xffff); 646b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->setStencil(kStencilInElement); 647a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com setup_boolean_blendcoeffs(drawState, op); 6484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 6497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com 650c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com drawState->setAlpha(invert ? 0x00 : 0xff); 651c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com 652e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (!this->drawElement(dst, element, pr)) { 653e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com fAACache.reset(); 654e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com return NULL; 6554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com } 656f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 657b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com if (useTemp) { 658b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // Now draw into the accumulator using the real operation and the temp buffer as a 659b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // texture 660b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com this->mergeMask(result, 661b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com temp.texture(), 662b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com op, 663b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com maskSpaceIBounds, 664b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com maskSpaceElementIBounds); 665b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } else { 666b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com // Draw to the exterior pixels (those with a zero stencil value). 667b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->setAlpha(invert ? 0xff : 0x00); 668b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, 669b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kZero_StencilOp, 670b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kZero_StencilOp, 671b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com kEqual_StencilFunc, 672b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0xffff, 673b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0x0000, 674b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com 0xffff); 675b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->setStencil(kDrawOutsideElement); 676b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com fGpu->drawSimpleRect(clipSpaceIBounds); 677b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com drawState->disableStencil(); 678b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com } 679f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } else { 680e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com // all the remaining ops can just be directly draw into the accumulation buffer 681c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com drawState->setAlpha(0xff); 6826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com setup_boolean_blendcoeffs(drawState, op); 683b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com this->drawElement(result, element); 684f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 685f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 686f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 687c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 6884c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return result; 6891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 6901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 691f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 692fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device 693f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com// (as opposed to canvas) coordinates 694d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgbool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID, 695d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org InitialState initialState, 6964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const ElementList& elements, 6974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const SkIRect& clipSpaceIBounds, 6984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const SkIPoint& clipSpaceToStencilOffset) { 6991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 700f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); 7011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 70213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 703f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(drawState->isClipState()); 7041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrRenderTarget* rt = drawState->getRenderTarget(); 70649f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(rt); 7071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // TODO: dynamically attach a SB when needed. 7091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); 7101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (NULL == stencilBuffer) { 7111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return false; 7121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 7131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 714d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if (stencilBuffer->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) { 7151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 716d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org stencilBuffer->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset); 7171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 718137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com // Set the matrix so that rendered clip elements are transformed from clip to stencil space. 719137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkVector translate = { 720137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkIntToScalar(clipSpaceToStencilOffset.fX), 721137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkIntToScalar(clipSpaceToStencilOffset.fY) 722137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com }; 723137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com SkMatrix matrix; 724137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com matrix.setTranslate(translate); 725137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix); 72613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com drawState = fGpu->drawState(); 727137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com 7281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->setRenderTarget(rt); 7291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7309f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com // We set the current clip to the bounds so that our recursive draws are scissored to them. 7319f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com SkIRect stencilSpaceIBounds(clipSpaceIBounds); 7329f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com stencilSpaceIBounds.offset(clipSpaceToStencilOffset); 7339f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com GrDrawTarget::AutoClipRestore acr(fGpu, stencilSpaceIBounds); 7349f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com drawState->enableState(GrDrawState::kClip_StateBit); 7359f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com 7361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP 7371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 7381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif 7391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com int clipBit = stencilBuffer->bits(); 7414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); 7421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com clipBit = (1 << (clipBit-1)); 7431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 744b0bd4f64a6827dda6f4ec48e4746b0f0b72a975fbsalomon fGpu->clearStencilClip(rt, stencilSpaceIBounds, kAllIn_InitialState == initialState); 7451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // walk through each clip element and perform its set op 7471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // with the existing clip. 74849f085dddff10473b6ebf832a974288300224e60bsalomon for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { 7494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const Element* element = iter.get(); 7508afae61a57f87e4a50578effce6c428031499301tomhudson@google.com bool fillInverted = false; 7511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // enabled at bottom of loop 7521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->disableState(GrGpu::kModifyStencilClip_StateBit); 753ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com // if the target is MSAA then we want MSAA enabled when the clip is soft 754ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com if (rt->isMultisampled()) { 7558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA()); 756ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com } 7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 75845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com // This will be used to determine whether the clip shape can be rendered into the 75945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com // stencil with arbitrary stencil settings. 76045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRenderer::StencilSupport stencilSupport; 7611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7625f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 76312b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com 7648182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com SkRegion::Op op = element->getOp(); 765f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 766e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com GrPathRenderer* pr = NULL; 767e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org SkPath clipPath; 7688182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if (Element::kRect_Type == element->getType()) { 76945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; 7701e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com fillInverted = false; 7718afae61a57f87e4a50578effce6c428031499301tomhudson@google.com } else { 772e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org element->asPath(&clipPath); 773e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org fillInverted = clipPath.isInverseFillType(); 774e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (fillInverted) { 775e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org clipPath.toggleInverseFillType(); 776e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com } 777e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr = this->getContext()->getPathRenderer(clipPath, 77845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com stroke, 77945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com fGpu, 78045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com false, 78145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRendererChain::kStencilOnly_DrawType, 782e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com &stencilSupport); 783e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (NULL == pr) { 7841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return false; 7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 7861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 7871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com int passes; 7891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; 7901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 79145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com bool canRenderDirectToStencil = 79245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; 7931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com bool canDrawDirectToClip; // Given the renderer, the element, 7944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // fill rule, and set operation can 7954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // we render the element directly to 7964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // stencil bit used for clipping. 7974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, 7984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com canRenderDirectToStencil, 7994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com clipBit, 8004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com fillInverted, 8014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com &passes, 8024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com stencilSettings); 8031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // draw the element to the client stencil bits if necessary 8051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (!canDrawDirectToClip) { 8061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, 8074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com kIncClamp_StencilOp, 8084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com kIncClamp_StencilOp, 8094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com kAlways_StencilFunc, 8104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 0xffff, 8114c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 0x0000, 8124c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 0xffff); 8131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 8148182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if (Element::kRect_Type == element->getType()) { 8151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *drawState->stencil() = gDrawToStencil; 81601c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon fGpu->drawSimpleRect(element->getRect()); 8171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 818e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if (!clipPath.isEmpty()) { 81919dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org if (canRenderDirectToStencil) { 82019dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org *drawState->stencil() = gDrawToStencil; 821e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr->drawPath(clipPath, stroke, fGpu, false); 82219dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org } else { 823e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr->stencilPath(clipPath, stroke, fGpu); 82419dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org } 8251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // now we modify the clip bit by rendering either the clip 8301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // element directly or a bounding rect of the entire clip. 8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->enableState(GrGpu::kModifyStencilClip_StateBit); 8321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com for (int p = 0; p < passes; ++p) { 8331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *drawState->stencil() = stencilSettings[p]; 8341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (canDrawDirectToClip) { 8358182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if (Element::kRect_Type == element->getType()) { 8361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 83701c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon fGpu->drawSimpleRect(element->getRect()); 8381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 8391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 840e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org pr->drawPath(clipPath, stroke, fGpu, false); 8411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 8431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 8444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The view matrix is setup to do clip space -> stencil space translation, so 8454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // draw rect in clip space. 84601c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon fGpu->drawSimpleRect(SkRect::Make(clipSpaceIBounds)); 8471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 851c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com // set this last because recursive draws may overwrite it back to kNone. 852f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); 853c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kStencil_ClipMaskType; 8541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return true; 8551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 8561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 857f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com 858411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping of clip-respecting stencil funcs to normal stencil funcs 859411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping depends on whether stencil-clipping is in effect. 860fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic const GrStencilFunc 861411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = { 862411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com {// Stencil-Clipping is DISABLED, we are effectively always inside the clip 863411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // In the Clip Funcs 864411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc 865411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 866411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kLessIfInClip_StencilFunc 867411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 868411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // Special in the clip func that forces user's ref to be 0. 869411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc 870411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // make ref 0 and do normal nequal. 871411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com }, 872411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com {// Stencil-Clipping is ENABLED 873411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // In the Clip Funcs 874411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc 875411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // eq stencil clip bit, mask 876411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // out user bits. 877411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 878411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 879411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // add stencil bit to mask and ref 880411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 881411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kLessIfInClip_StencilFunc 882411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 883411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // for both of these we can add 884411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // the clip bit to the mask and 885411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // ref and compare as normal 886411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // Special in the clip func that forces user's ref to be 0. 887411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc 888411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // make ref have only the clip bit set 889411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // and make comparison be less 890411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // 10..0 < 1..user_bits.. 891411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 892411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}; 893411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 894a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace { 895a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// Sets the settings to clip against the stencil buffer clip while ignoring the 896a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// client bits. 897a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comconst GrStencilSettings& basic_apply_stencil_clip_settings() { 898a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // stencil settings to use when clip is in stencil 899a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings, 900a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kKeep_StencilOp, 901a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kKeep_StencilOp, 902a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kAlwaysIfInClip_StencilFunc, 903a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 0x0000, 904a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 0x0000, 905fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 0x0000); 906a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); 907a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 908a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 909a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 910a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::setGpuStencil() { 911a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We make two copies of the StencilSettings here (except in the early 912a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // exit scenario. One copy from draw state to the stack var. Then another 913a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // from the stack var to the gpu. We could make this class hold a ptr to 914a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // GrGpu's fStencilSettings and eliminate the stack copy here. 915a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 916a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com const GrDrawState& drawState = fGpu->getDrawState(); 917a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 918a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // use stencil for clipping if clipping is enabled and the clip 919a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // has been written into the stencil. 920a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrClipMaskManager::StencilClipMode clipMode; 921a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (this->isClipInStencil() && drawState.isClipState()) { 922a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kRespectClip_StencilClipMode; 923a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We can't be modifying the clip and respecting it at the same time. 924f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!drawState.isStateFlagEnabled( 925a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrGpu::kModifyStencilClip_StateBit)); 926a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else if (drawState.isStateFlagEnabled( 927a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrGpu::kModifyStencilClip_StateBit)) { 928a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kModifyClip_StencilClipMode; 929a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 930a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode; 931a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 932a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 933a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilSettings settings; 934a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // The GrGpu client may not be using the stencil buffer but we may need to 935a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // enable it in order to respect a stencil clip. 936a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (drawState.getStencil().isDisabled()) { 937a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) { 938a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings = basic_apply_stencil_clip_settings(); 939a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 940a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableStencil(); 941a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return; 942a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 943a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 944a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings = drawState.getStencil(); 945a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 946a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 947a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // TODO: dynamically attach a stencil buffer 948a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int stencilBits = 0; 949fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com GrStencilBuffer* stencilBuffer = 950a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com drawState.getRenderTarget()->getStencilBuffer(); 95149f085dddff10473b6ebf832a974288300224e60bsalomon if (stencilBuffer) { 952a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com stencilBits = stencilBuffer->bits(); 953a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 954a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 955f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(fGpu->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); 956f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(fGpu->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); 957a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->adjustStencilParams(&settings, clipMode, stencilBits); 958a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->setStencilSettings(settings); 959a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 960a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 961a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, 962a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com StencilClipMode mode, 963a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int stencilBitCnt) { 964f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(stencilBitCnt > 0); 965411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 966411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com if (kModifyClip_StencilClipMode == mode) { 967a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We assume that this clip manager itself is drawing to the GrGpu and 968a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // has already setup the correct values. 969a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return; 970411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 971a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 972411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com unsigned int clipBit = (1 << (stencilBitCnt - 1)); 973411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com unsigned int userBits = clipBit - 1; 974411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 975a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilSettings::Face face = GrStencilSettings::kFront_Face; 976bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com bool twoSided = fGpu->caps()->twoSidedStencilSupport(); 977a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 978a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com bool finished = false; 979a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com while (!finished) { 980a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilFunc func = settings->func(face); 981a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t writeMask = settings->writeMask(face); 982a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t funcMask = settings->funcMask(face); 983a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t funcRef = settings->funcRef(face); 984a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 985f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT((unsigned) func < kStencilFuncCount); 986a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 987a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com writeMask &= userBits; 988a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 989a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (func >= kBasicStencilFuncCount) { 990a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int respectClip = kRespectClip_StencilClipMode == mode; 991a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (respectClip) { 992a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // The GrGpu class should have checked this 993f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(this->isClipInStencil()); 994a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com switch (func) { 995a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kAlwaysIfInClip_StencilFunc: 996a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = clipBit; 997a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = clipBit; 998a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 999a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kEqualIfInClip_StencilFunc: 1000a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kLessIfInClip_StencilFunc: 1001a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kLEqualIfInClip_StencilFunc: 1002a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = (funcMask & userBits) | clipBit; 1003a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = (funcRef & userBits) | clipBit; 1004a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 1005a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kNonZeroIfInClip_StencilFunc: 1006a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = (funcMask & userBits) | clipBit; 1007a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = clipBit; 1008a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 1009a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com default: 101088cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org SkFAIL("Unknown stencil func"); 1011a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1012a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1013a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask &= userBits; 1014a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef &= userBits; 1015411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1016fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com const GrStencilFunc* table = 1017a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com gSpecialToBasicStencilFunc[respectClip]; 1018a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com func = table[func - kBasicStencilFuncCount]; 1019f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(func >= 0 && func < kBasicStencilFuncCount); 1020411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } else { 1021a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask &= userBits; 1022a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef &= userBits; 1023411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1024a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1025a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFunc(face, func); 1026a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setWriteMask(face, writeMask); 1027a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFuncMask(face, funcMask); 1028a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFuncRef(face, funcRef); 1029a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1030a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (GrStencilSettings::kFront_Face == face) { 1031a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com face = GrStencilSettings::kBack_Face; 1032a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com finished = !twoSided; 1033a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1034a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com finished = true; 1035a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1036a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1037a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (!twoSided) { 1038a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->copyFrontSettingsToBack(); 1039411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1040411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com} 1041411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 1042411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com//////////////////////////////////////////////////////////////////////////////// 1043d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgGrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID, 10444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com GrReducedClip::InitialState initialState, 10454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const GrReducedClip::ElementList& elements, 10464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const SkIRect& clipSpaceIBounds) { 1047f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); 10486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1049ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds); 105049f085dddff10473b6ebf832a974288300224e60bsalomon if (result) { 10514c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return result; 10526b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 10536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 10544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // The mask texture may be larger than necessary. We round out the clip space bounds and pin 10554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // the top left corner of the resulting rect to the top left of the texture. 10564c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height()); 10574c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 10582c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com GrSWMaskHelper helper(this->getContext()); 10596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1060b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix matrix; 10614c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft), 10624c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com SkIntToScalar(-clipSpaceIBounds.fTop)); 106371614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski helper.init(maskSpaceIBounds, &matrix, false); 10644c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com 10654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com helper.clear(kAllIn_InitialState == initialState ? 0xFF : 0x00); 1066fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 10675f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 106812b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com 106949f085dddff10473b6ebf832a974288300224e60bsalomon for (ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) { 1070fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 10714c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com const Element* element = iter.get(); 10728182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com SkRegion::Op op = element->getOp(); 1073fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 10744c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { 10754c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // Intersect and reverse difference require modifying pixels outside of the geometry 10764c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // that is being "drawn". In both cases we erase all the pixels outside of the geometry 10774c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // but leave the pixels inside the geometry alone. For reverse difference we invert all 10784c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com // the pixels before clearing the ones outside the geometry. 1079fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com if (SkRegion::kReverseDifference_Op == op) { 10804469938e92d779dff05e745559e67907bbf21e78reed@google.com SkRect temp = SkRect::Make(clipSpaceIBounds); 1081fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // invert the entire scene 1082366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF); 1083fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1084fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 10855c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org SkPath clipPath; 10865c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org element->asPath(&clipPath); 10875c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org clipPath.toggleInverseFillType(); 10885c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA(), 0x00); 1089fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1090fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com continue; 1091fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1092fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1093fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // The other ops (union, xor, diff) only affect pixels inside 1094fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // the geometry so they can just be drawn normally 10958182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if (Element::kRect_Type == element->getType()) { 10968182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com helper.draw(element->getRect(), op, element->isAA(), 0xFF); 10978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com } else { 10985c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org SkPath path; 10995c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org element->asPath(&path); 11005c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org helper.draw(path, stroke, op, element->isAA(), 0xFF); 11016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 11026b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 11036b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1104ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski // Allocate clip mask texture 1105ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, true); 1106ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski if (NULL == result) { 1107ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski fAACache.reset(); 1108ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski return NULL; 1109ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski } 1110d92cf2ebbfbb9d737ea4a551e64ffccb08376875robertphillips@google.com helper.toTexture(result); 11116b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1112c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 11134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com return result; 11146b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 11156b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1116f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 1117c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomonvoid GrClipMaskManager::purgeResources() { 1118c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon fAACache.purgeResources(); 11191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 11206e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com 11216e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.comvoid GrClipMaskManager::setGpu(GrGpu* gpu) { 11226e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com fGpu = gpu; 11236e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com fAACache.setContext(gpu->getContext()); 11246e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com} 1125c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org 1126c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.orgvoid GrClipMaskManager::adjustPathStencilParams(GrStencilSettings* settings) { 1127c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org const GrDrawState& drawState = fGpu->getDrawState(); 1128c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org GrClipMaskManager::StencilClipMode clipMode; 1129c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org if (this->isClipInStencil() && drawState.isClipState()) { 1130c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org clipMode = GrClipMaskManager::kRespectClip_StencilClipMode; 1131c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org // We can't be modifying the clip and respecting it at the same time. 1132c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org SkASSERT(!drawState.isStateFlagEnabled( 1133c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org GrGpu::kModifyStencilClip_StateBit)); 1134c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org } else if (drawState.isStateFlagEnabled( 1135c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org GrGpu::kModifyStencilClip_StateBit)) { 1136c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org clipMode = GrClipMaskManager::kModifyClip_StencilClipMode; 1137c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org } else { 1138c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode; 1139c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org } 1140c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org 1141c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org // TODO: dynamically attach a stencil buffer 1142c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org int stencilBits = 0; 1143c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org GrStencilBuffer* stencilBuffer = 1144c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org drawState.getRenderTarget()->getStencilBuffer(); 114549f085dddff10473b6ebf832a974288300224e60bsalomon if (stencilBuffer) { 1146c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org stencilBits = stencilBuffer->bits(); 1147c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org this->adjustStencilParams(settings, clipMode, stencilBits); 1148c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org } 1149c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org} 1150