bool GrClipMaskManager::drawClipShape(GrGpu* gpu, GrTexture* target, const GrClip& clipIn, int index) { GrDrawState* drawState = gpu->drawState(); GrAssert(NULL != drawState); drawState->setRenderTarget(target->asRenderTarget()); if (kRect_ClipType == clipIn.getElementType(index)) { if (clipIn.getDoAA(index)) { // convert the rect to a path for AA SkPath temp; temp.addRect(clipIn.getRect(index)); return this->drawPath(gpu, temp, kEvenOdd_PathFill, clipIn.getDoAA(index)); } else { gpu->drawSimpleRect(clipIn.getRect(index), NULL, 0); } } else { return this->drawPath(gpu, clipIn.getPath(index), clipIn.getPathFill(index), clipIn.getDoAA(index)); } return true; }
//////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, const GrClip& clipIn, GrTexture** result, GrIRect *resultBounds) { if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) { return true; } GrTexture* accum = fAACache.getLastMask(); if (NULL == accum) { fClipMaskInAlpha = false; fAACache.reset(); return false; } GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); GrDrawState* drawState = gpu->drawState(); GrDrawTarget::AutoGeometryPush agp(gpu); int count = clipIn.getElementCount(); if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { // if we were able to trim down the size of the mask we need to // offset the paths & rects that will be used to compute it GrMatrix m; m.setTranslate(SkIntToScalar(-resultBounds->fLeft), SkIntToScalar(-resultBounds->fTop)); drawState->setViewMatrix(m); } bool clearToInside; SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning int start = process_initial_clip_elements(clipIn, *resultBounds, &clearToInside, &startOp); clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000); GrAutoScratchTexture temp; // walk through each clip element and perform its set op for (int c = start; c < count; ++c) { SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c); if (SkRegion::kReplace_Op == op) { // TODO: replace is actually a lot faster then intersection // for this path - refactor the stencil path so it can handle // replace ops and alter GrClip to allow them through // clear the accumulator and draw the new object directly into it clear(gpu, accum, 0x00000000); setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(gpu, accum, clipIn, c); } else if (SkRegion::kReverseDifference_Op == op || SkRegion::kIntersect_Op == op) { // there is no point in intersecting a screen filling rectangle. if (SkRegion::kIntersect_Op == op && kRect_ClipType == clipIn.getElementType(c) && contains(clipIn.getRect(c), *resultBounds)) { continue; } getTemp(*resultBounds, &temp); if (NULL == temp.texture()) { fClipMaskInAlpha = false; fAACache.reset(); return false; } // clear the temp target & draw into it clear(gpu, temp.texture(), 0x00000000); setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); this->drawClipShape(gpu, temp.texture(), clipIn, c); // TODO: rather than adding these two translations here // compute the bounding box needed to render the texture // into temp if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { GrMatrix m; m.setTranslate(SkIntToScalar(resultBounds->fLeft), SkIntToScalar(resultBounds->fTop)); drawState->preConcatViewMatrix(m); } // Now draw into the accumulator using the real operation // and the temp buffer as a texture setup_boolean_blendcoeffs(drawState, op); this->drawTexture(gpu, accum, temp.texture()); if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { GrMatrix m; m.setTranslate(SkIntToScalar(-resultBounds->fLeft), SkIntToScalar(-resultBounds->fTop)); drawState->preConcatViewMatrix(m); } } else { // all the remaining ops can just be directly draw into // the accumulation buffer setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(gpu, accum, clipIn, c); } } *result = accum; return true; }
/* * This method traverses the clip stack to see if the GrSoftwarePathRenderer * will be used on any element. If so, it returns true to indicate that the * entire clip should be rendered in SW and then uploaded en masse to the gpu. */ bool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) { if (!clipIn.requiresAA()) { // The stencil buffer can handle this case return false; } // TODO: generalize this test so that when // a clip gets complex enough it can just be done in SW regardless // of whether it would invoke the GrSoftwarePathRenderer. bool useSW = false; for (int i = 0; i < clipIn.getElementCount(); ++i) { if (SkRegion::kReplace_Op == clipIn.getOp(i)) { // Everything before a replace op can be ignored so start // afresh w.r.t. determining if any element uses the SW path useSW = false; } if (!clipIn.getDoAA(i)) { // non-anti-aliased rects and paths can always be drawn either // directly or by the GrDefaultPathRenderer continue; } if (kRect_ClipType == clipIn.getElementType(i)) { // Antialiased rects are converted to paths and then drawn with // kEvenOdd_PathFill. if (!GrAAConvexPathRenderer::staticCanDrawPath( true, // always convex kEvenOdd_PathFill, gpu, true)) { // anti-aliased // if the GrAAConvexPathRenderer can't render this rect (due // to lack of derivative support in the shaders) then // the GrSoftwarePathRenderer will be used useSW = true; } continue; } // only paths need to be considered in the rest of the loop body if (GrAAHairLinePathRenderer::staticCanDrawPath(clipIn.getPath(i), clipIn.getPathFill(i), gpu, clipIn.getDoAA(i))) { // the hair line path renderer can handle this one continue; } if (GrAAConvexPathRenderer::staticCanDrawPath( clipIn.getPath(i).isConvex(), clipIn.getPathFill(i), gpu, clipIn.getDoAA(i))) { // the convex path renderer can handle this one continue; } // otherwise the GrSoftwarePathRenderer is going to be invoked useSW = true; } return useSW; }