diff options
author | 2015-05-27 11:02:55 -0700 | |
---|---|---|
committer | 2015-05-27 11:02:55 -0700 | |
commit | ccb1b5751075506b4615d2112889d01ee8ad6436 (patch) | |
tree | 84bac0d48ad26f2f3bdb8c4b2ddeb95bb3459750 | |
parent | 24a366a03756d7a8755f940d3160698cf9122cc0 (diff) |
Move SkGpuDevice::internalDrawPath to GrBlurUtils::drawPathWithMaskFilter
This CL is ugly but it:
removes the stored SkGpuDevice back pointer from GrTextContext (at the cost of passing more parameters)
moves SkGpuDevice::internalDrawPath to GrDrawContext::drawPathFull
Unfortunately, the GrTextContext-derived classes still need the SkGpuDevice for filterTextFlags calls but I will try removing that in a separate CL.
Review URL: https://codereview.chromium.org/1157773003
-rw-r--r-- | gyp/gpu.gypi | 2 | ||||
-rw-r--r-- | include/gpu/GrContext.h | 4 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.cpp | 72 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.h | 30 | ||||
-rw-r--r-- | src/gpu/GrBlurUtils.cpp | 295 | ||||
-rw-r--r-- | src/gpu/GrBlurUtils.h | 40 | ||||
-rwxr-xr-x | src/gpu/GrContext.cpp | 5 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.cpp | 41 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.h | 15 | ||||
-rw-r--r-- | src/gpu/GrTextContext.cpp | 52 | ||||
-rw-r--r-- | src/gpu/GrTextContext.h | 26 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 290 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 4 |
13 files changed, 477 insertions, 399 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index c4ca5ed7f3..8a93bf8264 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -83,6 +83,8 @@ '<(skia_src_path)/gpu/GrBatchTest.h', '<(skia_src_path)/gpu/GrBlend.cpp', '<(skia_src_path)/gpu/GrBlend.h', + '<(skia_src_path)/gpu/GrBlurUtils.cpp', + '<(skia_src_path)/gpu/GrBlurUtils.h', '<(skia_src_path)/gpu/GrBufferAllocPool.cpp', '<(skia_src_path)/gpu/GrBufferAllocPool.h', '<(skia_src_path)/gpu/GrCaps.cpp', diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index 2167513d2e..56ba262b86 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -480,11 +480,9 @@ private: * render target and the context. Caller assumes the ownership * of the returned object. The returned object must be deleted * before the context is destroyed. - * TODO we can possibly bury this behind context, but we need to be able to use the - * drawText_asPaths logic on SkGpuDevice + * TODO bury this behind context! */ GrTextContext* createTextContext(GrRenderTarget*, - SkGpuDevice*, const SkDeviceProperties&, bool enableDistanceFieldFonts); diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index 750cb13fc0..14f8ef7106 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -10,6 +10,7 @@ #include "GrBatchFontCache.h" #include "GrBatchTarget.h" #include "GrBatchTest.h" +#include "GrBlurUtils.h" #include "GrDefaultGeoProcFactory.h" #include "GrDrawContext.h" #include "GrFontScaler.h" @@ -94,10 +95,9 @@ static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { // Distance field text in textblobs GrAtlasTextContext::GrAtlasTextContext(GrContext* context, - SkGpuDevice* gpuDevice, const SkDeviceProperties& properties, bool enableDistanceFields) - : INHERITED(context, gpuDevice, properties) + : INHERITED(context, properties) , fDistanceAdjustTable(SkNEW_ARGS(DistanceAdjustTable, (properties.gamma()))) { // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest // vertexStride @@ -196,10 +196,9 @@ void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable(float gam } GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, - SkGpuDevice* gpuDevice, const SkDeviceProperties& props, bool enableDistanceFields) { - return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props, enableDistanceFields)); + return SkNEW_ARGS(GrAtlasTextContext, (context, props, enableDistanceFields)); } bool GrAtlasTextContext::canDraw(const GrRenderTarget*, @@ -345,9 +344,10 @@ inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()); } -void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, - const SkPaint& skPaint, const SkMatrix& viewMatrix, - const SkTextBlob* blob, SkScalar x, SkScalar y, +void GrAtlasTextContext::drawTextBlob(SkGpuDevice* gpuDevice, GrRenderTarget* rt, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkTextBlob* blob, + SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { // If we have been abandoned, then don't draw if (fContext->abandoned()) { @@ -411,8 +411,8 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, fCache->remove(cacheBlob); cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, kGrayTextVASize))); - this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y, - drawFilter, clipRect, rt, clip, grPaint); + this->regenerateTextBlob(gpuDevice, cacheBlob, skPaint, grPaint.getColor(), viewMatrix, + blob, x, y, drawFilter, clipRect, rt, clip, grPaint); } else { // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y // offsets @@ -428,12 +428,12 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, } else { cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); } - this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y, - drawFilter, clipRect, rt, clip, grPaint); + this->regenerateTextBlob(gpuDevice, cacheBlob, skPaint, grPaint.getColor(), viewMatrix, + blob, x, y, drawFilter, clipRect, rt, clip, grPaint); } cacheBlob->fPaintColor = skPaint.getColor(); - this->flush(drawContext, blob, cacheBlob, rt, skPaint, grPaint, drawFilter, + this->flush(gpuDevice, drawContext, blob, cacheBlob, rt, skPaint, grPaint, drawFilter, clip, viewMatrix, clipBounds, x, y, transX, transY); } @@ -472,7 +472,7 @@ inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, return true; } -void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, +void GrAtlasTextContext::regenerateTextBlob(SkGpuDevice* gpuDevice, BitmapTextBlob* cacheBlob, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, @@ -500,7 +500,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, continue; } - runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); + runPaint.setFlags(gpuDevice->filterTextFlags(runPaint)); // setup vertex / glyphIndex for the new run if (run > 0) { @@ -775,12 +775,12 @@ GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip return blob; } -void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, +void GrAtlasTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt, + const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - GrDrawContext* drawContext = fContext->drawContext(); if (drawContext) { SkAutoTUnref<BitmapTextBlob> blob( this->createDrawTextBlob(rt, clip, paint, skPaint, viewMatrix, @@ -789,13 +789,13 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, } } -void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, +void GrAtlasTextContext::onDrawPosText(GrDrawContext* drawContext, GrRenderTarget* rt, + const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds) { - GrDrawContext* drawContext = fContext->drawContext(); if (drawContext) { SkAutoTUnref<BitmapTextBlob> blob( this->createDrawPosTextBlob(rt, clip, paint, skPaint, viewMatrix, @@ -2043,7 +2043,9 @@ private: float fGamma; }; -void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, const SkPaint& skPaint, +void GrAtlasTextContext::flushRunAsPaths(SkGpuDevice* gpuDevice, GrDrawContext* drawContext, + GrRenderTarget* rt, const SkTextBlob::RunIterator& it, + const GrClip& clip, const SkPaint& skPaint, SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y) { SkPaint runPaint = skPaint; @@ -2057,20 +2059,23 @@ void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons return; } - runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); + runPaint.setFlags(gpuDevice->filterTextFlags(runPaint)); switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->drawTextAsPath(runPaint, viewMatrix, (const char *)it.glyphs(), + this->drawTextAsPath(drawContext, rt, clip, runPaint, viewMatrix, + (const char *)it.glyphs(), textLen, x + offset.x(), y + offset.y(), clipBounds); break; case SkTextBlob::kHorizontal_Positioning: - this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(), + this->drawPosTextAsPath(drawContext, rt, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), clipBounds); break; case SkTextBlob::kFull_Positioning: - this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(), + this->drawPosTextAsPath(drawContext, rt, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); break; } @@ -2140,8 +2145,9 @@ inline void GrAtlasTextContext::flushRun(GrDrawContext* drawContext, } } -inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt, - const SkPaint& skPaint, +inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, + GrDrawContext* drawContext, GrRenderTarget* rt, + const GrClip& clip, const SkPaint& skPaint, SkScalar transX, SkScalar transY, const SkIRect& clipBounds) { if (!cacheBlob->fBigGlyphs.count()) { @@ -2161,12 +2167,13 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend SkMatrix translate = cacheBlob->fViewMatrix; translate.postTranslate(bigGlyph.fVx, bigGlyph.fVy); - fGpuDevice->internalDrawPath(bigGlyph.fPath, skPaint, translate, &pathMatrix, clipBounds, - false); + GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, bigGlyph.fPath, + skPaint, translate, &pathMatrix, clipBounds, false); } } -void GrAtlasTextContext::flush(GrDrawContext* drawContext, +void GrAtlasTextContext::flush(SkGpuDevice* gpuDevice, + GrDrawContext* drawContext, const SkTextBlob* blob, BitmapTextBlob* cacheBlob, GrRenderTarget* rt, @@ -2188,7 +2195,8 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext, SkTextBlob::RunIterator it(blob); for (int run = 0; !it.done(); it.next(), run++) { if (cacheBlob->fRuns[run].fDrawAsPaths) { - this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBounds, x, y); + this->flushRunAsPaths(gpuDevice, drawContext, rt, it, clip, skPaint, + drawFilter, viewMatrix, clipBounds, x, y); continue; } cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); @@ -2197,7 +2205,7 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext, } // Now flush big glyphs - this->flushBigGlyphs(cacheBlob, rt, skPaint, transX, transY, clipBounds); + this->flushBigGlyphs(cacheBlob, drawContext, rt, clip, skPaint, transX, transY, clipBounds); } void GrAtlasTextContext::flush(GrDrawContext* drawContext, @@ -2216,7 +2224,7 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext, } // Now flush big glyphs - this->flushBigGlyphs(cacheBlob, rt, skPaint, 0, 0, clipBounds); + this->flushBigGlyphs(cacheBlob, drawContext, rt, clip, skPaint, 0, 0, clipBounds); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2234,7 +2242,7 @@ BATCH_TEST_DEFINE(TextBlobBatch) { // We don't yet test the fall back to paths in the GrTextContext base class. This is mostly // because we don't really want to have a gpu device here. // We enable distance fields by twiddling a knob on the paint - gTextContext = GrAtlasTextContext::Create(context, NULL, gDeviceProperties, false); + gTextContext = GrAtlasTextContext::Create(context, gDeviceProperties, false); } // create dummy render target diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index ad0f765f4c..3a8c37e1fd 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -34,26 +34,25 @@ class GrTextBlobCache; */ class GrAtlasTextContext : public GrTextContext { public: - static GrAtlasTextContext* Create(GrContext*, SkGpuDevice*, const SkDeviceProperties&, + static GrAtlasTextContext* Create(GrContext*, const SkDeviceProperties&, bool enableDistanceFields); private: - GrAtlasTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&, - bool enableDistanceFields); + GrAtlasTextContext(GrContext*, const SkDeviceProperties&, bool enableDistanceFields); ~GrAtlasTextContext() override {} bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix) override; - void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override; - void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, + void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, + const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds) override; - void drawTextBlob(GrRenderTarget*, const GrClip&, const SkPaint&, + void drawTextBlob(SkGpuDevice*, GrRenderTarget*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds) override; @@ -272,7 +271,9 @@ private: size_t vertexStride, bool useVertexColor, GrGlyph*); - inline void flushRunAsPaths(const SkTextBlob::RunIterator&, const SkPaint&, SkDrawFilter*, + inline void flushRunAsPaths(SkGpuDevice*, GrDrawContext*, GrRenderTarget*, + const SkTextBlob::RunIterator&, const GrClip& clip, + const SkPaint&, SkDrawFilter*, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y); inline BitmapTextBatch* createBatch(BitmapTextBlob*, const PerSubRunInfo&, @@ -281,14 +282,15 @@ private: const SkPaint&); inline void flushRun(GrDrawContext*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor, SkScalar transX, SkScalar transY, const SkPaint&); - inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt, - const SkPaint& skPaint, + inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrDrawContext*, GrRenderTarget*, + const GrClip& clip, const SkPaint& skPaint, SkScalar transX, SkScalar transY, const SkIRect& clipBounds); // We have to flush SkTextBlobs differently from drawText / drawPosText - void flush(GrDrawContext*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&, - const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix, - const SkIRect& clipBounds, SkScalar x, SkScalar y, SkScalar transX, SkScalar transY); + void flush(SkGpuDevice*, GrDrawContext*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, + const SkPaint&, const GrPaint&, SkDrawFilter*, const GrClip&, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y, + SkScalar transX, SkScalar transY); void flush(GrDrawContext*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&, const GrPaint&, const GrClip&, const SkIRect& clipBounds); @@ -337,7 +339,7 @@ private: const BitmapTextBlob&, const SkPaint&, const SkMaskFilter::BlurRec&, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor, + void regenerateTextBlob(SkGpuDevice*, BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipRect, GrRenderTarget*, diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp new file mode 100644 index 0000000000..a757a4aed4 --- /dev/null +++ b/src/gpu/GrBlurUtils.cpp @@ -0,0 +1,295 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrBlurUtils.h" +#include "GrDrawContext.h" +#include "GrContext.h" +#include "effects/GrSimpleTextureEffect.h" +#include "GrStrokeInfo.h" +#include "GrTexture.h" +#include "GrTextureProvider.h" +#include "SkDraw.h" +#include "SkGr.h" +#include "SkMaskFilter.h" +#include "SkPaint.h" + +static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) { + return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect); +} + +// Draw a mask using the supplied paint. Since the coverage/geometry +// is already burnt into the mask this boils down to a rect draw. +// Return true if the mask was successfully drawn. +static bool draw_mask(GrDrawContext* drawContext, + GrRenderTarget* rt, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkRect& maskRect, + GrPaint* grp, + GrTexture* mask) { + SkMatrix matrix; + matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); + matrix.postIDiv(mask->width(), mask->height()); + + grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix, + kDevice_GrCoordSet))->unref(); + + SkMatrix inverse; + if (!viewMatrix.invert(&inverse)) { + return false; + } + drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse); + return true; +} + +static bool draw_with_mask_filter(GrDrawContext* drawContext, + GrTextureProvider* textureProvider, + GrRenderTarget* rt, + const GrClip& clipData, + const SkMatrix& viewMatrix, + const SkPath& devPath, + SkMaskFilter* filter, + const SkIRect& clipBounds, + GrPaint* grp, + SkPaint::Style style) { + SkMask srcM, dstM; + + if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, + SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) { + return false; + } + SkAutoMaskFreeImage autoSrc(srcM.fImage); + + if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) { + return false; + } + // this will free-up dstM when we're done (allocated in filterMask()) + SkAutoMaskFreeImage autoDst(dstM.fImage); + + if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) { + return false; + } + + // we now have a device-aligned 8bit mask in dstM, ready to be drawn using + // the current clip (and identity matrix) and GrPaint settings + GrSurfaceDesc desc; + desc.fWidth = dstM.fBounds.width(); + desc.fHeight = dstM.fBounds.height(); + desc.fConfig = kAlpha_8_GrPixelConfig; + + SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture( + desc, GrTextureProvider::kApprox_ScratchTexMatch)); + if (!texture) { + return false; + } + texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, + dstM.fImage, dstM.fRowBytes); + + SkRect maskRect = SkRect::Make(dstM.fBounds); + + return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, texture); +} + +// Create a mask of 'devPath' and place the result in 'mask'. +static GrTexture* create_mask_GPU(GrContext* context, + const SkRect& maskRect, + const SkPath& devPath, + const GrStrokeInfo& strokeInfo, + bool doAA, + int sampleCnt) { + GrSurfaceDesc desc; + desc.fFlags = kRenderTarget_GrSurfaceFlag; + desc.fWidth = SkScalarCeilToInt(maskRect.width()); + desc.fHeight = SkScalarCeilToInt(maskRect.height()); + desc.fSampleCnt = doAA ? sampleCnt : 0; + // We actually only need A8, but it often isn't supported as a + // render target so default to RGBA_8888 + desc.fConfig = kRGBA_8888_GrPixelConfig; + + if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) { + desc.fConfig = kAlpha_8_GrPixelConfig; + } + + GrTexture* mask = context->textureProvider()->refScratchTexture( + desc, GrTextureProvider::kApprox_ScratchTexMatch); + if (NULL == mask) { + return NULL; + } + + SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); + + GrDrawContext* drawContext = context->drawContext(); + if (!drawContext) { + return NULL; + } + + drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true); + + GrPaint tempPaint; + tempPaint.setAntiAlias(doAA); + tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); + + // setup new clip + GrClip clip(clipRect); + + // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint. + SkMatrix translate; + translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); + drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo); + return mask; +} + +void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, + GrDrawContext* drawContext, + GrRenderTarget* renderTarget, + const GrClip& clip, + const SkPath& origSrcPath, + const SkPaint& paint, + const SkMatrix& origViewMatrix, + const SkMatrix* prePathMatrix, + const SkIRect& clipBounds, + bool pathIsMutable) { + SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); + + GrStrokeInfo strokeInfo(paint); + + // If we have a prematrix, apply it to the path, optimizing for the case + // where the original path can in fact be modified in place (even though + // its parameter type is const). + SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); + SkTLazy<SkPath> tmpPath; + SkTLazy<SkPath> effectPath; + SkPathEffect* pathEffect = paint.getPathEffect(); + + SkMatrix viewMatrix = origViewMatrix; + + if (prePathMatrix) { + // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix. + // The pre-path-matrix also should not affect shading. + if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint.getShader() && + (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { + viewMatrix.preConcat(*prePathMatrix); + } else { + SkPath* result = pathPtr; + + if (!pathIsMutable) { + result = tmpPath.init(); + result->setIsVolatile(true); + pathIsMutable = true; + } + // should I push prePathMatrix on our MV stack temporarily, instead + // of applying it here? See SkDraw.cpp + pathPtr->transform(*prePathMatrix, result); + pathPtr = result; + } + } + // at this point we're done with prePathMatrix + SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) + + GrPaint grPaint; + if (!SkPaint2GrPaint(context, renderTarget, paint, viewMatrix, true, &grPaint)) { + return; + } + + const SkRect* cullRect = NULL; // TODO: what is our bounds? + if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, + &strokeInfo, cullRect)) { + pathPtr = effectPath.get(); + pathIsMutable = true; + } + + if (paint.getMaskFilter()) { + if (!strokeInfo.isHairlineStyle()) { + SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); + if (strokeInfo.isDashed()) { + if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) { + pathPtr = strokedPath; + pathIsMutable = true; + } + strokeInfo.removeDash(); + } + if (strokeInfo.applyToPath(strokedPath, *pathPtr)) { + pathPtr = strokedPath; + pathIsMutable = true; + strokeInfo.setFillStyle(); + } + } + + // avoid possibly allocating a new path in transform if we can + SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); + if (!pathIsMutable) { + devPathPtr->setIsVolatile(true); + } + + // transform the path into device space + pathPtr->transform(viewMatrix, devPathPtr); + + SkRect maskRect; + if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), + clipBounds, + viewMatrix, + &maskRect)) { + SkIRect finalIRect; + maskRect.roundOut(&finalIRect); + if (clip_bounds_quick_reject(clipBounds, finalIRect)) { + // clipped out + return; + } + + if (paint.getMaskFilter()->directFilterMaskGPU(context, + renderTarget, + &grPaint, + clip, + viewMatrix, + strokeInfo, + *devPathPtr)) { + // the mask filter was able to draw itself directly, so there's nothing + // left to do. + return; + } + + + SkAutoTUnref<GrTexture> mask(create_mask_GPU(context, + maskRect, + *devPathPtr, + strokeInfo, + grPaint.isAntiAlias(), + renderTarget->numSamples())); + if (mask) { + GrTexture* filtered; + + if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, + &filtered, true)) { + // filterMaskGPU gives us ownership of a ref to the result + SkAutoTUnref<GrTexture> atu(filtered); + if (draw_mask(drawContext, + renderTarget, + clip, + viewMatrix, + maskRect, + &grPaint, + filtered)) { + // This path is completely drawn + return; + } + } + } + } + + // draw the mask on the CPU - this is a fallthrough path in case the + // GPU path fails + SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_Style : + SkPaint::kFill_Style; + draw_with_mask_filter(drawContext, context->textureProvider(), renderTarget, + clip, viewMatrix, *devPathPtr, + paint.getMaskFilter(), clipBounds, &grPaint, style); + return; + } + + drawContext->drawPath(renderTarget, clip, grPaint, viewMatrix, *pathPtr, strokeInfo); +} + diff --git a/src/gpu/GrBlurUtils.h b/src/gpu/GrBlurUtils.h new file mode 100644 index 0000000000..0fc77266b0 --- /dev/null +++ b/src/gpu/GrBlurUtils.h @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBlurUtils_DEFINED +#define GrBlurUtils_DEFINED + +class GrClip; +class GrContext; +class GrDrawContext; +class GrRenderTarget; +struct SkIRect; +class SkMatrix; +class SkPaint; +class SkPath; + + +/** + * Blur utilities. + */ +namespace GrBlurUtils { + /** + * Draw a path handling the mask filter if present. + */ + void drawPathWithMaskFilter(GrContext* context, + GrDrawContext* drawContext, + GrRenderTarget* rt, + const GrClip& clip, + const SkPath& origSrcPath, + const SkPaint& paint, + const SkMatrix& origViewMatrix, + const SkMatrix* prePathMatrix, + const SkIRect& clipBounds, + bool pathIsMutable); +}; + +#endif diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index a9beabb537..cc7e6c2b6f 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -244,18 +244,17 @@ void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) } GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget, - SkGpuDevice* gpuDevice, const SkDeviceProperties& leakyProperties, bool enableDistanceFieldFonts) { if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMultisampled()) { GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment(); if (sb) { - return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties); + return GrStencilAndCoverTextContext::Create(this, leakyProperties); } } - return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDistanceFieldFonts); + return GrAtlasTextContext::Create(this, leakyProperties, enableDistanceFieldFonts); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp index 539d731743..4d34cf47ba 100644 --- a/src/gpu/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/GrStencilAndCoverTextContext.cpp @@ -22,21 +22,18 @@ #include "SkTextFormatParams.h" GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, - SkGpuDevice* gpuDevice, const SkDeviceProperties& properties) - : GrTextContext(context, gpuDevice, properties) + : GrTextContext(context, properties) , fStroke(SkStrokeRec::kFill_InitStyle) , fQueuedGlyphCount(0) , fFallbackGlyphsIdx(kGlyphBufferSize) { } GrStencilAndCoverTextContext* -GrStencilAndCoverTextContext::Create(GrContext* context, SkGpuDevice* gpuDevice, - const SkDeviceProperties& props) { +GrStencilAndCoverTextContext::Create(GrContext* context, const SkDeviceProperties& props) { GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverTextContext, - (context, gpuDevice, props)); - textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, gpuDevice, props, - false); + (context, props)); + textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, props, false); return textContext; } @@ -74,7 +71,7 @@ bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt, return rec.getFormat() != SkMask::kARGB32_Format; } -void GrStencilAndCoverTextContext::onDrawText(GrRenderTarget* rt, +void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, @@ -157,17 +154,19 @@ void GrStencilAndCoverTextContext::onDrawText(GrRenderTarget* rt, const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); if (glyph.fWidth) { - this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); + this->appendGlyph(drawContext, glyph, + SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); } fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); } - this->finish(); + this->finish(drawContext); } -void GrStencilAndCoverTextContext::onDrawPosText(GrRenderTarget* rt, +void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* drawContext, + GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, @@ -211,12 +210,12 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrRenderTarget* rt, SkPoint loc; alignProc(tmsLoc, glyph, &loc); - this->appendGlyph(glyph, loc); + this->appendGlyph(drawContext, glyph, loc); } pos += scalarsPerPosition; } - this->finish(); + this->finish(drawContext); } static GrPathRange* get_gr_glyphs(GrContext* ctx, @@ -409,10 +408,11 @@ bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) { return true; } -inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { +inline void GrStencilAndCoverTextContext::appendGlyph(GrDrawContext* drawContext, + const SkGlyph& glyph, const SkPoint& pos) { if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); - this->flush(); + this->flush(drawContext); } // Stick the glyphs we can't draw at the end of the buffer, growing backwards. @@ -430,17 +430,12 @@ static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { return &pointArray[0].fX; } -void GrStencilAndCoverTextContext::flush() { +void GrStencilAndCoverTextContext::flush(GrDrawContext* drawContext) { if (fQueuedGlyphCount > 0) { SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(), fViewMatrix, fLocalMatrix)); - GrDrawContext* drawContext = fContext->drawContext(); - if (!drawContext) { - return; - } - drawContext->drawPaths(&fPipelineBuilder, pp, fGlyphs, fGlyphIndices, GrPathRange::kU16_PathIndexType, get_xy_scalar_array(fGlyphPositions), @@ -477,8 +472,8 @@ void GrStencilAndCoverTextContext::flush() { } } -void GrStencilAndCoverTextContext::finish() { - this->flush(); +void GrStencilAndCoverTextContext::finish(GrDrawContext* drawContext) { + this->flush(drawContext); fGlyphs->unref(); fGlyphs = NULL; diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h index 0cb55535c2..d36b60f11c 100644 --- a/src/gpu/GrStencilAndCoverTextContext.h +++ b/src/gpu/GrStencilAndCoverTextContext.h @@ -23,8 +23,7 @@ class GrPathRange; */ class GrStencilAndCoverTextContext : public GrTextContext { public: - static GrStencilAndCoverTextContext* Create(GrContext*, SkGpuDevice*, - const SkDeviceProperties&); + static GrStencilAndCoverTextContext* Create(GrContext*, const SkDeviceProperties&); virtual ~GrStencilAndCoverTextContext(); @@ -68,16 +67,16 @@ private: SkMatrix fLocalMatrix; bool fUsingDeviceSpaceGlyphs; - GrStencilAndCoverTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&); + GrStencilAndCoverTextContext(GrContext*, const SkDeviceProperties&); bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix) override; - void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override; - void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, @@ -87,9 +86,9 @@ private: size_t textByteLength, RenderMode, const SkMatrix& viewMatrix, const SkIRect& regionClipBounds); bool mapToFallbackContext(SkMatrix* inverse); - void appendGlyph(const SkGlyph&, const SkPoint&); - void flush(); - void finish(); + void appendGlyph(GrDrawContext*, const SkGlyph&, const SkPoint&); + void flush(GrDrawContext*); + void finish(GrDrawContext*); }; diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp index 4b8bc68e33..1edacfc06e 100644 --- a/src/gpu/GrTextContext.cpp +++ b/src/gpu/GrTextContext.cpp @@ -6,8 +6,9 @@ */ #include "GrTextContext.h" +#include "GrBlurUtils.h" #include "GrContext.h" -#include "GrDrawTarget.h" +#include "GrDrawContext.h" #include "GrFontScaler.h" #include "SkAutoKern.h" @@ -19,11 +20,9 @@ #include "SkTextMapStateProc.h" #include "SkTextToPathIter.h" -GrTextContext::GrTextContext(GrContext* context, SkGpuDevice* gpuDevice, - const SkDeviceProperties& properties) +GrTextContext::GrTextContext(GrContext* context, const SkDeviceProperties& properties) : fFallbackTextContext(NULL) , fContext(context) - , fGpuDevice(gpuDevice) , fDeviceProperties(properties) { } @@ -52,19 +51,24 @@ void GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPai return; } + GrDrawContext* drawContext = fContext->drawContext(); + if (!drawContext) { + return; + } + GrTextContext* textContext = this; do { if (textContext->canDraw(rt, clip, paint, skPaint, viewMatrix)) { - textContext->onDrawText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y, - clipBounds); + textContext->onDrawText(drawContext, rt, clip, paint, skPaint, viewMatrix, + text, byteLength, x, y, clipBounds); return; } textContext = textContext->fFallbackTextContext; } while (textContext); // fall back to drawing as a path - SkASSERT(fGpuDevice); - this->drawTextAsPath(skPaint, viewMatrix, text, byteLength, x, y, clipBounds); + this->drawTextAsPath(drawContext, rt, clip, skPaint, viewMatrix, + text, byteLength, x, y, clipBounds); } void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, @@ -76,10 +80,16 @@ void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const Gr return; } + GrDrawContext* drawContext = fContext->drawContext(); + if (!drawContext) { + return; + } + GrTextContext* textContext = this; do { if (textContext->canDraw(rt, clip, paint, skPaint, viewMatrix)) { - textContext->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, pos, + textContext->onDrawPosText(drawContext, rt, clip, paint, skPaint, viewMatrix, + text, byteLength, pos, scalarsPerPosition, offset, clipBounds); return; } @@ -87,12 +97,12 @@ void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const Gr } while (textContext); // fall back to drawing as a path - SkASSERT(fGpuDevice); - this->drawPosTextAsPath(skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, - clipBounds); + this->drawPosTextAsPath(drawContext, rt, clip, skPaint, viewMatrix, text, byteLength, pos, + scalarsPerPosition, offset, clipBounds); } -void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint, +void GrTextContext::drawTextBlob(SkGpuDevice* gpuDevice, GrRenderTarget* rt, + const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { @@ -112,7 +122,7 @@ void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const S continue; } - runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); + runPaint.setFlags(gpuDevice->filterTextFlags(runPaint)); GrPaint grPaint; if (!SkPaint2GrPaint(fContext, fRenderTarget, runPaint, viewMatrix, true, &grPaint)) { @@ -143,7 +153,9 @@ void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const S } } -void GrTextContext::drawTextAsPath(const SkPaint& skPaint, const SkMatrix& viewMatrix, +void GrTextContext::drawTextAsPath(GrDrawContext* drawContext, GrRenderTarget* rt, + const GrClip& clip, + const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) { SkTextToPathIter iter(text, byteLength, skPaint, true); @@ -159,13 +171,16 @@ void GrTextContext::drawTextAsPath(const SkPaint& skPaint, const SkMatrix& viewM matrix.postTranslate(xpos - prevXPos, 0); if (iterPath) { const SkPaint& pnt = iter.getPaint(); - fGpuDevice->internalDrawPath(*iterPath, pnt, viewMatrix, &matrix, clipBounds, false); + GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, *iterPath, + pnt, viewMatrix, &matrix, clipBounds, false); } prevXPos = xpos; } } -void GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix, +void GrTextContext::drawPosTextAsPath(GrDrawContext* drawContext, GrRenderTarget* rt, + const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { @@ -204,7 +219,8 @@ void GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& matrix[SkMatrix::kMTransX] = loc.fX; matrix[SkMatrix::kMTransY] = loc.fY; - fGpuDevice->internalDrawPath(*path, paint, viewMatrix, &matrix, clipBounds, false); + GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, *path, paint, + viewMatrix, &matrix, clipBounds, false); } } pos += scalarsPerPosition; diff --git a/src/gpu/GrTextContext.h b/src/gpu/GrTextContext.h index 242ae3abe4..07485f4d17 100644 --- a/src/gpu/GrTextContext.h +++ b/src/gpu/GrTextContext.h @@ -16,7 +16,7 @@ class GrClip; class GrContext; -class GrDrawTarget; +class GrDrawContext; class GrFontScaler; class SkDrawFilter; class SkGpuDevice; @@ -37,18 +37,14 @@ public: const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds); - virtual void drawTextBlob(GrRenderTarget*, const GrClip&, const SkPaint&, - const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, + virtual void drawTextBlob(SkGpuDevice*, GrRenderTarget*, const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkTextBlob*, + SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); protected: GrTextContext* fFallbackTextContext; GrContext* fContext; - // TODO we probably don't really need to store a back pointer to the owning SkGpuDevice, except - // we need to be able to call drawPath on it in the event no other text context can draw the - // text. We might be able to move this logic to context though. This is unreffed because - // GrTextContext is completely owned by SkGpuDevice - SkGpuDevice* fGpuDevice; SkDeviceProperties fDeviceProperties; SkAutoTUnref<GrRenderTarget> fRenderTarget; @@ -58,24 +54,28 @@ protected: GrPaint fPaint; SkPaint fSkPaint; - GrTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&); + GrTextContext(GrContext*, const SkDeviceProperties&); virtual bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix) = 0; - virtual void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + virtual void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, + const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) = 0; - virtual void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + virtual void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, + const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) = 0; - void drawTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix, + void drawTextAsPath(GrDrawContext*, GrRenderTarget*, const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds); - void drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix, + void drawPosTextAsPath(GrDrawContext*, GrRenderTarget*, const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 94ded8de98..0008540cb5 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -7,6 +7,7 @@ #include "SkGpuDevice.h" +#include "GrBlurUtils.h" #include "GrContext.h" #include "GrDrawContext.h" #include "GrGpu.h" @@ -167,8 +168,7 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height, fLegacyBitmap.setPixelRef(pr)->unref(); bool useDFT = fSurfaceProps.isUseDistanceFieldFonts(); - fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(), - useDFT); + fTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProperties(), useDFT); fDrawContext.reset(SkRef(fContext->drawContext())); } @@ -626,145 +626,13 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, /////////////////////////////////////////////////////////////////////////////// -// helpers for applying mask filters -namespace { - -// Draw a mask using the supplied paint. Since the coverage/geometry -// is already burnt into the mask this boils down to a rect draw. -// Return true if the mask was successfully drawn. -bool draw_mask(GrDrawContext* drawContext, - GrRenderTarget* rt, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkRect& maskRect, - GrPaint* grp, - GrTexture* mask) { - SkMatrix matrix; - matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); - matrix.postIDiv(mask->width(), mask->height()); - - grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix, - kDevice_GrCoordSet))->unref(); - - SkMatrix inverse; - if (!viewMatrix.invert(&inverse)) { - return false; - } - drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse); - return true; -} - -static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) { - return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect); -} - -bool draw_with_mask_filter(GrDrawContext* drawContext, - GrTextureProvider* textureProvider, - GrRenderTarget* rt, - const GrClip& clipData, - const SkMatrix& viewMatrix, - const SkPath& devPath, - SkMaskFilter* filter, - const SkIRect& clipBounds, - GrPaint* grp, - SkPaint::Style style) { - SkMask srcM, dstM; - - if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, - SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) { - return false; - } - SkAutoMaskFreeImage autoSrc(srcM.fImage); - - if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) { - return false; - } - // this will free-up dstM when we're done (allocated in filterMask()) - SkAutoMaskFreeImage autoDst(dstM.fImage); - - if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) { - return false; - } - - // we now have a device-aligned 8bit mask in dstM, ready to be drawn using - // the current clip (and identity matrix) and GrPaint settings - GrSurfaceDesc desc; - desc.fWidth = dstM.fBounds.width(); - desc.fHeight = dstM.fBounds.height(); - desc.fConfig = kAlpha_8_GrPixelConfig; - - SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture( - desc, GrTextureProvider::kApprox_ScratchTexMatch)); - if (!texture) { - return false; - } - texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, - dstM.fImage, dstM.fRowBytes); - - SkRect maskRect = SkRect::Make(dstM.fBounds); - - return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, texture); -} - -// Create a mask of 'devPath' and place the result in 'mask'. -GrTexture* create_mask_GPU(GrContext* context, - const SkRect& maskRect, - const SkPath& devPath, - const GrStrokeInfo& strokeInfo, - bool doAA, - int sampleCnt) { - GrSurfaceDesc desc; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fWidth = SkScalarCeilToInt(maskRect.width()); - desc.fHeight = SkScalarCeilToInt(maskRect.height()); - desc.fSampleCnt = doAA ? sampleCnt : 0; - // We actually only need A8, but it often isn't supported as a - // render target so default to RGBA_8888 - desc.fConfig = kRGBA_8888_GrPixelConfig; - - if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, - desc.fSampleCnt > 0)) { - desc.fConfig = kAlpha_8_GrPixelConfig; - } - - GrTexture* mask = context->textureProvider()->refScratchTexture( - desc, GrTextureProvider::kApprox_ScratchTexMatch); - if (NULL == mask) { - return NULL; - } - - SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); - - GrDrawContext* drawContext = context->drawContext(); - if (!drawContext) { - return NULL; - } - - drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true); - - GrPaint tempPaint; - tempPaint.setAntiAlias(doAA); - tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); - - // setup new clip - GrClip clip(clipRect); - - // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint. - SkMatrix translate; - translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); - drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo); - return mask; -} - -SkBitmap wrap_texture(GrTexture* texture, int width, int height) { +static SkBitmap wrap_texture(GrTexture* texture, int width, int height) { SkBitmap result; result.setInfo(SkImageInfo::MakeN32Premul(width, height)); result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref(); return result; } -}; - void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { @@ -772,150 +640,10 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, CHECK_SHOULD_DRAW(draw); GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext); - return this->internalDrawPath(origSrcPath, paint, *draw.fMatrix, prePathMatrix, - draw.fClip->getBounds(), pathIsMutable); -} - -void SkGpuDevice::internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint, - const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix, - const SkIRect& clipBounds, bool pathIsMutable) { - SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); - - GrStrokeInfo strokeInfo(paint); - - // If we have a prematrix, apply it to the path, optimizing for the case - // where the original path can in fact be modified in place (even though - // its parameter type is const). - SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); - SkTLazy<SkPath> tmpPath; - SkTLazy<SkPath> effectPath; - SkPathEffect* pathEffect = paint.getPathEffect(); - - SkMatrix viewMatrix = origViewMatrix; - - if (prePathMatrix) { - // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix. - // The pre-path-matrix also should not affect shading. - if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint.getShader() && - (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { - viewMatrix.preConcat(*prePathMatrix); - } else { - SkPath* result = pathPtr; - - if (!pathIsMutable) { - result = tmpPath.init(); - result->setIsVolatile(true); - pathIsMutable = true; - } - // should I push prePathMatrix on our MV stack temporarily, instead - // of applying it here? See SkDraw.cpp - pathPtr->transform(*prePathMatrix, result); - pathPtr = result; - } - } - // at this point we're done with prePathMatrix - SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) - - GrPaint grPaint; - if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, viewMatrix, true, &grPaint)) { - return; - } - - const SkRect* cullRect = NULL; // TODO: what is our bounds? - if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, - &strokeInfo, cullRect)) { - pathPtr = effectPath.get(); - pathIsMutable = true; - } - - if (paint.getMaskFilter()) { - if (!strokeInfo.isHairlineStyle()) { - SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); - if (strokeInfo.isDashed()) { - if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) { - pathPtr = strokedPath; - pathIsMutable = true; - } - strokeInfo.removeDash(); - } - if (strokeInfo.applyToPath(strokedPath, *pathPtr)) { - pathPtr = strokedPath; - pathIsMutable = true; - strokeInfo.setFillStyle(); - } - } - - // avoid possibly allocating a new path in transform if we can - SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); - if (!pathIsMutable) { - devPathPtr->setIsVolatile(true); - } - - // transform the path into device space - pathPtr->transform(viewMatrix, devPathPtr); - - SkRect maskRect; - if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), - clipBounds, - viewMatrix, - &maskRect)) { - SkIRect finalIRect; - maskRect.roundOut(&finalIRect); - if (clip_bounds_quick_reject(clipBounds, finalIRect)) { - // clipped out - return; - } - - if (paint.getMaskFilter()->directFilterMaskGPU(fContext, - fRenderTarget, - &grPaint, - fClip, - viewMatrix, - strokeInfo, - *devPathPtr)) { - // the mask filter was able to draw itself directly, so there's nothing - // left to do. - return; - } - - - SkAutoTUnref<GrTexture> mask(create_mask_GPU(fContext, - maskRect, - *devPathPtr, - strokeInfo, - grPaint.isAntiAlias(), - fRenderTarget->numSamples())); - if (mask) { - GrTexture* filtered; - - if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) { - // filterMaskGPU gives us ownership of a ref to the result - SkAutoTUnref<GrTexture> atu(filtered); - if (draw_mask(fDrawContext, - fRenderTarget, - fClip, - viewMatrix, - maskRect, - &grPaint, - filtered)) { - // This path is completely drawn - return; - } - } - } - } - - // draw the mask on the CPU - this is a fallthrough path in case the - // GPU path fails - SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_Style : - SkPaint::kFill_Style; - draw_with_mask_filter(fDrawContext, fContext->textureProvider(), fRenderTarget, - fClip, viewMatrix, *devPathPtr, - paint.getMaskFilter(), clipBounds, &grPaint, style); - return; - } - - fDrawContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo); + GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, fRenderTarget, + fClip, origSrcPath, paint, + *draw.fMatrix, prePathMatrix, + draw.fClip->getBounds(), pathIsMutable); } static const int kBmpSmallTileSize = 1 << 10; @@ -1931,8 +1659,8 @@ void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSca SkDEBUGCODE(this->validate();) - fTextContext->drawTextBlob(fRenderTarget, fClip, paint, *draw.fMatrix, blob, x, y, drawFilter, - draw.fClip->getBounds()); + fTextContext->drawTextBlob(this, fRenderTarget, fClip, paint, *draw.fMatrix, + blob, x, y, drawFilter, draw.fClip->getBounds()); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 1356a6f0fb..d7dceed89d 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -212,10 +212,6 @@ private: int tileSize, bool bicubic); - void internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint, - const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix, - const SkIRect& clipBounds, bool pathIsMutable); - bool drawDashLine(const SkPoint pts[2], const SkPaint& paint); static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&, |