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
This commit is contained in:
robertphillips 2015-05-27 11:02:55 -07:00 committed by Commit bot
parent 24a366a037
commit ccb1b57510
13 changed files with 477 additions and 399 deletions

View File

@ -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',

View File

@ -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);

View File

@ -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

View File

@ -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*,

295
src/gpu/GrBlurUtils.cpp Normal file
View File

@ -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);
}

40
src/gpu/GrBlurUtils.h Normal file
View File

@ -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

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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*);
};

View File

@ -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;

View File

@ -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);

View File

@ -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());
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -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&,