GrClipMaskManager.cpp revision d9f7503e0cb0c4db856f53b4bdeec1332db6f296
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" 107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com#include "effects/GrTextureDomainEffect.h" 111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h" 121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h" 131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h" 141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrPathRenderer.h" 15a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com#include "GrPaint.h" 166b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h" 17fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAConvexPathRenderer.h" 18fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAHairLinePathRenderer.h" 1958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrSWMaskHelper.h" 2046a8600405e678718271f62c5994119b8d3241e9robertphillips@google.com#include "GrCacheID.h" 2146a8600405e678718271f62c5994119b8d3241e9robertphillips@google.com 2246a8600405e678718271f62c5994119b8d3241e9robertphillips@google.comGR_DEFINE_RESOURCE_CACHE_DOMAIN(GrClipMaskManager, GetAlphaMaskDomain) 23a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 24ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com#define GR_AA_CLIP 1 25a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 26f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 27a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.comnamespace { 28fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the 2908283afc265f1153834256fc1012519813ba6b73bsalomon@google.com// stage matrix this also alters the vertex layout 30fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comvoid setup_drawstate_aaclip(GrGpu* gpu, 31fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com GrTexture* result, 327b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com const GrIRect &devBound) { 33a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com GrDrawState* drawState = gpu->drawState(); 34a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com GrAssert(drawState); 35a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 36dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com static const int kMaskStage = GrPaint::kTotalStages+1; 37a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 38b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix mat; 39a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com mat.setIDiv(result->width(), result->height()); 40fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com mat.preTranslate(SkIntToScalar(-devBound.fLeft), 417b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com SkIntToScalar(-devBound.fTop)); 42a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com mat.preConcat(drawState->getViewMatrix()); 43a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 4408283afc265f1153834256fc1012519813ba6b73bsalomon@google.com drawState->stage(kMaskStage)->reset(); 457b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com 467b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); 477b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->stage(kMaskStage)->setEffect( 487b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::Create(result, 497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com mat, 507b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::MakeTexelDomain(result, domainTexels), 517b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::kDecal_WrapMode))->unref(); 52a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com} 53a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 548a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool path_needs_SW_renderer(GrContext* context, 5513b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrGpu* gpu, 5613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com const SkPath& path, 5713b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrPathFill fill, 5813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com bool doAA) { 598a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com // last (false) parameter disallows use of the SW path renderer 608a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com return NULL == context->getPathRenderer(path, fill, gpu, doAA, false); 618a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com} 628a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com 63a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.comGrPathFill get_path_fill(const SkPath& path) { 64a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com switch (path.getFillType()) { 65a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com case SkPath::kWinding_FillType: 66a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return kWinding_GrPathFill; 67a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com case SkPath::kEvenOdd_FillType: 68a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return kEvenOdd_GrPathFill; 69a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com case SkPath::kInverseWinding_FillType: 70a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return kInverseWinding_GrPathFill; 71a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com case SkPath::kInverseEvenOdd_FillType: 72a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return kInverseEvenOdd_GrPathFill; 73a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com default: 74a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com GrCrash("Unsupported path fill in clip."); 75a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return kWinding_GrPathFill; // suppress warning 76a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } 77a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com} 78a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 79b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com/** 80b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com * Does any individual clip in 'clipIn' use anti-aliasing? 81b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com */ 82641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.combool requires_AA(const SkClipStack& clipIn) { 83b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 84641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack::Iter iter; 85641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com iter.reset(clipIn, SkClipStack::Iter::kBottom_IterStart); 86b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 87641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = NULL; 88b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com for (clip = iter.skipToTopmost(SkRegion::kReplace_Op); 89b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com NULL != clip; 90e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com clip = iter.nextCombined()) { 91b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 92b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com if (clip->fDoAA) { 93b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com return true; 94b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com } 95b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com } 96b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 97b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com return false; 98b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com} 99b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 1006b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 1016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 102fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/* 103fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer 104fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the 105fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu. 106fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */ 107641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.combool GrClipMaskManager::useSWOnlyPath(const SkClipStack& clipIn) { 108a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com 1098a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com // TODO: generalize this function so that when 110fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // a clip gets complex enough it can just be done in SW regardless 111fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // of whether it would invoke the GrSoftwarePathRenderer. 112fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com bool useSW = false; 113fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 114641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack::Iter iter(clipIn, SkClipStack::Iter::kBottom_IterStart); 115641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = NULL; 116fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 117a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com for (clip = iter.skipToTopmost(SkRegion::kReplace_Op); 118a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com NULL != clip; 119e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com clip = iter.nextCombined()) { 120fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 121f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com // rects can always be drawn directly w/o using the software path 122f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com // so only paths need to be checked 123a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fPath && 124fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com path_needs_SW_renderer(this->getContext(), fGpu, 125fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com *clip->fPath, 126a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com get_path_fill(*clip->fPath), 127a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com clip->fDoAA)) { 128f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com useSW = true; 129fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 130fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 131fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 132fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com return useSW; 133a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com} 134a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 135f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 1366b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil, 1376b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software 138beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn) { 139c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kNone_ClipMaskType; 140a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 14113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 142f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (!drawState->isClipState() || clipDataIn->fClipStack->isWideOpen()) { 143a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableScissor(); 144a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 1451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return true; 1461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 1471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 1481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrRenderTarget* rt = drawState->getRenderTarget(); 1491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // GrDrawTarget should have filtered this for us 1501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrAssert(NULL != rt); 1511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 1527b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect devClipBounds; 153e4d69c0e46c1a000eb89ef950bdaf0aea680a816robertphillips@google.com bool isIntersectionOfRects = false; 1543e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com 1557b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com clipDataIn->getConservativeBounds(rt, &devClipBounds, &isIntersectionOfRects); 1567b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (devClipBounds.isEmpty()) { 1573e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com return false; 158a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 159a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1606794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com#if GR_AA_CLIP 161beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com bool requiresAA = requires_AA(*clipDataIn->fClipStack); 162b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com 163a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // If MSAA is enabled we can do everything in the stencil buffer. 164fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // Otherwise check if we should just create the entire clip mask 165a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // in software (this will only happen if the clip mask is anti-aliased 166a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // and too complex for the gpu to handle in its entirety) 167f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (0 == rt->numSamples() && 168fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com requiresAA && 169beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com this->useSWOnlyPath(*clipDataIn->fClipStack)) { 1706b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com // The clip geometry is complex enough that it will be more 1716b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com // efficient to create it entirely in software 1726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com GrTexture* result = NULL; 1737b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect devBound; 1747b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (this->createSoftwareClipMask(*clipDataIn, &result, &devBound)) { 1757b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com setup_drawstate_aaclip(fGpu, result, devBound); 176a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableScissor(); 177a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 1786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return true; 1796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 180a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com 181a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // if SW clip mask creation fails fall through to the other 182a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // two possible methods (bottoming out at stencil clipping) 1836b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 1846b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 185f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // If MSAA is enabled use the (faster) stencil path for AA clipping 186f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // otherwise the alpha clip mask is our only option 187b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com if (0 == rt->numSamples() && requiresAA) { 188f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // Since we are going to create a destination texture of the correct 189f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // size for the mask (rather than being bound by the size of the 190f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // render target) we aren't going to use scissoring like the stencil 191f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // path does (see scissorSettings below) 192a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com GrTexture* result = NULL; 1937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect devBound; 1947b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (this->createAlphaClipMask(*clipDataIn, &result, &devBound)) { 1957b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com setup_drawstate_aaclip(fGpu, result, devBound); 196a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableScissor(); 197a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 198f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return true; 199f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 200f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 201f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // if alpha clip mask creation fails fall through to the stencil 202f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // buffer method 203f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 204f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP 205f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 206fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // Either a hard (stencil buffer) clip was explicitly requested or 2075acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com // an antialiased clip couldn't be created. In either case, free up 2085acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com // the texture in the antialiased mask cache. 2095acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com // TODO: this may require more investigation. Ganesh performs a lot of 210a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit 211fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // the stencil buffer path. These may be "incorrectly" clearing the 2125acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com // AA cache. 2135acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com fAACache.reset(); 2145acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com 215a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // If the clip is a rectangle then just set the scissor. Otherwise, create 216a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // a stencil mask. 217f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (isIntersectionOfRects) { 2187b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com fGpu->enableScissor(devClipBounds); 219a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 220a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return true; 2211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 2221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // use the stencil clip if we can't represent the clip as a rectangle. 224fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com bool useStencil = !clipDataIn->fClipStack->isWideOpen() && 2257b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com !devClipBounds.isEmpty(); 2261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 227c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com if (useStencil) { 2287b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com this->createStencilClipMask(*clipDataIn, devClipBounds); 2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 230a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // This must occur after createStencilClipMask. That function may change 231a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // the scissor. Also, it only guarantees that the stencil mask is correct 232a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // within the bounds it was passed, so we must use both stencil and scissor 233a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // test to the bounds for the final draw. 2347b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com fGpu->enableScissor(devClipBounds); 235a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->setGpuStencil(); 2361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return true; 2371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 2381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0 2401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP 2421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com #include "GrRandom.h" 2431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrRandom gRandom; 2441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); 2451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else 2461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com #define SET_RANDOM_COLOR 2471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif 2481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 2491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace { 2506623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com/** 2517b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * Does "canvContainer" contain "devContainee"? If either is empty then 2527b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * no containment is possible. "canvContainer" is in canvas coordinates while 2537b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * "devContainee" is in device coordiates. "origin" provides the mapping between 254f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com * the two. 2556623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com */ 256fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.combool contains(const SkRect& canvContainer, 2577b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com const SkIRect& devContainee, 258f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com const SkIPoint& origin) { 2597b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com return !devContainee.isEmpty() && !canvContainer.isEmpty() && 260fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com canvContainer.fLeft <= SkIntToScalar(devContainee.fLeft+origin.fX) && 2617b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com canvContainer.fTop <= SkIntToScalar(devContainee.fTop+origin.fY) && 262fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com canvContainer.fRight >= SkIntToScalar(devContainee.fRight+origin.fX) && 2637b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com canvContainer.fBottom >= SkIntToScalar(devContainee.fBottom+origin.fY); 2646623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com} 2656623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com 266f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 2671e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// determines how many elements at the head of the clip can be skipped and 2681e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// whether the initial clear should be to the inside- or outside-the-clip value, 2691e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// and what op should be used to draw the first element that isn't skipped. 270641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.comconst SkClipStack::Iter::Clip* process_initial_clip_elements( 271641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack::Iter* iter, 2727b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com const GrIRect& devBounds, 2731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com bool* clearToInside, 274f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com SkRegion::Op* firstOp, 275f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com const GrClipData& clipData) { 276a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 277a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com GrAssert(NULL != iter && NULL != clearToInside && NULL != firstOp); 2781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 279fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // logically before the first element of the clip stack is 2801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // processed the clip is entirely open. However, depending on the 2811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // first set op we may prefer to clear to 0 for performance. We may 2821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // also be able to skip the initial clip paths/rects. We loop until 2831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we cannot skip an element. 2841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com bool done = false; 2851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *clearToInside = true; 2861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 287641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = NULL; 288a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 289a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com for (clip = iter->skipToTopmost(SkRegion::kReplace_Op); 290a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com NULL != clip && !done; 291e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com clip = iter->nextCombined()) { 292a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com switch (clip->fOp) { 2930f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kReplace_Op: 2941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // replace ignores everything previous 295a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kReplace_Op; 2961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *clearToInside = false; 2971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 2981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 2990f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kIntersect_Op: 3001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // if this element contains the entire bounds then we 3011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // can skip it. 302f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (NULL != clip->fRect && 3037b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com contains(*clip->fRect, devBounds, clipData.fOrigin)) { 3041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // if everything is initially clearToInside then intersect is 3071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // same as clear to 0 and treat as a replace. Otherwise, 3081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // set stays empty. 3091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (*clearToInside) { 310a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kReplace_Op; 3111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *clearToInside = false; 3121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 3131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we can skip a leading union. 3160f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kUnion_Op: 3171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // if everything is initially outside then union is 318fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // same as replace. Otherwise, every pixel is still 3191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // clearToInside 3201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (!*clearToInside) { 321a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kReplace_Op; 3221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 3231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3250f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kXOR_Op: 3261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // xor is same as difference or replace both of which 3271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // can be 1-pass instead of 2 for xor. 3281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (*clearToInside) { 329a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kDifference_Op; 3301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 331a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kReplace_Op; 3321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 3341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3350f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kDifference_Op: 3361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // if all pixels are clearToInside then we have to process the 3371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // difference, otherwise it has no effect and all pixels 3381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // remain outside. 3391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (*clearToInside) { 340a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kDifference_Op; 3411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3440f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com case SkRegion::kReverseDifference_Op: 3451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // if all pixels are clearToInside then reverse difference 3466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // produces empty set. Otherwise it is same as replace 3471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (*clearToInside) { 3481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *clearToInside = false; 3491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 350a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com *firstOp = SkRegion::kReplace_Op; 3511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com done = true; 3521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 3531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com break; 3541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com default: 3551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrCrash("Unknown set op."); 3561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 357a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 358a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (done) { 359a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com // we need to break out here (rather than letting the test in 360a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com // the loop do it) since backing up the iterator is very expensive 361a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com break; 362a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } 3631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 364a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com return clip; 3651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 366f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 367f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 369f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comnamespace { 370f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 371f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 372fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the OpenGL blend function to perform the specified 373fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// boolean operation for alpha clip mask creation 3746b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) { 375f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 376f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com switch (op) { 377f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kReplace_Op: 37847059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); 379f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 380f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kIntersect_Op: 38147059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); 382f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 383f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kUnion_Op: 38447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 385f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 386f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kXOR_Op: 38747059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); 388f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 389f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kDifference_Op: 39047059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); 391f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 392f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com case SkRegion::kReverseDifference_Op: 39347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); 394f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 395f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com default: 396f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrAssert(false); 397f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com break; 398f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 399f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 400f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 401366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 402366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 40372176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com 4047b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com// 'rect' enters in device coordinates and leaves in canvas coordinates 4057b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.comvoid device_to_canvas(SkRect* rect, const SkIPoint& origin) { 4067b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrAssert(NULL != rect); 4077b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com 4087b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com rect->fLeft += SkIntToScalar(origin.fX); 4097b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com rect->fTop += SkIntToScalar(origin.fY); 4107b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com rect->fRight += SkIntToScalar(origin.fX); 4117b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com rect->fBottom += SkIntToScalar(origin.fY); 4127b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com} 4137b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com 41472176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com} 415f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 416f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 41713b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.combool GrClipMaskManager::drawClipShape(GrTexture* target, 418641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip, 4196794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com const SkIRect& clipRect) { 42013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 421f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrAssert(NULL != drawState); 422f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 423f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com drawState->setRenderTarget(target->asRenderTarget()); 424f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4256794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GrDrawTarget::AutoClipRestore acr(fGpu); 4266794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkClipStack rectStack(clipRect); 4276794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GrClipData cd; 4286794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com cd.fClipStack = &rectStack; 4296794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com cd.fOrigin.setZero(); 4306794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com fGpu->setClip(&cd); 4316794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 432a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 433a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (clip->fDoAA) { 43413b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu, 435f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com *clip->fRect, 436f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com true); 437f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } else { 438a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com fGpu->drawSimpleRect(*clip->fRect, NULL); 439f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 440a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } else if (NULL != clip->fPath) { 4416794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 4426794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GrPathRenderer* pr = this->getContext()->getPathRenderer(*clip->fPath, 4436794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com get_path_fill(*clip->fPath), 4446794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com fGpu, 4456794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com clip->fDoAA, 4466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com false); 4476794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com if (NULL == pr) { 4486794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GrAssert(false); // We should have done the whole clip-stack in SW. 4496794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com return false; 4506794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } 4516794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 4526794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com pr->drawPath(*clip->fPath, get_path_fill(*clip->fPath), fGpu, clip->fDoAA); 453f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 454f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return true; 455f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 456f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4577b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.comvoid GrClipMaskManager::mergeMask(GrTexture* dstMask, 4587b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTexture* srcMask, 4597b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkRegion::Op op, 4607b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com const GrIRect& dstBound, 4617b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com const GrIRect& srcBound) { 46213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 463f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrAssert(NULL != drawState); 4647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkMatrix oldMatrix = drawState->getViewMatrix(); 4657b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->viewMatrix()->reset(); 466f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4677b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->setRenderTarget(dstMask->asRenderTarget()); 468f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4697b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com setup_boolean_blendcoeffs(drawState, op); 47072b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com 471b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix sampleM; 4727b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com sampleM.setIDiv(srcMask->width(), srcMask->height()); 4737b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->stage(0)->setEffect( 4747b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::Create(srcMask, 4757b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com sampleM, 4767b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound), 4777b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrTextureDomainEffect::kDecal_WrapMode))->unref(); 4787b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL); 479f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 480676e66096c60615bac52f365111596de5c4ca8a6tomhudson@google.com drawState->disableStage(0); 4817b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->setViewMatrix(oldMatrix); 482f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com} 483f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 4846d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations 4856d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too 486fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comvoid GrClipMaskManager::getTemp(const GrIRect& bounds, 487f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com GrAutoScratchTexture* temp) { 488f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com if (NULL != temp->texture()) { 4896d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com // we've already allocated the temp texture 4906d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com return; 4916d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com } 4926d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 49375b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com GrTextureDesc desc; 49475b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit; 49575b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fWidth = bounds.width(); 49675b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fHeight = bounds.height(); 49775b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fConfig = kAlpha_8_GrPixelConfig; 4986b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 4992c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com temp->set(this->getContext(), desc); 5006d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com} 5016d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 5026d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 503641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.comvoid GrClipMaskManager::setupCache(const SkClipStack& clipIn, 5046623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com const GrIRect& bounds) { 505f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com // Since we are setting up the cache we know the last lookup was a miss 506f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com // Free up the currently cached mask so it can be reused 507f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.reset(); 5086d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 50975b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com GrTextureDesc desc; 51075b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit; 51175b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fWidth = bounds.width(); 51275b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fHeight = bounds.height(); 51375b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com desc.fConfig = kAlpha_8_GrPixelConfig; 514f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 515f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.acquireMask(clipIn, desc, bounds); 516f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com} 517f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 5186b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 5196b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Shared preamble between gpu and SW-only AA clip mask creation paths. 5206b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Handles caching, determination of clip mask bound & allocation (if needed) 5216b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// of the result texture 5226b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Returns true if there is no more work to be done (i.e., we got a cache hit) 523beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::clipMaskPreamble(const GrClipData& clipDataIn, 5246b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com GrTexture** result, 5257b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect* devResultBounds) { 52613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* origDrawState = fGpu->drawState(); 527f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrAssert(origDrawState->isClipState()); 528f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 529f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrRenderTarget* rt = origDrawState->getRenderTarget(); 530f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com GrAssert(NULL != rt); 531f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 532f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // unlike the stencil path the alpha path is not bound to the size of the 533f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // render target - determine the minimum size required for the mask 534f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com // Note: intBounds is in device (as opposed to canvas) coordinates 5359cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com clipDataIn.getConservativeBounds(rt, devResultBounds); 536f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 537f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // need to outset a pixel since the standard bounding box computation 5386794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // path doesn't leave any room for anti-aliasing (esp. w.r.t. rects) 5399cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com devResultBounds->outset(1, 1); 540f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 541a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com // TODO: make sure we don't outset if bounds are still 0,0 @ min 542a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com 543ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com if (fAACache.canReuse(*clipDataIn.fClipStack, *devResultBounds)) { 5448fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com *result = fAACache.getLastMask(); 5457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com fAACache.getLastBound(devResultBounds); 5468fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com return true; 5478fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com } 5488fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com 5499cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com this->setupCache(*clipDataIn.fClipStack, *devResultBounds); 5506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return false; 5516b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 552f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 5536794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.comnamespace { 5546794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com// Does a look-ahead to check whether we can bound earlier mask generation by forthcoming 5556794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com// intersections. 5566794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.comvoid get_current_mask_bounds(const SkIRect& maskResultBounds, 5576794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com const SkClipStack::Iter& curr, 5586794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com const SkVector& clipToMaskOffset, 5596794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkRect* currMaskBounds) { 5606794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkClipStack::Iter isectIter(curr); 5616794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com const SkClipStack::Iter::Clip* clip = isectIter.skipToNext(SkRegion::kIntersect_Op); 5626794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com if (NULL != clip) { 5636794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com *currMaskBounds = clip->getBounds(); 5646794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com while (NULL != (clip = isectIter.next()) && 5656794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkRegion::kIntersect_Op == clip->fOp && 5666794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com !clip->isInverseFilled()) { 5676794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com currMaskBounds->intersect(clip->getBounds()); 5686794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } 5696794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com currMaskBounds->offset(clipToMaskOffset); 5706794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com currMaskBounds->intersect(SkRect::MakeFromIRect(maskResultBounds)); 5716794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } else { 5726794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com *currMaskBounds = SkRect::MakeFromIRect(maskResultBounds); 5736794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } 5746794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com} 5756794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com} 5766794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 5776b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 5786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha 579beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, 5806b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com GrTexture** result, 5817b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect *devResultBounds) { 5827b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrAssert(NULL != devResultBounds); 583c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 584c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com 5857b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) { 586c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 5876b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return true; 5886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 589f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 590f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com // Note: 'resultBounds' is in device (as opposed to canvas) coordinates 591f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com 592f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com GrTexture* accum = fAACache.getLastMask(); 5936d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com if (NULL == accum) { 594f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.reset(); 595f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return false; 596f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 597f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 59813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 59913b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 600f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 60113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawTarget::AutoGeometryPush agp(fGpu); 602f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 6037b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // The mask we generate is translated so that its upper-left corner is at devResultBounds 6047b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // upper-left corner in device space. 6057b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrIRect maskResultBounds = GrIRect::MakeWH(devResultBounds->width(), devResultBounds->height()); 6067b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com 6077b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // Set the matrix so that rendered clip elements are transformed from the space of the clip 6087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // stack to the alpha-mask. This accounts for both translation due to the clip-origin and the 6097b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // placement of the mask within the device. 6107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkVector clipToMaskOffset = { 6117b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkIntToScalar(-devResultBounds->fLeft - clipDataIn.fOrigin.fX), 6127b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com SkIntToScalar(-devResultBounds->fTop - clipDataIn.fOrigin.fY) 6137b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com }; 6147b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com drawState->viewMatrix()->setTranslate(clipToMaskOffset); 615f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 616f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com bool clearToInside; 617a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning 618a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 6196794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkClipStack::Iter iter(*clipDataIn.fClipStack, SkClipStack::Iter::kBottom_IterStart); 6206794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com iter.skipToTopmost(SkRegion::kReplace_Op); 6216794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 622641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter, 6237b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com *devResultBounds, 624a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com &clearToInside, 625f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com &firstOp, 626f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com clipDataIn); 6277b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // The scratch texture that we are drawing into can be substantially larger than the mask. Only 6287b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // clear the part that we care about. 6297b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com fGpu->clear(&maskResultBounds, 630fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com clearToInside ? 0xffffffff : 0x00000000, 631c82a8b7aa4ec19fba508c394920a9e88d3e5bd12robertphillips@google.com accum->asRenderTarget()); 6326794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GR_DEBUGCODE(bool accumClearedToZero = !clearToInside;) 633f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 634d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com 635f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com GrAutoScratchTexture temp; 636a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com bool first = true; 6376794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 6386794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // We bound mask-generation to both the known bounds of the final result as well as the bounds 6396794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // of the next run of intersections. This limits the amount of clearing and merging we have 6406794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // to do and can also allow us to skip intersect-rects entirely. 6416794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkRect currMaskBounds; 6426794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkIRect currMaskIBounds; 6436794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com get_current_mask_bounds(maskResultBounds, iter, clipToMaskOffset, &currMaskBounds); 6446794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // currMaskBounds is used to reduce the number of pixels touched. It also allows us to skip 6456794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // non-AA intersect rects since we've clipped earlier elements to those rects already. 6466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // We round out here which is consistent with how non-AA rects are handled. 6476794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com currMaskBounds.roundOut(&currMaskIBounds); 6486794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 6496794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // used to know when we're through with a run of intersect ops. 6506794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com SkRegion::Op prevOp = SkRegion::kReplace_Op; 6516794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 652f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // walk through each clip element and perform its set op 653e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com for ( ; NULL != clip; clip = iter.nextCombined()) { 654f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 655a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op op = clip->fOp; 656a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (first) { 657a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com first = false; 658a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com op = firstOp; 659a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } 660f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 6616794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com if (op == SkRegion::kIntersect_Op) { 6626794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // When we encounter an intersect we may have already fully accounted for it by applying 6636794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // currMaskBounds to the accumulated mask. 6646794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com if (NULL != clip->fRect && 6656794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com (!clip->fDoAA || clip->fRect->contains(currMaskBounds))) { 6666794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com prevOp = SkRegion::kIntersect_Op; 6676794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com continue; 6687b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com } 6696794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } else if (prevOp == SkRegion::kIntersect_Op) { 6706794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // We've finished a run of intersects, update currMaskBounds based on the next run. 6716794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com get_current_mask_bounds(maskResultBounds, iter, clipToMaskOffset, &currMaskBounds); 6726794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com currMaskBounds.roundOut(&currMaskIBounds); 6736794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com } 67472b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com 6756794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com prevOp = op; 6766794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com 6776794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com if (SkRegion::kReplace_Op == op) { 6786794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // The accumulator should already be cleared. There can only be one replace since we 6796794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // skip to the last one. Moreover, process_initial_clip_elements will have set 6806794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // clearToInside to false before the initial clear. 6816794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GrAssert(accumClearedToZero); 6826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com setup_boolean_blendcoeffs(drawState, op); 6836794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com this->drawClipShape(accum, clip, currMaskIBounds); 684f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 685f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } else if (SkRegion::kReverseDifference_Op == op || 686f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com SkRegion::kIntersect_Op == op) { 6876794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // There is no point in intersecting a screen filling rectangle. 688f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (SkRegion::kIntersect_Op == op && NULL != clip->fRect && 6897b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) { 690f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com continue; 691f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 692f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 6937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com getTemp(*devResultBounds, &temp); 694f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com if (NULL == temp.texture()) { 695f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.reset(); 6966d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com return false; 6976d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com } 6986d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com 6996794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // This is the bounds of the clip element in the space of the alpha-mask. The temporary 7007b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // mask buffer can be substantially larger than the actually clip stack element. We 7017b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com // touch the minimum number of pixels necessary and use decal mode to combine it with 7026794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // the accumulator. 7037b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrRect elementMaskBounds = clip->getBounds(); 7047b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com elementMaskBounds.offset(clipToMaskOffset); 7056794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com elementMaskBounds.intersect(currMaskBounds); 7067b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com GrIRect elementMaskIBounds; 7077b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com elementMaskBounds.roundOut(&elementMaskIBounds); 7087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com 7096794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // Clear the temp target & draw into it 7107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget()); 711f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 7126b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); 7136794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com this->drawClipShape(temp.texture(), clip, currMaskIBounds); 714f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 7156794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // Now draw into the accumulator using the real operation and the temp buffer as a 7166794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com // texture 7177b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com this->mergeMask(accum, temp.texture(), op, maskResultBounds, elementMaskIBounds); 718f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } else { 719fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // all the remaining ops can just be directly draw into 720f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com // the accumulation buffer 7216b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com setup_boolean_blendcoeffs(drawState, op); 7226794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com this->drawClipShape(accum, clip, currMaskIBounds); 723f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 7246794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com GR_DEBUGCODE(accumClearedToZero = false;) 725f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com } 726f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 727a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com *result = accum; 728c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 729f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com return true; 7301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 7311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 732f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 733fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device 734f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com// (as opposed to canvas) coordinates 735beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, 7367b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com const GrIRect& devClipBounds) { 7371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 738c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 7391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 74013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawState* drawState = fGpu->drawState(); 7411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrAssert(drawState->isClipState()); 7421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrRenderTarget* rt = drawState->getRenderTarget(); 7441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrAssert(NULL != rt); 7451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // TODO: dynamically attach a SB when needed. 7471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); 7481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (NULL == stencilBuffer) { 7491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return false; 7501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 7511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 752beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com if (stencilBuffer->mustRenderClip(clipDataIn, rt->width(), rt->height())) { 7531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 754beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com stencilBuffer->setLastClip(clipDataIn, rt->width(), rt->height()); 7551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we set the current clip to the bounds so that our recursive 7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // draws are scissored to them. We use the copy of the complex clip 7581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we just stashed on the SB to render from. We set it back after 7591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we finish drawing it into the stencil. 760beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com const GrClipData* oldClipData = fGpu->getClip(); 761beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com 7627b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com // The origin of 'newClipData' is (0, 0) so it is okay to place 7637b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com // a device-coordinate bound in 'newClipStack' 764641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack newClipStack(devClipBounds); 765beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com GrClipData newClipData; 766beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com newClipData.fClipStack = &newClipStack; 767beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com 768beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com fGpu->setClip(&newClipData); 7691e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 77013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 77113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com drawState = fGpu->drawState(); 7721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->setRenderTarget(rt); 77313b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com GrDrawTarget::AutoGeometryPush agp(fGpu); 7741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 775f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com if (0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) { 776fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // Add the saveLayer's offset to the view matrix rather than 777f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com // offset each individual draw 7787b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com drawState->viewMatrix()->setTranslate( 779fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkIntToScalar(-clipDataIn.fOrigin.fX), 780f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com SkIntToScalar(-clipDataIn.fOrigin.fY)); 781f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com } 782f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com 7831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP 7841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->enableState(GrDrawState::kNoColorWrites_StateBit); 7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif 7861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com int clipBit = stencilBuffer->bits(); 7881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SkASSERT((clipBit <= 16) && 7891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com "Ganesh only handles 16b or smaller stencil buffers"); 7901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com clipBit = (1 << (clipBit-1)); 7911e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7927b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect devRTRect = GrIRect::MakeWH(rt->width(), rt->height()); 7931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 7941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com bool clearToInside; 795a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning 796a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 797fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkClipStack::Iter iter(*oldClipData->fClipStack, 798641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack::Iter::kBottom_IterStart); 799641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter, 8007b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com devRTRect, 801ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com &clearToInside, 802f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com &firstOp, 803f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com clipDataIn); 8041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8057b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com fGpu->clearStencilClip(devClipBounds, clearToInside); 806a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com bool first = true; 8071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // walk through each clip element and perform its set op 8091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // with the existing clip. 810e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com for ( ; NULL != clip; clip = iter.nextCombined()) { 8111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrPathFill fill; 8128afae61a57f87e4a50578effce6c428031499301tomhudson@google.com bool fillInverted = false; 8131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // enabled at bottom of loop 8141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->disableState(GrGpu::kModifyStencilClip_StateBit); 815ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com // if the target is MSAA then we want MSAA enabled when the clip is soft 816ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com if (rt->isMultisampled()) { 817d5d69ffaea117428972db48796f7e75f0d1dab34bsalomon@google.com drawState->setState(GrDrawState::kHWAntialias_StateBit, clip->fDoAA); 818ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com } 8191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8208afae61a57f87e4a50578effce6c428031499301tomhudson@google.com // Can the clip element be drawn directly to the stencil buffer 8218afae61a57f87e4a50578effce6c428031499301tomhudson@google.com // with a non-inverted fill rule without extra passes to 8228afae61a57f87e4a50578effce6c428031499301tomhudson@google.com // resolve in/out status? 8238afae61a57f87e4a50578effce6c428031499301tomhudson@google.com bool canRenderDirectToStencil = false; 8241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 825a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op op = clip->fOp; 826a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (first) { 827a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com first = false; 828a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com op = firstOp; 829a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } 830f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com 8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrPathRenderer* pr = NULL; 8328d033a1b125886c62906d975b5cc28a382064526bsalomon@google.com const SkPath* clipPath = NULL; 833a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 8341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com canRenderDirectToStencil = true; 83547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com fill = kEvenOdd_GrPathFill; 8361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com fillInverted = false; 8371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // there is no point in intersecting a screen filling 8381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // rectangle. 839f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com if (SkRegion::kIntersect_Op == op && 8407b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) { 8411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com continue; 8421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8438afae61a57f87e4a50578effce6c428031499301tomhudson@google.com } else { 8448afae61a57f87e4a50578effce6c428031499301tomhudson@google.com GrAssert(NULL != clip->fPath); 845a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com fill = get_path_fill(*clip->fPath); 8461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com fillInverted = GrIsFillInverted(fill); 8471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com fill = GrNonInvertedFill(fill); 848a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com clipPath = clip->fPath; 8498afae61a57f87e4a50578effce6c428031499301tomhudson@google.com pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true); 8501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (NULL == pr) { 8518afae61a57f87e4a50578effce6c428031499301tomhudson@google.com fGpu->setClip(oldClipData); 8521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return false; 8531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com canRenderDirectToStencil = 85513b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com !pr->requiresStencilPass(*clipPath, fill, fGpu); 8561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com int passes; 8591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; 8601e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com bool canDrawDirectToClip; // Given the renderer, the element, 8621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // fill rule, and set operation can 8631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // we render the element directly to 8641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // stencil bit used for clipping. 8651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com canDrawDirectToClip = 8661e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GrStencilSettings::GetClipPasses(op, 8678afae61a57f87e4a50578effce6c428031499301tomhudson@google.com canRenderDirectToStencil, 8688afae61a57f87e4a50578effce6c428031499301tomhudson@google.com clipBit, 8698afae61a57f87e4a50578effce6c428031499301tomhudson@google.com fillInverted, 8708afae61a57f87e4a50578effce6c428031499301tomhudson@google.com &passes, 8718afae61a57f87e4a50578effce6c428031499301tomhudson@google.com stencilSettings); 8721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // draw the element to the client stencil bits if necessary 8741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (!canDrawDirectToClip) { 8751e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, 8761e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com kIncClamp_StencilOp, 8771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com kIncClamp_StencilOp, 8781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com kAlways_StencilFunc, 8791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 0xffff, 8801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 0x0000, 8811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 0xffff); 8821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 883a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 8841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *drawState->stencil() = gDrawToStencil; 885a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com fGpu->drawSimpleRect(*clip->fRect, NULL); 8861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 8871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (canRenderDirectToStencil) { 8881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *drawState->stencil() = gDrawToStencil; 8890f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com pr->drawPath(*clipPath, fill, fGpu, false); 8901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 89113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com pr->drawPathToStencil(*clipPath, fill, fGpu); 8921e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 8951e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 8961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // now we modify the clip bit by rendering either the clip 8971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // element directly or a bounding rect of the entire clip. 8981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com drawState->enableState(GrGpu::kModifyStencilClip_StateBit); 8991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com for (int p = 0; p < passes; ++p) { 9001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *drawState->stencil() = stencilSettings[p]; 9011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com if (canDrawDirectToClip) { 902a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 9031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 904a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com fGpu->drawSimpleRect(*clip->fRect, NULL); 9051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 9061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 9070f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com pr->drawPath(*clipPath, fill, fGpu, false); 9081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 9091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } else { 9101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com SET_RANDOM_COLOR 911fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // 'devClipBounds' is already in device coordinates so the 912fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // translation in the view matrix is inappropriate. 9137b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com // Convert it to canvas space so the drawn rect will 914f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com // be in the correct location 9157b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrRect canvClipBounds; 9167b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com canvClipBounds.set(devClipBounds); 9177b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com device_to_canvas(&canvClipBounds, clipDataIn.fOrigin); 9187b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com fGpu->drawSimpleRect(canvClipBounds, NULL); 9191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 9201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 9211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 9221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com // restore clip 923beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com fGpu->setClip(oldClipData); 9241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com } 925c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com // set this last because recursive draws may overwrite it back to kNone. 926c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 927c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kStencil_ClipMaskType; 9281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com return true; 9291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 9301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com 931f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com 932411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping of clip-respecting stencil funcs to normal stencil funcs 933411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping depends on whether stencil-clipping is in effect. 934fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic const GrStencilFunc 935411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = { 936411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com {// Stencil-Clipping is DISABLED, we are effectively always inside the clip 937411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // In the Clip Funcs 938411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc 939411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 940411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kLessIfInClip_StencilFunc 941411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 942411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // Special in the clip func that forces user's ref to be 0. 943411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc 944411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // make ref 0 and do normal nequal. 945411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com }, 946411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com {// Stencil-Clipping is ENABLED 947411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // In the Clip Funcs 948411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc 949411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // eq stencil clip bit, mask 950411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // out user bits. 951411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 952411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kEqual_StencilFunc, // kEqualIfInClip_StencilFunc 953411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // add stencil bit to mask and ref 954411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 955411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kLessIfInClip_StencilFunc 956411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc 957411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // for both of these we can add 958411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // the clip bit to the mask and 959411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // ref and compare as normal 960411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // Special in the clip func that forces user's ref to be 0. 961411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc 962411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // make ref have only the clip bit set 963411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // and make comparison be less 964411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com // 10..0 < 1..user_bits.. 965411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 966411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}; 967411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 968a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace { 969a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// Sets the settings to clip against the stencil buffer clip while ignoring the 970a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// client bits. 971a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comconst GrStencilSettings& basic_apply_stencil_clip_settings() { 972a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // stencil settings to use when clip is in stencil 973a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings, 974a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kKeep_StencilOp, 975a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kKeep_StencilOp, 976a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com kAlwaysIfInClip_StencilFunc, 977a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 0x0000, 978a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 0x0000, 979fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 0x0000); 980a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); 981a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 982a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 983a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 984a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::setGpuStencil() { 985a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We make two copies of the StencilSettings here (except in the early 986a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // exit scenario. One copy from draw state to the stack var. Then another 987a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // from the stack var to the gpu. We could make this class hold a ptr to 988a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // GrGpu's fStencilSettings and eliminate the stack copy here. 989a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 990a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com const GrDrawState& drawState = fGpu->getDrawState(); 991a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 992a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // use stencil for clipping if clipping is enabled and the clip 993a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // has been written into the stencil. 994a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrClipMaskManager::StencilClipMode clipMode; 995a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (this->isClipInStencil() && drawState.isClipState()) { 996a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kRespectClip_StencilClipMode; 997a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We can't be modifying the clip and respecting it at the same time. 998a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrAssert(!drawState.isStateFlagEnabled( 999a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrGpu::kModifyStencilClip_StateBit)); 1000a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else if (drawState.isStateFlagEnabled( 1001a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrGpu::kModifyStencilClip_StateBit)) { 1002a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kModifyClip_StencilClipMode; 1003a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1004a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode; 1005a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1006a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1007a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilSettings settings; 1008a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // The GrGpu client may not be using the stencil buffer but we may need to 1009a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // enable it in order to respect a stencil clip. 1010a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (drawState.getStencil().isDisabled()) { 1011a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) { 1012a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings = basic_apply_stencil_clip_settings(); 1013a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1014a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->disableStencil(); 1015a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return; 1016a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1017a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1018a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings = drawState.getStencil(); 1019a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1020a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1021a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // TODO: dynamically attach a stencil buffer 1022a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int stencilBits = 0; 1023fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com GrStencilBuffer* stencilBuffer = 1024a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com drawState.getRenderTarget()->getStencilBuffer(); 1025a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (NULL != stencilBuffer) { 1026a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com stencilBits = stencilBuffer->bits(); 1027a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1028a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1029f66018798099750e639a8fa131fece492a050997bsalomon@google.com GrAssert(fGpu->getCaps().stencilWrapOpsSupport() || 10309e553c6e7cff5fd699ed4dee1d52317362ea30d0bsalomon@google.com !settings.usesWrapOp()); 1031f66018798099750e639a8fa131fece492a050997bsalomon@google.com GrAssert(fGpu->getCaps().twoSidedStencilSupport() || !settings.isTwoSided()); 1032a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com this->adjustStencilParams(&settings, clipMode, stencilBits); 1033a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com fGpu->setStencilSettings(settings); 1034a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com} 1035a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1036a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, 1037a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com StencilClipMode mode, 1038a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int stencilBitCnt) { 1039411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com GrAssert(stencilBitCnt > 0); 1040411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 1041411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com if (kModifyClip_StencilClipMode == mode) { 1042a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // We assume that this clip manager itself is drawing to the GrGpu and 1043a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // has already setup the correct values. 1044a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com return; 1045411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1046a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1047411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com unsigned int clipBit = (1 << (stencilBitCnt - 1)); 1048411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com unsigned int userBits = clipBit - 1; 1049411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 1050a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilSettings::Face face = GrStencilSettings::kFront_Face; 1051f66018798099750e639a8fa131fece492a050997bsalomon@google.com bool twoSided = fGpu->getCaps().twoSidedStencilSupport(); 1052a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1053a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com bool finished = false; 1054a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com while (!finished) { 1055a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrStencilFunc func = settings->func(face); 1056a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t writeMask = settings->writeMask(face); 1057a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t funcMask = settings->funcMask(face); 1058a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com uint16_t funcRef = settings->funcRef(face); 1059a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1060a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrAssert((unsigned) func < kStencilFuncCount); 1061a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1062a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com writeMask &= userBits; 1063a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1064a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (func >= kBasicStencilFuncCount) { 1065a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com int respectClip = kRespectClip_StencilClipMode == mode; 1066a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (respectClip) { 1067a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // The GrGpu class should have checked this 1068a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrAssert(this->isClipInStencil()); 1069a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com switch (func) { 1070a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kAlwaysIfInClip_StencilFunc: 1071a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = clipBit; 1072a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = clipBit; 1073a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 1074a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kEqualIfInClip_StencilFunc: 1075a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kLessIfInClip_StencilFunc: 1076a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kLEqualIfInClip_StencilFunc: 1077a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = (funcMask & userBits) | clipBit; 1078a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = (funcRef & userBits) | clipBit; 1079a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 1080a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com case kNonZeroIfInClip_StencilFunc: 1081a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask = (funcMask & userBits) | clipBit; 1082a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef = clipBit; 1083a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com break; 1084a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com default: 1085a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrCrash("Unknown stencil func"); 1086a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1087a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1088a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask &= userBits; 1089a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef &= userBits; 1090411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1091fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com const GrStencilFunc* table = 1092a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com gSpecialToBasicStencilFunc[respectClip]; 1093a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com func = table[func - kBasicStencilFuncCount]; 1094a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com GrAssert(func >= 0 && func < kBasicStencilFuncCount); 1095411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } else { 1096a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcMask &= userBits; 1097a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com funcRef &= userBits; 1098411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1099a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1100a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFunc(face, func); 1101a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setWriteMask(face, writeMask); 1102a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFuncMask(face, funcMask); 1103a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->setFuncRef(face, funcRef); 1104a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 1105a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (GrStencilSettings::kFront_Face == face) { 1106a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com face = GrStencilSettings::kBack_Face; 1107a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com finished = !twoSided; 1108a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } else { 1109a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com finished = true; 1110a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1111a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com } 1112a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com if (!twoSided) { 1113a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com settings->copyFrontSettingsToBack(); 1114411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com } 1115411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com} 1116411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 1117411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com//////////////////////////////////////////////////////////////////////////////// 1118411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com 1119fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comnamespace { 1120fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1121fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comGrPathFill invert_fill(GrPathFill fill) { 1122fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com static const GrPathFill gInvertedFillTable[] = { 112347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com kInverseWinding_GrPathFill, // kWinding_GrPathFill 112447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com kInverseEvenOdd_GrPathFill, // kEvenOdd_GrPathFill 112547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com kWinding_GrPathFill, // kInverseWinding_GrPathFill 112647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com kEvenOdd_GrPathFill, // kInverseEvenOdd_GrPathFill 112747059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com kHairLine_GrPathFill, // kHairLine_GrPathFill 1128fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com }; 112947059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(0 == kWinding_GrPathFill); 113047059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(1 == kEvenOdd_GrPathFill); 113147059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(2 == kInverseWinding_GrPathFill); 113247059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(3 == kInverseEvenOdd_GrPathFill); 113347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(4 == kHairLine_GrPathFill); 113447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com GR_STATIC_ASSERT(5 == kGrPathFillCount); 1135fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com return gInvertedFillTable[fill]; 1136fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com} 1137fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1138fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com} 1139fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1140beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn, 11416b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com GrTexture** result, 11427b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com GrIRect* devResultBounds) { 1143c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com GrAssert(kNone_ClipMaskType == fCurrClipMaskType); 11446b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 11457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) { 11466b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return true; 11476b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 11486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1149f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com GrTexture* accum = fAACache.getLastMask(); 11506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com if (NULL == accum) { 1151f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.reset(); 11526b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return false; 11536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 11546b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 11552c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com GrSWMaskHelper helper(this->getContext()); 11566b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1157b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix matrix; 1158fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com matrix.setTranslate(SkIntToScalar(-clipDataIn.fOrigin.fX), 1159f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com SkIntToScalar(-clipDataIn.fOrigin.fY)); 11607b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com helper.init(*devResultBounds, &matrix); 1161fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1162fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com bool clearToInside; 1163a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning 1164a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com 1165fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkClipStack::Iter iter(*clipDataIn.fClipStack, 1166641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com SkClipStack::Iter::kBottom_IterStart); 1167641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter, 11687b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com *devResultBounds, 1169fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com &clearToInside, 1170f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com &firstOp, 1171f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com clipDataIn); 1172fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1173366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com helper.clear(clearToInside ? 0xFF : 0x00); 1174fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1175a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com bool first = true; 1176e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com for ( ; NULL != clip; clip = iter.nextCombined()) { 1177fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1178a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com SkRegion::Op op = clip->fOp; 1179a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (first) { 1180a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com first = false; 1181a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com op = firstOp; 1182a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } 1183fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1184fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com if (SkRegion::kIntersect_Op == op || 1185fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com SkRegion::kReverseDifference_Op == op) { 1186fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // Intersect and reverse difference require modifying pixels 1187fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // outside of the geometry that is being "drawn". In both cases 1188fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // we erase all the pixels outside of the geometry but 1189fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // leave the pixels inside the geometry alone. For reverse 1190fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // difference we invert all the pixels before clearing the ones 1191fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // outside the geometry. 1192fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com if (SkRegion::kReverseDifference_Op == op) { 11937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com SkRect temp; 11947b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com temp.set(*devResultBounds); 1195ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com temp.offset(SkIntToScalar(clipDataIn.fOrigin.fX), 1196ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com SkIntToScalar(clipDataIn.fOrigin.fX)); 1197fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1198fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // invert the entire scene 1199366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF); 1200fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1201fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1202a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 1203fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1204fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // convert the rect to a path so we can invert the fill 1205fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com SkPath temp; 1206a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com temp.addRect(*clip->fRect); 1207fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1208fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com helper.draw(temp, SkRegion::kReplace_Op, 1209a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com kInverseEvenOdd_GrPathFill, clip->fDoAA, 1210366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 0x00); 1211a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } else if (NULL != clip->fPath) { 1212a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com helper.draw(*clip->fPath, 1213fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com SkRegion::kReplace_Op, 1214a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com invert_fill(get_path_fill(*clip->fPath)), 1215a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com clip->fDoAA, 1216366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 0x00); 1217fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1218fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1219fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com continue; 1220fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com } 1221fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1222fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // The other ops (union, xor, diff) only affect pixels inside 1223fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // the geometry so they can just be drawn normally 1224a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com if (NULL != clip->fRect) { 1225fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1226a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com helper.draw(*clip->fRect, 1227fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com op, 1228a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com clip->fDoAA, 0xFF); 12296b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1230a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com } else if (NULL != clip->fPath) { 1231fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com helper.draw(*clip->fPath, 1232fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com op, 1233a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com get_path_fill(*clip->fPath), 1234a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com clip->fDoAA, 0xFF); 12356b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 12366b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com } 12376b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1238fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // Because we are using the scratch texture cache, "accum" may be 1239fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // larger than expected and have some cruft in the areas we aren't using. 1240fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com // Clear it out. 1241c82a8b7aa4ec19fba508c394920a9e88d3e5bd12robertphillips@google.com fGpu->clear(NULL, 0x00000000, accum->asRenderTarget()); 1242fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com 1243366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com helper.toTexture(accum, clearToInside ? 0xFF : 0x00); 12446b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 12456b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com *result = accum; 12466b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1247c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com fCurrClipMaskType = kAlpha_ClipMaskType; 12486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com return true; 12496b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com} 12506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com 1251f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 1252f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.comvoid GrClipMaskManager::releaseResources() { 1253f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com fAACache.releaseResources(); 12541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com} 1255