diff options
-rw-r--r-- | gm/dcshader.cpp | 298 | ||||
-rw-r--r-- | gyp/gmslides.gypi | 1 | ||||
-rw-r--r-- | include/gpu/GrColor.h | 14 | ||||
-rw-r--r-- | src/core/SkBlitter.cpp | 36 | ||||
-rw-r--r-- | tests/GpuColorFilterTest.cpp | 6 |
5 files changed, 331 insertions, 24 deletions
diff --git a/gm/dcshader.cpp b/gm/dcshader.cpp new file mode 100644 index 0000000000..24d548d8d2 --- /dev/null +++ b/gm/dcshader.cpp @@ -0,0 +1,298 @@ + +/* + * 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" +#if SK_SUPPORT_GPU +#include "GrFragmentProcessor.h" +#include "GrCoordTransform.h" +#include "gl/GrGLProcessor.h" +#include "gl/builders/GrGLProgramBuilder.h" +#include "Resources.h" +#include "SkShader.h" +#include "SkStream.h" +#include "SkTypeface.h" + +namespace skiagm { + +/////////////////////////////////////////////////////////////////////////////// + +class DCShader : public SkShader { +public: + DCShader(const SkMatrix& matrix) : fDeviceMatrix(matrix) {} + + Factory getFactory() const SK_OVERRIDE { return NULL; } + + bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM, + const SkMatrix* localMatrix, GrColor* color, + GrFragmentProcessor** fp) const SK_OVERRIDE; +private: + const SkMatrix fDeviceMatrix; +}; + +class DCFP : public GrFragmentProcessor { +public: + DCFP(const SkMatrix& m) : fDeviceTransform(kDevice_GrCoordSet, m) { + this->addCoordTransform(&fDeviceTransform); + this->initClassID<DCFP>(); + } + + void getGLProcessorKey(const GrGLCaps& caps, + GrProcessorKeyBuilder* b) const SK_OVERRIDE {} + + GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE { + class DCGLFP : public GrGLFragmentProcessor { + void emitCode(GrGLFPBuilder* builder, + const GrFragmentProcessor& fp, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray& coords, + const TextureSamplerArray& samplers) { + GrGLFPFragmentBuilder* fpb = builder->getFragmentShaderBuilder(); + fpb->codeAppendf("vec2 c = %s;", fpb->ensureFSCoords2D(coords, 0).c_str()); + fpb->codeAppend("vec2 r = mod(c, vec2(20.0));"); + fpb->codeAppend("vec4 color = vec4(0.5*sin(c.x / 15.0) + 0.5," + "0.5*cos((c.x + c.y) / 15.0) + 0.5," + "(r.x + r.y) / 20.0," + "distance(r, vec2(15.0)) / 20.0 + 0.2);"); + fpb->codeAppendf("color.rgb *= color.a;" + "%s = color * %s;", + outputColor, GrGLSLExpr4(inputColor).c_str()); + } + void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {} + }; + return SkNEW(DCGLFP); + } + + const char* name() const SK_OVERRIDE { return "DCFP"; } + + void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { + inout->mulByUnknownFourComponents(); + } + +private: + bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; } + + GrCoordTransform fDeviceTransform; +}; + +bool DCShader::asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM, + const SkMatrix* localMatrix, GrColor* color, + GrFragmentProcessor** fp) const { + *fp = SkNEW_ARGS(DCFP, (fDeviceMatrix)); + *color = GrColorPackA4(paint.getAlpha()); + return true; +} + +class DCShaderGM : public GM { +public: + DCShaderGM() { + this->setBGColor(0xFFAABBCC); + } + + ~DCShaderGM() SK_OVERRIDE { + for (int i = 0; i < fPrims.count(); ++i) { + SkDELETE(fPrims[i]); + } + } + +protected: + uint32_t onGetFlags() const SK_OVERRIDE { + return kGPUOnly_Flag; + } + + SkString onShortName() SK_OVERRIDE { + return SkString("dcshader"); + } + + SkISize onISize() SK_OVERRIDE { return SkISize::Make(1000, 900); } + + void onOnceBeforeDraw() SK_OVERRIDE { + struct Rect : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + SkRect rect = SkRect::MakeXYWH(0, 0, 50, 50); + canvas->drawRect(rect, paint); + return rect; + } + }; + + struct Circle : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + static const SkScalar radius = 25; + canvas->drawCircle(radius, radius, radius, paint); + return SkRect::MakeXYWH(0, 0, 2 * radius, 2 * radius); + } + }; + + struct RRect : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + SkRRect rrect; + rrect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 10, 10); + canvas->drawRRect(rrect, paint); + return rrect.getBounds(); + } + }; + + struct DRRect : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + SkRRect outerRRect; + outerRRect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 5, 5); + SkRRect innerRRect; + innerRRect.setRectXY(SkRect::MakeXYWH(5, 8, 35, 30), 8, 3); + canvas->drawDRRect(outerRRect, innerRRect, paint); + return outerRRect.getBounds(); + } + }; + struct Path : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + SkPath path; + path.addCircle(15, 15, 10); + path.addOval(SkRect::MakeXYWH(2, 2, 22, 37)); + path.setFillType(SkPath::kEvenOdd_FillType); + canvas->drawPath(path, paint); + return path.getBounds(); + } + }; + + struct Points : public Prim { + Points(SkCanvas::PointMode mode) : fMode(mode) {} + + SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE { + SkRandom random; + SkPoint points[500]; + SkRect bounds = SkRect::MakeWH(50, 50); + int count = SkToInt(SK_ARRAY_COUNT(points)); + if (SkCanvas::kPoints_PointMode != fMode) { + count = SkTMin(count, 10); + } + for (int p = 0; p < count; ++p) { + points[p].fX = random.nextUScalar1() * bounds.width(); + points[p].fY = random.nextUScalar1() * bounds.width(); + } + canvas->drawPoints(fMode, count, points, paint); + return bounds; + } + SkCanvas::PointMode fMode; + }; + + struct Text : public Prim { + SkRect draw(SkCanvas* canvas, const SkPaint& origPaint) SK_OVERRIDE { + SkPaint paint = origPaint; + paint.setTextSize(30.f); + this->setFont(&paint); + const char* text = this->text(); + static const SkVector offset = SkVector::Make(10, 10); + canvas->drawText(text, strlen(text), offset.fX, offset.fY, paint); + SkRect bounds; + paint.measureText(text, strlen(text), &bounds); + bounds.offset(offset); + return bounds; + } + + virtual void setFont(SkPaint* paint) { + sk_tool_utils::set_portable_typeface(paint); + } + + virtual const char* text() const { return "Hello, Skia!"; } + }; + + struct BmpText : public Text { + void setFont(SkPaint* paint) SK_OVERRIDE { + if (!fTypeface) { + SkString filename = GetResourcePath("/Funkster.ttf"); + SkAutoTUnref<SkFILEStream> stream(new SkFILEStream(filename.c_str())); + if (!stream->isValid()) { + SkDebugf("Could not find Funkster.ttf, please set --resourcePath " + "correctly.\n"); + return; + } + fTypeface.reset(SkTypeface::CreateFromStream(stream)); + } + paint->setTypeface(fTypeface); + } + + const char* text() const SK_OVERRIDE { return "Hi, Skia!"; } + + SkAutoTUnref<SkTypeface> fTypeface; + }; + fPrims.push_back(SkNEW(Rect)); + fPrims.push_back(SkNEW(Circle)); + fPrims.push_back(SkNEW(RRect)); + fPrims.push_back(SkNEW(DRRect)); + fPrims.push_back(SkNEW(Path)); + fPrims.push_back(SkNEW(Points(SkCanvas::kPoints_PointMode))); + fPrims.push_back(SkNEW(Points(SkCanvas::kLines_PointMode))); + fPrims.push_back(SkNEW(Points(SkCanvas::kPolygon_PointMode))); + fPrims.push_back(SkNEW(Text)); + fPrims.push_back(SkNEW(BmpText)); + } + + void onDraw(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + SkTArray<SkMatrix> devMats; + devMats.push_back().reset(); + devMats.push_back().setRotate(45, 500, 500); + devMats.push_back().setRotate(-30, 200, 200); + devMats.back().setPerspX(-SkScalarToPersp(SK_Scalar1 / 2000)); + devMats.back().setPerspY(SkScalarToPersp(SK_Scalar1 / 1000)); + + + SkTArray<SkMatrix> viewMats; + viewMats.push_back().setScale(0.75f, 0.75f); + viewMats.push_back().setRotate(45, 50, 50); + viewMats.back().postScale(0.5f, 1.1f); + + canvas->translate(10, 20); + canvas->save(); + SkScalar tx = 0, maxTy = 0; + static const SkScalar kW = 900; + + for (int aa = 0; aa < 2; ++aa) { + for (int i = 0; i < fPrims.count(); ++i) { + for (int j = 0; j < devMats.count(); ++j) { + for (int k = 0; k < viewMats.count(); ++k) { + paint.setShader(SkNEW_ARGS(DCShader, (devMats[j])))->unref(); + paint.setAntiAlias(SkToBool(aa)); + canvas->save(); + canvas->concat(viewMats[k]); + SkRect bounds = fPrims[i]->draw(canvas, paint); + canvas->restore(); + viewMats[k].mapRect(&bounds); + // add margins + bounds.fRight += 20; + bounds.fBottom += 20; + canvas->translate(bounds.fRight, 0); + tx += bounds.fRight; + maxTy = SkTMax(bounds.fBottom, maxTy); + if (tx > kW) { + tx = 0; + canvas->restore(); + canvas->translate(0, maxTy); + canvas->save(); + maxTy = 0; + } + } + } + } + } + canvas->restore(); + } + +private: + struct Prim { + virtual ~Prim() {} + virtual SkRect draw(SkCanvas*, const SkPaint&) = 0; + }; + + SkTArray<Prim*> fPrims; + + typedef GM INHERITED; +}; + +DEF_GM( return SkNEW(DCShaderGM); ) +} +#endif diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index 1b78cc0cec..10b70f35b0 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -64,6 +64,7 @@ '../gm/cubicpaths.cpp', '../gm/cmykjpeg.cpp', '../gm/degeneratesegments.cpp', + '../gm/dcshader.cpp', '../gm/discard.cpp', '../gm/dashcubics.cpp', '../gm/dashing.cpp', diff --git a/include/gpu/GrColor.h b/include/gpu/GrColor.h index 860d18da2f..43bfd8dc11 100644 --- a/include/gpu/GrColor.h +++ b/include/gpu/GrColor.h @@ -41,8 +41,7 @@ typedef uint32_t GrColor; /** * Pack 4 components (RGBA) into a GrColor int */ -static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, - unsigned b, unsigned a) { +static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, unsigned b, unsigned a) { SkASSERT((uint8_t)r == r); SkASSERT((uint8_t)g == g); SkASSERT((uint8_t)b == b); @@ -53,6 +52,17 @@ static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, (a << GrColor_SHIFT_A); } +/** + * Packs a color with an alpha channel replicated across all four channels. + */ +static inline GrColor GrColorPackA4(unsigned a) { + SkASSERT((uint8_t)a == a); + return (a << GrColor_SHIFT_R) | + (a << GrColor_SHIFT_G) | + (a << GrColor_SHIFT_B) | + (a << GrColor_SHIFT_A); +} + // extract a component (byte) from a GrColor int #define GrColorUnpackR(color) (((color) >> GrColor_SHIFT_R) & 0xFF) diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 792661bc6f..5bb7ac8d01 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -841,14 +841,11 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, bool drawCoverage) { SkASSERT(allocator != NULL); - SkBlitter* blitter = NULL; - // which check, in case we're being called by a client with a dummy device // (e.g. they have a bounder that always aborts the draw) if (kUnknown_SkColorType == device.colorType() || (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) { - blitter = allocator->createT<SkNullBlitter>(); - return blitter; + return allocator->createT<SkNullBlitter>(); } SkShader* shader = origPaint.getShader(); @@ -873,8 +870,7 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, paint.writable()->setXfermode(NULL); break; case kSkipDrawing_XferInterp:{ - blitter = allocator->createT<SkNullBlitter>(); - return blitter; + return allocator->createT<SkNullBlitter>(); } default: break; @@ -921,24 +917,26 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, /* * We create a SkShader::Context object, and store it on the blitter. */ - SkShader::Context* shaderContext; + SkShader::Context* shaderContext = NULL; if (shader) { SkShader::ContextRec rec(device, *paint, matrix); - // Try to create the ShaderContext - void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize()); - shaderContext = shader->createContext(rec, storage); - if (!shaderContext) { - allocator->freeLast(); - blitter = allocator->createT<SkNullBlitter>(); - return blitter; + size_t contextSize = shader->contextSize(); + if (contextSize) { + // Try to create the ShaderContext + void* storage = allocator->reserveT<SkShader::Context>(contextSize); + shaderContext = shader->createContext(rec, storage); + if (!shaderContext) { + allocator->freeLast(); + return allocator->createT<SkNullBlitter>(); + } + SkASSERT(shaderContext); + SkASSERT((void*) shaderContext == storage); + } else { + return allocator->createT<SkNullBlitter>(); } - SkASSERT(shaderContext); - SkASSERT((void*) shaderContext == storage); - } else { - shaderContext = NULL; } - + SkBlitter* blitter = NULL; switch (device.colorType()) { case kAlpha_8_SkColorType: if (drawCoverage) { diff --git a/tests/GpuColorFilterTest.cpp b/tests/GpuColorFilterTest.cpp index aeee3daf37..bf0ba3046a 100644 --- a/tests/GpuColorFilterTest.cpp +++ b/tests/GpuColorFilterTest.cpp @@ -64,9 +64,9 @@ static void test_getConstantColorComponents(skiatest::Reporter* reporter, GrCont const GrColor gr_c1 = SkColor2GrColor(c1); const GrColor gr_c2 = SkColor2GrColor(c2); - const GrColor gr_black = GrColorPackRGBA(0, 0, 0, 0); - const GrColor gr_white = GrColorPackRGBA(255, 255, 255, 255); - const GrColor gr_whiteTrans = GrColorPackRGBA(128, 128, 128, 128); + const GrColor gr_black = GrColorPackA4(0); + const GrColor gr_white = GrColorPackA4(255); + const GrColor gr_whiteTrans = GrColorPackA4(128); GetConstantComponentTestCase filterTests[] = { // A color filtered with Clear produces black. |