aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/dcshader.cpp298
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/gpu/GrColor.h14
-rw-r--r--src/core/SkBlitter.cpp36
-rw-r--r--tests/GpuColorFilterTest.cpp6
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.