Beef up GrContext::AutoMatrix to handle doing GrPaint matrix adjustments.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6656047

git-svn-id: http://skia.googlecode.com/svn/trunk@5918 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-10-12 14:51:52 +00:00
Родитель 223d81d882
Коммит 3cbaa2d4da
7 изменённых файлов: 173 добавлений и 101 удалений

Просмотреть файл

@ -537,7 +537,7 @@ public:
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read the rectangle from.
* @param rowBytes number of bytes bewtween consecutive rows. Zero means rows are tightly
* @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly
* packed.
* @param pixelOpsFlags see PixelOpsFlags enum above.
*/
@ -556,7 +556,7 @@ public:
* @param height height of rectangle to read in pixels.
* @param config the pixel config of the destination buffer
* @param buffer memory to read the rectangle into.
* @param rowBytes number of bytes bewtween consecutive rows. Zero means rows are tightly
* @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly
* packed.
* @param pixelOpsFlags see PixelOpsFlags enum above.
*
@ -578,7 +578,7 @@ public:
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read pixels from
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* @param rowBytes number of bytes between consecutive rows. Zero
* means rows are tightly packed.
* @param pixelOpsFlags see PixelOpsFlags enum above.
*/
@ -669,55 +669,104 @@ public:
};
/**
* Save/restore the view-matrix in the context.
* Save/restore the view-matrix in the context. It can optionally adjust a paint to account
* for a coordinate system change. Here is an example of how the paint param can be used:
*
* A GrPaint is setup with custom stages. The stages will have access to the pre-matrix source
* geometry positions when the draw is executed. Later on a decision is made to transform the
* geometry to device space on the CPU. The custom stages now need to know that the space in
* which the geometry will be specified has changed.
*
* Note that when restore is called (or in the destructor) the context's matrix will be
* restored. However, the paint will not be restored. The caller must make a copy of the
* paint if necessary. Hint: use SkTCopyOnFirstWrite if the AutoMatrix is conditionally
* initialized.
*/
class AutoMatrix : GrNoncopyable {
public:
enum InitialMatrix {
kPreserve_InitialMatrix,
kIdentity_InitialMatrix,
};
AutoMatrix() : fContext(NULL) {}
AutoMatrix(GrContext* ctx, InitialMatrix initialState) : fContext(ctx) {
fMatrix = ctx->getMatrix();
switch (initialState) {
case kPreserve_InitialMatrix:
break;
case kIdentity_InitialMatrix:
ctx->setMatrix(GrMatrix::I());
break;
default:
GrCrash("Unexpected initial matrix state");
~AutoMatrix() { this->restore(); }
/**
* Initializes by pre-concat'ing the context's current matrix with the preConcat param.
*/
void setPreConcat(GrContext* context, const GrMatrix& preConcat, GrPaint* paint = NULL) {
GrAssert(NULL != context);
this->restore();
fContext = context;
fMatrix = context->getMatrix();
this->preConcat(preConcat, paint);
}
/**
* Sets the context's matrix to identity. Returns false if the inverse matrix is required to
* update a paint but the matrix cannot be inverted.
*/
bool setIdentity(GrContext* context, GrPaint* paint = NULL) {
GrAssert(NULL != context);
this->restore();
if (NULL != paint) {
if (!paint->preConcatSamplerMatricesWithInverse(context->getMatrix())) {
return false;
}
}
fMatrix = context->getMatrix();
fContext = context;
context->setIdentityMatrix();
return true;
}
AutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) {
fMatrix = ctx->getMatrix();
ctx->setMatrix(matrix);
/**
* Replaces the context's matrix with a new matrix. Returns false if the inverse matrix is
* required to update a paint but the matrix cannot be inverted.
*/
bool set(GrContext* context, const GrMatrix& newMatrix, GrPaint* paint = NULL) {
if (NULL != paint) {
if (!this->setIdentity(context, paint)) {
return false;
}
this->preConcat(newMatrix, paint);
} else {
this->restore();
fContext = context;
fMatrix = context->getMatrix();
context->setMatrix(newMatrix);
}
return true;
}
void set(GrContext* ctx) {
if (NULL != fContext) {
fContext->setMatrix(fMatrix);
}
fMatrix = ctx->getMatrix();
fContext = ctx;
}
void set(GrContext* ctx, const GrMatrix& matrix) {
if (NULL != fContext) {
fContext->setMatrix(fMatrix);
}
fMatrix = ctx->getMatrix();
ctx->setMatrix(matrix);
fContext = ctx;
}
~AutoMatrix() {
/**
* If this has been initialized then the context's matrix will be further updated by
* pre-concat'ing the preConcat param. The matrix that will be restored remains unchanged.
* The paint is assumed to be relative to the context's matrix at the time this call is
* made, not the matrix at the time AutoMatrix was first initialized. In other words, this
* performs an incremental update of the paint.
*/
void preConcat(const GrMatrix& preConcat, GrPaint* paint = NULL) {
if (NULL != paint) {
paint->preConcatSamplerMatrices(preConcat);
}
fContext->concatMatrix(preConcat);
}
/**
* Returns false if never initialized or the inverse matrix was required to update a paint
* but the matrix could not be inverted.
*/
bool succeeded() const { return NULL != fContext; }
/**
* If this has been initialized then the context's original matrix is restored.
*/
void restore() {
if (NULL != fContext) {
fContext->setMatrix(fMatrix);
fContext = NULL;
}
}
@ -770,9 +819,12 @@ public:
public:
AutoWideOpenIdentityDraw(GrContext* ctx, GrRenderTarget* rt)
: fAutoClip(ctx, AutoClip::kWideOpen_InitialClip)
, fAutoRT(ctx, rt)
, fAutoMatrix(ctx, AutoMatrix::kIdentity_InitialMatrix) {
, fAutoRT(ctx, rt) {
fAutoMatrix.setIdentity(ctx);
// should never fail with no paint param.
GrAssert(fAutoMatrix.succeeded());
}
private:
AutoClip fAutoClip;
AutoRenderTarget fAutoRT;

Просмотреть файл

@ -189,9 +189,8 @@ public:
bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
/**
* Preconcats the matrix of all samplers in the mask with the inverse of a matrix. If the
* matrix inverse cannot be computed (and there is at least one enabled stage) then false is
* returned.
* Preconcats the matrix of all enabled stages with the inverse of a matrix. If the matrix
* inverse cannot be computed (and there is at least one enabled stage) then false is returned.
*/
bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
GrMatrix inv;
@ -219,6 +218,22 @@ public:
return true;
}
/**
* Preconcats the matrix of all stages with a matrix.
*/
void preConcatSamplerMatrices(const GrMatrix& matrix) {
for (int i = 0; i < kMaxColorStages; ++i) {
if (this->isColorStageEnabled(i)) {
fColorSamplers[i].preConcatMatrix(matrix);
}
}
for (int i = 0; i < kMaxCoverageStages; ++i) {
if (this->isCoverageStageEnabled(i)) {
fCoverageSamplers[i].preConcatMatrix(matrix);
}
}
}
GrPaint& operator=(const GrPaint& paint) {
fSrcBlendCoeff = paint.fSrcBlendCoeff;
fDstBlendCoeff = paint.fDstBlendCoeff;

Просмотреть файл

@ -196,7 +196,10 @@ GrTexture* SkBlendImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, co
GrAutoScratchTexture ast(context, desc);
GrTexture* dst = ast.detach();
GrContext::AutoMatrix avm(context, GrMatrix::I());
GrContext::AutoMatrix am;
am.setIdentity(context);
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
GrContext::AutoClip ac(context, rect);

Просмотреть файл

@ -442,14 +442,19 @@ GrTexture* apply_morphology(GrTexture* srcTexture,
SkISize radius) {
GrContext* context = srcTexture->getContext();
srcTexture->ref();
GrContext::AutoMatrix avm(context, GrMatrix::I());
GrContext::AutoMatrix am;
am.setIdentity(context);
GrContext::AutoClip acs(context, GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
SkIntToScalar(srcTexture->height())));
GrTextureDesc desc;
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
desc.fWidth = SkScalarCeilToInt(rect.width());
desc.fHeight = SkScalarCeilToInt(rect.height());
desc.fConfig = kRGBA_8888_GrPixelConfig;
if (radius.fWidth > 0) {
GrAutoScratchTexture ast(context, desc);
GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());

Просмотреть файл

@ -603,12 +603,10 @@ void GrContext::drawPaint(const GrPaint& origPaint) {
}
inverse.mapRect(&r);
} else {
if (paint->hasStage()) {
if (!paint.writable()->preConcatSamplerMatricesWithInverse(fDrawState->getViewMatrix())) {
GrPrintf("Could not invert matrix\n");
}
if (!am.setIdentity(this, paint.writable())) {
GrPrintf("Could not invert matrix\n");
return;
}
am.set(this, GrMatrix::I());
}
// by definition this fills the entire clip, no need for AA
if (paint->isAntiAlias()) {
@ -1780,7 +1778,9 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
AutoRenderTarget art(this);
AutoMatrix avm(this, GrMatrix::I());
AutoMatrix am;
am.setIdentity(this);
SkIRect clearRect;
int scaleFactorX, radiusX;
int scaleFactorY, radiusY;

Просмотреть файл

@ -206,12 +206,13 @@ void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
glyph->fPath = path;
}
GrContext::AutoMatrix am(fContext, GrContext::AutoMatrix::kPreserve_InitialMatrix);
GrContext::AutoMatrix am;
GrMatrix translate;
translate.setTranslate(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
fContext->concatMatrix(translate);
fContext->drawPath(fPaint, *glyph->fPath, kWinding_GrPathFill);
GrPaint tmpPaint(fPaint);
am.setPreConcat(fContext, translate, &tmpPaint);
fContext->drawPath(tmpPaint, *glyph->fPath, kWinding_GrPathFill);
return;
}

Просмотреть файл

@ -26,13 +26,13 @@
#if 0
extern bool (*gShouldDrawProc)();
#define CHECK_SHOULD_DRAW(draw) \
#define CHECK_SHOULD_DRAW(draw, forceI) \
do { \
if (gShouldDrawProc && !gShouldDrawProc()) return; \
this->prepareDraw(draw); \
this->prepareDraw(draw, forceI); \
} while (0)
#else
#define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
#define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
#endif
// we use the same texture slot on GrPaint for bitmaps and shaders
@ -407,14 +407,18 @@ static void check_bounds(const GrClipData& clipData,
// call this every draw call, to ensure that the context reflects our state,
// and not the state from some other canvas/device
void SkGpuDevice::prepareDraw(const SkDraw& draw) {
void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) {
GrAssert(NULL != fClipData.fClipStack);
fContext->setRenderTarget(fRenderTarget);
SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
fContext->setMatrix(*draw.fMatrix);
if (forceIdentity) {
fContext->setIdentityMatrix();
} else {
fContext->setMatrix(*draw.fMatrix);
}
fClipData.fOrigin = this->getOrigin();
#ifdef SK_DEBUG
@ -625,7 +629,7 @@ void SkGpuDevice::clear(SkColor color) {
}
void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
GrPaint grPaint;
SkAutoCachedTexture textures[GrPaint::kMaxColorStages];
@ -649,7 +653,7 @@ static const GrPrimitiveType gPointMode2PrimtiveType[] = {
void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
size_t count, const SkPoint pts[], const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
SkScalar width = paint.getStrokeWidth();
if (width < 0) {
@ -688,7 +692,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) {
CHECK_FOR_NODRAW_ANNOTATION(paint);
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
SkScalar width = paint.getStrokeWidth();
@ -837,21 +841,12 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
SkAutoTUnref<GrTexture> blurTexture;
GrMatrix origMatrix = context->getMatrix();
// We pass kPreserve here. We will replace the current matrix below.
GrContext::AutoMatrix avm(context, GrContext::AutoMatrix::kPreserve_InitialMatrix);
{
GrContext::AutoRenderTarget art(context, pathTexture->asRenderTarget());
GrContext::AutoClip ac(context, srcRect);
context->clear(NULL, 0);
// Draw hard shadow to pathTexture with path top-left at origin 0,0.
GrMatrix translate;
translate.setTranslate(offset.fX, offset.fY);
GrPaint tempPaint;
if (grp->isAntiAlias()) {
tempPaint.setAntiAlias(true);
@ -860,14 +855,17 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
// to properly blend partially covered pixels. This means the AA
// code path may not be taken. So we use a dst blend coeff of ISA. We
// could special case AA draws to a dst surface with known alpha=0 to
// use a zero dst coeff when dual source blending isn't available.
// use a zero dst coeff when dual source blending isn't available.f
tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
}
context->setMatrix(translate);
context->drawPath(tempPaint, devPath, pathFillType);
// switch to device coord drawing when going back to the main RT.
context->setIdentityMatrix();
GrContext::AutoMatrix am;
// Draw hard shadow to pathTexture with path top-left at origin using tempPaint.
GrMatrix translate;
translate.setTranslate(offset.fX, offset.fY);
am.set(context, translate);
context->drawPath(tempPaint, devPath, pathFillType);
// If we're doing a normal blur, we can clobber the pathTexture in the
// gaussianBlur. Otherwise, we need to save it for later compositing.
@ -876,6 +874,7 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
srcRect, sigma, sigma));
if (!isNormalBlur) {
context->setIdentityMatrix();
GrPaint paint;
paint.reset();
paint.colorSampler(0)->matrix()->setIDiv(pathTexture->width(),
@ -900,10 +899,11 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
}
}
if (!grp->preConcatSamplerMatricesWithInverse(origMatrix)) {
GrContext::AutoMatrix am;
if (!am.setIdentity(context, grp)) {
return false;
}
static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1;
// we assume the last mask index is available for use
GrAssert(!grp->isCoverageStageEnabled(MASK_IDX));
@ -943,13 +943,9 @@ bool drawWithMaskFilter(GrContext* context, const SkPath& devPath,
}
// we now have a device-aligned 8bit mask in dstM, ready to be drawn using
// the current clip (and identity matrix) and grpaint settings
if (!grp->preConcatSamplerMatricesWithInverse(context->getMatrix())) {
return false;
}
GrContext::AutoMatrix avm(context, GrMatrix::I());
// the current clip (and identity matrix) and GrPaint settings
GrContext::AutoMatrix am;
am.setIdentity(context, grp);
GrTextureDesc desc;
desc.fWidth = dstM.fBounds.width();
@ -993,7 +989,7 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
CHECK_FOR_NODRAW_ANNOTATION(paint);
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
bool doFill = true;
@ -1202,7 +1198,7 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
const SkRect* srcRectPtr,
const SkMatrix& m,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
SkRect srcRect;
if (NULL == srcRectPtr) {
@ -1465,7 +1461,8 @@ void apply_custom_stage(GrContext* context,
const GrRect& rect,
GrCustomStage* stage) {
SkASSERT(srcTexture && srcTexture->getContext() == context);
GrContext::AutoMatrix avm(context, GrMatrix::I());
GrContext::AutoMatrix am;
am.setIdentity(context);
GrContext::AutoRenderTarget art(context, dstTexture->asRenderTarget());
GrContext::AutoClip acs(context, rect);
@ -1504,8 +1501,9 @@ static GrTexture* filter_texture(SkDevice* device, GrContext* context,
}
void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
int left, int top, const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
int left, int top, const SkPaint& paint) {
// drawSprite is defined to be in device coords.
CHECK_SHOULD_DRAW(draw, true);
SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
@ -1521,8 +1519,6 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
return;
}
GrContext::AutoMatrix avm(fContext, GrMatrix::I());
GrSamplerState* sampler = grPaint.colorSampler(kBitmapTextureIdx);
GrTexture* texture;
@ -1584,7 +1580,7 @@ void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
}
void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
int x, int y, const SkPaint& paint) {
int x, int y, const SkPaint& paint) {
// clear of the source device must occur before CHECK_SHOULD_DRAW
SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
if (dev->fNeedClear) {
@ -1592,7 +1588,8 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
dev->clear(0x0);
}
CHECK_SHOULD_DRAW(draw);
// drawDevice is defined to be in device coords.
CHECK_SHOULD_DRAW(draw, true);
GrPaint grPaint;
SkAutoCachedTexture colorLutTexture;
@ -1622,7 +1619,6 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
int w = bm.width();
int h = bm.height();
GrContext::AutoMatrix avm(fContext, GrMatrix::I());
GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
GrIntToScalar(y),
GrIntToScalar(w),
@ -1691,7 +1687,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
GrPaint grPaint;
SkAutoCachedTexture textures[GrPaint::kMaxColorStages];
@ -1800,7 +1796,7 @@ SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
size_t byteLength, SkScalar x, SkScalar y,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
if (fContext->getMatrix().hasPerspective()) {
// this guy will just call our drawPath()
@ -1827,7 +1823,7 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
size_t byteLength, const SkScalar pos[],
SkScalar constY, int scalarsPerPos,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
if (fContext->getMatrix().hasPerspective()) {
// this guy will just call our drawPath()
@ -1855,7 +1851,7 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
size_t len, const SkPath& path,
const SkMatrix* m, const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
CHECK_SHOULD_DRAW(draw, false);
SkASSERT(draw.fDevice == this);
draw.drawTextOnPath((const char*)text, len, path, m, paint);