Use Color Processor for color bitmap text draws on gpu.

This change is here since previously color bitmap text was rendered using a
geometry processor in the coverage stage. The problem with this is that we
cannot correctly do xfer modes with this method. So I now make color bitmap text
draw using a color stage in the same was as a draw bitmap call.

One issue that arrises from this fix is that we end up adding this final color
processor after any previous color processors. Thus if we have a custom blend
implemented as a color processor it will be before this text one and we won't
blend correctly. This issue will get fixed once an xfer processor is fully
implemented. I have hacked a test locally to show that if we can add the text
color processor to the begining of the color stages we do blend correctly in all
cases (so the xfer processor will be a fix).

BUG=skia:

Review URL: https://codereview.chromium.org/689923004
This commit is contained in:
egdaniel 2014-10-31 06:55:45 -07:00 committed by Commit bot
parent bd1605905b
commit ed3af6648f
3 changed files with 223 additions and 23 deletions

174
gm/colortypexfermode.cpp Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkBitmap.h"
#include "SkGradientShader.h"
#include "SkShader.h"
#include "SkXfermode.h"
#include "../src/fonts/SkGScalerContext.h"
namespace skiagm {
static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
class ColorTypeXfermodeGM : public GM {
SkBitmap fBG;
virtual void onOnceBeforeDraw() SK_OVERRIDE {
fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
kOpaque_SkAlphaType), gData, 4);
}
public:
const static int W = 64;
const static int H = 64;
ColorTypeXfermodeGM() {
const SkColor colors[] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
SK_ColorMAGENTA, SK_ColorCYAN, SK_ColorYELLOW
};
SkMatrix local;
local.setRotate(180);
SkShader* s = SkGradientShader::CreateSweep(0,0, colors, NULL,
SK_ARRAY_COUNT(colors), 0, &local);
SkPaint paint;
paint.setAntiAlias(true);
paint.setShader(s)->unref();
SkTypeface* orig = sk_tool_utils::create_portable_typeface("Times",
SkTypeface::kBold);
if (NULL == orig) {
orig = SkTypeface::RefDefault();
}
fColorType = SkNEW_ARGS(SkGTypeface, (orig, paint));
orig->unref();
}
virtual ~ColorTypeXfermodeGM() {
fColorType->unref();
}
protected:
virtual SkString onShortName() {
return SkString("colortype_xfermodes");
}
virtual SkISize onISize() {
return SkISize::Make(400, 640);
}
virtual void onDraw(SkCanvas* canvas) {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
const struct {
SkXfermode::Mode fMode;
const char* fLabel;
} gModes[] = {
{ SkXfermode::kClear_Mode, "Clear" },
{ SkXfermode::kSrc_Mode, "Src" },
{ SkXfermode::kDst_Mode, "Dst" },
{ SkXfermode::kSrcOver_Mode, "SrcOver" },
{ SkXfermode::kDstOver_Mode, "DstOver" },
{ SkXfermode::kSrcIn_Mode, "SrcIn" },
{ SkXfermode::kDstIn_Mode, "DstIn" },
{ SkXfermode::kSrcOut_Mode, "SrcOut" },
{ SkXfermode::kDstOut_Mode, "DstOut" },
{ SkXfermode::kSrcATop_Mode, "SrcATop" },
{ SkXfermode::kDstATop_Mode, "DstATop" },
{ SkXfermode::kXor_Mode, "Xor" },
{ SkXfermode::kPlus_Mode, "Plus" },
{ SkXfermode::kModulate_Mode, "Modulate" },
{ SkXfermode::kScreen_Mode, "Screen" },
{ SkXfermode::kOverlay_Mode, "Overlay" },
{ SkXfermode::kDarken_Mode, "Darken" },
{ SkXfermode::kLighten_Mode, "Lighten" },
{ SkXfermode::kColorDodge_Mode, "ColorDodge" },
{ SkXfermode::kColorBurn_Mode, "ColorBurn" },
{ SkXfermode::kHardLight_Mode, "HardLight" },
{ SkXfermode::kSoftLight_Mode, "SoftLight" },
{ SkXfermode::kDifference_Mode, "Difference" },
{ SkXfermode::kExclusion_Mode, "Exclusion" },
{ SkXfermode::kMultiply_Mode, "Multiply" },
{ SkXfermode::kHue_Mode, "Hue" },
{ SkXfermode::kSaturation_Mode, "Saturation" },
{ SkXfermode::kColor_Mode, "Color" },
{ SkXfermode::kLuminosity_Mode, "Luminosity" },
};
const SkScalar w = SkIntToScalar(W);
const SkScalar h = SkIntToScalar(H);
SkMatrix m;
m.setScale(SkIntToScalar(6), SkIntToScalar(6));
SkShader* s = SkShader::CreateBitmapShader(fBG,
SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode,
&m);
SkPaint labelP;
labelP.setAntiAlias(true);
sk_tool_utils::set_portable_typeface(&labelP);
labelP.setTextAlign(SkPaint::kCenter_Align);
SkPaint textP;
textP.setAntiAlias(true);
textP.setTypeface(fColorType);
textP.setTextSize(SkIntToScalar(70));
const int W = 5;
SkScalar x0 = 0;
SkScalar y0 = 0;
SkScalar x = x0, y = y0;
for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
SkAutoUnref aur(mode);
SkRect r;
r.set(x, y, x+w, y+h);
SkPaint p;
p.setStyle(SkPaint::kFill_Style);
p.setShader(s);
canvas->drawRect(r, p);
r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
p.setStyle(SkPaint::kStroke_Style);
p.setShader(NULL);
canvas->drawRect(r, p);
textP.setXfermode(mode);
canvas->drawText("H", 1, x+ w/10.f, y + 7.f*h/8.f, textP);
#if 1
canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
x + w/2, y - labelP.getTextSize()/2, labelP);
#endif
x += w + SkIntToScalar(10);
if ((i % W) == W - 1) {
x = x0;
y += h + SkIntToScalar(30);
}
}
s->unref();
}
virtual uint32_t onGetFlags() const {
return kSkipPipe_Flag | kSkipPicture_Flag;
}
private:
SkTypeface* fColorType;
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static GM* MyFactory(void*) { return new ColorTypeXfermodeGM; }
static GMRegistry reg(MyFactory);
}

View File

@ -49,6 +49,7 @@
'../gm/colorfilters.cpp',
'../gm/colormatrix.cpp',
'../gm/colortype.cpp',
'../gm/colortypexfermode.cpp',
'../gm/colorwheel.cpp',
'../gm/complexclip.cpp',
'../gm/complexclip2.cpp',

View File

@ -15,6 +15,7 @@
#include "GrTextStrike.h"
#include "GrTextStrike_impl.h"
#include "effects/GrCustomCoordsTextureEffect.h"
#include "effects/GrSimpleTextureEffect.h"
#include "SkAutoKern.h"
#include "SkColorPriv.h"
@ -33,21 +34,29 @@ SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
namespace {
// position + texture coord
extern const GrVertexAttrib gTextVertexAttribs[] = {
extern const GrVertexAttrib gLCDVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
};
static const size_t kTextVASize = 2 * sizeof(SkPoint);
static const size_t kLCDTextVASize = 2 * sizeof(SkPoint);
// position + local coord
extern const GrVertexAttrib gColorVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
};
static const size_t kColorTextVASize = 2 * sizeof(SkPoint);
// position + color + texture coord
extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
extern const GrVertexAttrib gGrayVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
{kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
};
static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
static const size_t kGrayTextVASize = 2 * sizeof(SkPoint) + sizeof(GrColor);
static const int kVerticesPerGlyph = 4;
static const int kIndicesPerGlyph = 6;
@ -345,18 +354,21 @@ void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skP
this->finish();
}
static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, bool useColorVerts) {
static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, GrMaskFormat maskFormat) {
if (numVertices <= 0) {
return NULL;
}
// set up attributes
if (useColorVerts) {
drawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
if (kA8_GrMaskFormat == maskFormat) {
drawTarget->drawState()->setVertexAttribs<gGrayVertexAttribs>(
SK_ARRAY_COUNT(gGrayVertexAttribs), kGrayTextVASize);
} else if (kARGB_GrMaskFormat == maskFormat) {
drawTarget->drawState()->setVertexAttribs<gColorVertexAttribs>(
SK_ARRAY_COUNT(gColorVertexAttribs), kColorTextVASize);
} else {
drawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
drawTarget->drawState()->setVertexAttribs<gLCDVertexAttribs>(
SK_ARRAY_COUNT(gLCDVertexAttribs), kLCDTextVASize);
}
void* vertices = NULL;
bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
@ -476,12 +488,10 @@ HAS_ATLAS:
fCurrMaskFormat = glyph->fMaskFormat;
}
bool useColorVerts = kA8_GrMaskFormat == fCurrMaskFormat;
if (NULL == fVertices) {
int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts);
fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
}
SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
@ -495,8 +505,16 @@ HAS_ATLAS:
fVertexBounds.joinNonEmptyArg(r);
size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
(2 * sizeof(SkPoint));
size_t vertSize;
switch (fCurrMaskFormat) {
case kA8_GrMaskFormat:
vertSize = kGrayTextVASize;
break;
case kARGB_GrMaskFormat:
vertSize = kColorTextVASize;
default:
vertSize = kLCDTextVASize;
}
SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
@ -512,7 +530,7 @@ HAS_ATLAS:
SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
vertSize);
if (useColorVerts) {
if (kA8_GrMaskFormat == fCurrMaskFormat) {
if (0xFF == GrColorUnpackA(fPaint.getColor())) {
fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
}
@ -548,16 +566,23 @@ void GrBitmapTextContext::flush() {
SkASSERT(fCurrTexture);
GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
uint32_t textureUniqueID = fCurrTexture->getUniqueID();
// This effect could be stored with one of the cache objects (atlas?)
if (kARGB_GrMaskFormat == fCurrMaskFormat) {
GrFragmentProcessor* fragProcessor = GrSimpleTextureEffect::Create(fCurrTexture,
SkMatrix::I(),
params);
drawState->addColorProcessor(fragProcessor)->unref();
} else {
uint32_t textureUniqueID = fCurrTexture->getUniqueID();
if (textureUniqueID != fEffectTextureUniqueID) {
fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
params));
fEffectTextureUniqueID = textureUniqueID;
}
if (textureUniqueID != fEffectTextureUniqueID) {
fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
params));
fEffectTextureUniqueID = textureUniqueID;
drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
}
// This effect could be stored with one of the cache objects (atlas?)
drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
SkASSERT(fStrike);
switch (fCurrMaskFormat) {
// Color bitmap text