aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/SkGr.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-09-28 06:26:28 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-09-28 06:26:29 -0700
commitf1b7a1d82860e106ed7d3e0e876419e65783fb84 (patch)
tree8177909b7cf258639fccd47037befeae6c649c29 /src/gpu/SkGr.cpp
parent67c6513a96f0dbfeff2bee1c444a5ac9f07857c6 (diff)
Make skpaint->grpaint flow work for composing draws (verts and atlas)
One side effect is that the SkShader's (or implicit shader's) fragment processor is responsible for the transition from an unpremul paint color to a premul color. Review URL: https://codereview.chromium.org/1348583002
Diffstat (limited to 'src/gpu/SkGr.cpp')
-rw-r--r--src/gpu/SkGr.cpp184
1 files changed, 146 insertions, 38 deletions
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 09c83b929a..e0892d8ab9 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -24,8 +24,10 @@
#include "SkTextureCompressor.h"
#include "SkYUVPlanesCache.h"
#include "effects/GrBicubicEffect.h"
+#include "effects/GrConstColorProcessor.h"
#include "effects/GrDitherEffect.h"
#include "effects/GrPorterDuffXferProcessor.h"
+#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/GrYUVtoRGBEffect.h"
#ifndef SK_IGNORE_ETC1_SUPPORT
@@ -706,46 +708,132 @@ bool GrPixelConfig2ColorAndProfileType(GrPixelConfig config, SkColorType* ctOut,
return true;
}
-///////////////////////////////////////////////////////////////////////////////
-bool SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor paintColor,
- bool constantColor, GrPaint* grPaint) {
+////////////////////////////////////////////////////////////////////////////////////////////////
+static inline bool skpaint_to_grpaint_impl(GrContext* context,
+ const SkPaint& skPaint,
+ const SkMatrix& viewM,
+ const GrFragmentProcessor** shaderProcessor,
+ SkXfermode::Mode* primColorMode,
+ bool primitiveIsSrc,
+ GrPaint* grPaint) {
grPaint->setAntiAlias(skPaint.isAntiAlias());
- SkXfermode* mode = skPaint.getXfermode();
- GrXPFactory* xpFactory = nullptr;
- if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
- // Fall back to src-over
- // return false here?
- xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
+ // Setup the initial color considering the shader, the SkPaint color, and the presence or not
+ // of per-vertex colors.
+ SkAutoTUnref<const GrFragmentProcessor> aufp;
+ const GrFragmentProcessor* shaderFP = NULL;
+ if (shaderProcessor) {
+ shaderFP = *shaderProcessor;
+ } else if (const SkShader* shader = skPaint.getShader()) {
+ aufp.reset(shader->asFragmentProcessor(context, viewM, NULL, skPaint.getFilterQuality(),
+ grPaint->getProcessorDataManager()));
+ shaderFP = aufp;
+ if (!shaderFP) {
+ return false;
+ }
}
- SkASSERT(xpFactory);
- grPaint->setXPFactory(xpFactory)->unref();
- //set the color of the paint to the one of the parameter
- grPaint->setColor(paintColor);
+ // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
+ // a known constant value. In that case we can simply apply a color filter during this
+ // conversion without converting the color filter to a GrFragmentProcessor.
+ bool applyColorFilterToPaintColor = false;
+ if (shaderFP) {
+ if (primColorMode) {
+ // There is a blend between the primitive color and the shader color. The shader sees
+ // the opaque paint color. The shader's output is blended using the provided mode by
+ // the primitive color. The blended color is then modulated by the paint's alpha.
+
+ // The geometry processor will insert the primitive color to start the color chain, so
+ // the GrPaint color will be ignored.
+
+ GrColor shaderInput = SkColorToOpaqueGrColor(skPaint.getColor());
+
+ shaderFP = GrFragmentProcessor::OverrideInput(shaderFP, shaderInput);
+ aufp.reset(shaderFP);
+
+ if (primitiveIsSrc) {
+ shaderFP = GrXfermodeFragmentProcessor::CreateFromDstProcessor(shaderFP,
+ *primColorMode);
+ } else {
+ shaderFP = GrXfermodeFragmentProcessor::CreateFromSrcProcessor(shaderFP,
+ *primColorMode);
+ }
+ aufp.reset(shaderFP);
+ // The above may return null if compose results in a pass through of the prim color.
+ if (shaderFP) {
+ grPaint->addColorFragmentProcessor(shaderFP);
+ }
+
+ GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+ if (GrColor_WHITE != paintAlpha) {
+ grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create(
+ paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref();
+ }
+ } else {
+ // The shader's FP sees the paint unpremul color
+ grPaint->setColor(SkColorToUnpremulGrColor(skPaint.getColor()));
+ grPaint->addColorFragmentProcessor(shaderFP);
+ }
+ } else {
+ if (primColorMode) {
+ // There is a blend between the primitive color and the paint color. The blend considers
+ // the opaque paint color. The paint's alpha is applied to the post-blended color.
+ SkAutoTUnref<const GrFragmentProcessor> processor(
+ GrConstColorProcessor::Create(SkColorToOpaqueGrColor(skPaint.getColor()),
+ GrConstColorProcessor::kIgnore_InputMode));
+ if (primitiveIsSrc) {
+ processor.reset(GrXfermodeFragmentProcessor::CreateFromDstProcessor(processor,
+ *primColorMode));
+ } else {
+ processor.reset(GrXfermodeFragmentProcessor::CreateFromSrcProcessor(processor,
+ *primColorMode));
+
+ }
+ if (processor) {
+ grPaint->addColorFragmentProcessor(processor);
+ }
+
+ grPaint->setColor(SkColorToUnpremulGrColor(skPaint.getColor()) | 0xFF000000);
+
+ GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+ grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create(
+ paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref();
+ } else {
+ // No shader, no primitive color.
+ grPaint->setColor(SkColorToPremulGrColor(skPaint.getColor()));
+ applyColorFilterToPaintColor = true;
+ }
+ }
SkColorFilter* colorFilter = skPaint.getColorFilter();
if (colorFilter) {
- // if the source color is a constant then apply the filter here once rather than per pixel
- // in a shader.
- if (constantColor) {
- SkColor filtered = colorFilter->filterColor(skPaint.getColor());
- grPaint->setColor(SkColor2GrColor(filtered));
+ if (applyColorFilterToPaintColor) {
+ grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor())));
} else {
SkTDArray<const GrFragmentProcessor*> array;
- // return false if failed?
if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
&array)) {
for (int i = 0; i < array.count(); ++i) {
- grPaint->addColorFragmentProcessor(array[i]);
- array[i]->unref();
+ grPaint->addColorFragmentProcessor(array[i])->unref();
}
+ } else {
+ return false;
}
}
}
+ SkXfermode* mode = skPaint.getXfermode();
+ GrXPFactory* xpFactory = nullptr;
+ if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
+ // Fall back to src-over
+ // return false here?
+ xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
+ }
+ SkASSERT(xpFactory);
+ grPaint->setXPFactory(xpFactory)->unref();
+
#ifndef SK_IGNORE_GPU_DITHER
if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {
grPaint->addColorFragmentProcessor(GrDitherEffect::Create())->unref();
@@ -754,29 +842,49 @@ bool SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor
return true;
}
-bool SkPaint2GrPaint(GrContext* context,const SkPaint& skPaint, const SkMatrix& viewM,
- bool constantColor, GrPaint* grPaint) {
- SkShader* shader = skPaint.getShader();
- if (nullptr == shader) {
- return SkPaint2GrPaintNoShader(context, skPaint, SkColor2GrColor(skPaint.getColor()),
- constantColor, grPaint);
- }
-
- GrColor paintColor = SkColor2GrColor(skPaint.getColor());
+bool SkPaintToGrPaint(GrContext* context, const SkPaint& skPaint, const SkMatrix& viewM,
+ GrPaint* grPaint) {
+ return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, nullptr, false, grPaint);
+}
- const GrFragmentProcessor* fp = shader->asFragmentProcessor(context, viewM, NULL,
- skPaint.getFilterQuality(), grPaint->getProcessorDataManager());
- if (!fp) {
+/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
+bool SkPaintToGrPaintReplaceShader(GrContext* context,
+ const SkPaint& skPaint,
+ const GrFragmentProcessor* shaderFP,
+ GrPaint* grPaint) {
+ if (!shaderFP) {
return false;
}
- grPaint->addColorFragmentProcessor(fp)->unref();
- constantColor = false;
+ return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), &shaderFP, nullptr, false,
+ grPaint);
+}
+
+/** Ignores the SkShader (if any) on skPaint. */
+bool SkPaintToGrPaintNoShader(GrContext* context,
+ const SkPaint& skPaint,
+ GrPaint* grPaint) {
+ // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
+ static const GrFragmentProcessor* kNullShaderFP = nullptr;
+ static const GrFragmentProcessor** kIgnoreShader = &kNullShaderFP;
+ return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), kIgnoreShader, nullptr, false,
+ grPaint);
+}
- // The grcolor is automatically set when calling asFragmentProcessor.
- // If the shader can be seen as an effect it returns true and adds its effect to the grpaint.
- return SkPaint2GrPaintNoShader(context, skPaint, paintColor, constantColor, grPaint);
+/** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
+be setup as a vertex attribute using the specified SkXfermode::Mode. */
+bool SkPaintToGrPaintWithXfermode(GrContext* context,
+ const SkPaint& skPaint,
+ const SkMatrix& viewM,
+ SkXfermode::Mode primColorMode,
+ bool primitiveIsSrc,
+ GrPaint* grPaint) {
+ return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, &primColorMode, primitiveIsSrc,
+ grPaint);
}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
SkImageInfo GrMakeInfoFromTexture(GrTexture* tex, int w, int h, bool isOpaque) {
#ifdef SK_DEBUG
const GrSurfaceDesc& desc = tex->desc();