move shadows to device virtual

This CL keeps the impl for each device backend in the
utils file for simplicity (shared helpers). Future CLs
may move into their respective impl as they become
more specialized.

Bug: skia:
Change-Id: I97ce6cdcc5106ebf4c84778f943cc32d0b7613c1
Reviewed-on: https://skia-review.googlesource.com/15893
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2017-05-17 08:53:36 -04:00 committed by Skia Commit-Bot
parent 63e7973d1f
commit 4204da25aa
17 changed files with 200 additions and 79 deletions

View File

@ -24,6 +24,7 @@ class SkData;
class SkDraw;
class SkDrawable;
class SkDrawFilter;
struct SkDrawShadowRec;
class SkImage;
class SkImageFilter;
class SkLights;
@ -1237,6 +1238,8 @@ public:
*/
void temporary_internal_getRgnClip(SkRegion* region);
void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&);
protected:
// default impl defers to getDevice()->newSurface(info)
virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props);
@ -1331,6 +1334,7 @@ protected:
const SkPaint* paint);
virtual void onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
const SkRect& dst, const SkPaint* paint);
virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&);
enum ClipEdgeStyle {
kHard_ClipEdgeStyle,

View File

@ -71,6 +71,7 @@ protected:
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;

View File

@ -1909,6 +1909,21 @@ void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
}
}
void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
this->onDrawShadowRec(path, rec);
}
void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
SkPaint paint;
const SkRect& pathBounds = path.getBounds();
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
while (iter.next()) {
iter.fDevice->drawShadow(path, rec);
}
LOOPER_END
}
//////////////////////////////////////////////////////////////////////////////
// These are the virtual drawing methods
//////////////////////////////////////////////////////////////////////////////

View File

@ -8,6 +8,7 @@
#include "SkColorFilter.h"
#include "SkColorSpaceXformCanvas.h"
#include "SkColorSpaceXformer.h"
#include "SkDrawShadowRec.h"
#include "SkGradientShader.h"
#include "SkImageFilter.h"
#include "SkImagePriv.h"
@ -217,7 +218,11 @@ public:
fTarget->drawImageLattice(fXformer->apply(bitmap).get(), lattice, dst,
MaybePaint(paint, fXformer.get()));
}
void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
SkDrawShadowRec newRec(rec);
newRec.fColor = fXformer->apply(rec.fColor);
fTarget->private_draw_shadow_rec(path, newRec);
}
void onDrawPicture(const SkPicture* pic,
const SkMatrix* matrix,
const SkPaint* paint) override {

View File

@ -15,6 +15,7 @@
class SkBitmap;
class SkDrawFilter;
struct SkDrawShadowRec;
class SkImageFilterCache;
struct SkIRect;
class SkMatrix;
@ -234,6 +235,8 @@ protected:
const SkScalar pos[], int scalarsPerPos,
const SkPoint& offset, const SkPaint& paint) = 0;
virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
// default implementation unrolls the blob runs.
virtual void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
const SkPaint& paint, SkDrawFilter* drawFilter);

View File

@ -0,0 +1,23 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDrawShadowRec_DEFINED
#define SkDrawShadowRec_DEFINED
#include "SkPath.h"
struct SkDrawShadowRec {
SkPoint3 fZPlaneParams;
SkPoint3 fLightPos;
SkScalar fLightRadius;
float fAmbientAlpha;
float fSpotAlpha;
SkColor fColor;
uint32_t fFlags;
};
#endif

View File

@ -8,6 +8,7 @@
#include "SkCanvas.h"
#include "SkData.h"
#include "SkDrawFilter.h"
#include "SkDrawShadowRec.h"
#include "SkImage.h"
#include "SkImageFilter.h"
#include "SkLiteDL.h"
@ -55,7 +56,7 @@ namespace {
M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice) \
M(DrawText) M(DrawPosText) M(DrawPosTextH) \
M(DrawTextOnPath) M(DrawTextRSXform) M(DrawTextBlob) \
M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas)
M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas) M(DrawShadowRec)
#define M(T) T,
enum class Type : uint8_t { TYPES(M) };
@ -477,6 +478,17 @@ namespace {
maybe_unset(cull), &paint);
}
};
struct DrawShadowRec final : Op {
static const auto kType = Type::DrawShadowRec;
DrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec)
: fPath(path), fRec(rec)
{}
SkPath fPath;
SkDrawShadowRec fRec;
void draw(SkCanvas* c, const SkMatrix&) const {
c->private_draw_shadow_rec(fPath, fRec);
}
};
}
template <typename T, typename... Args>
@ -662,6 +674,9 @@ void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const S
texs, count,
colors, colors ? count : 0);
}
void SkLiteDL::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
this->push<DrawShadowRec>(0, path, rec);
}
typedef void(*draw_fn)(const void*, SkCanvas*, const SkMatrix&);
typedef void(*void_fn)(const void*);

View File

@ -77,6 +77,7 @@ public:
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkRect*, const SkPaint*);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
private:
template <typename T, typename... Args>

View File

@ -194,3 +194,6 @@ void SkLiteRecorder::onDrawAtlas(const SkImage* atlas,
const SkPaint* paint) {
fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint);
}
void SkLiteRecorder::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
fDL->drawShadowRec(path, rec);
}

View File

@ -77,6 +77,7 @@ public:
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int, SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
private:
typedef SkNoDrawCanvas INHERITED;

View File

@ -125,6 +125,7 @@ DRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.
DRAW(DrawAtlas, drawAtlas(r.atlas.get(),
r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
DRAW(DrawVertices, drawVertices(r.vertices, r.bmode, r.paint));
DRAW(DrawShadowRec, private_draw_shadow_rec(r.path, r.rec));
DRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value.get()));
#undef DRAW
@ -455,6 +456,10 @@ private:
}
}
Bounds bounds(const DrawShadowRec& op) const {
return this->adjustAndMap(op.path.getBounds(), nullptr);
}
Bounds bounds(const DrawPicture& op) const {
SkRect dst = op.picture->cullRect();
op.matrix.mapRect(&dst);

View File

@ -338,6 +338,10 @@ void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], cons
this->copy(cull));
}
void SkRecorder::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
APPEND(DrawShadowRec, path, rec);
}
void SkRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
APPEND(DrawAnnotation, rect, SkString(key), sk_ref_sp(value));
}

View File

@ -121,6 +121,7 @@ public:
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int count, SkBlendMode, const SkRect* cull, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle) override;
void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) override;

View File

@ -11,6 +11,7 @@
#include "SkData.h"
#include "SkCanvas.h"
#include "SkDrawable.h"
#include "SkDrawShadowRec.h"
#include "SkImage.h"
#include "SkImageFilter.h"
#include "SkMatrix.h"
@ -80,6 +81,7 @@ namespace SkRecords {
M(DrawTextBlob) \
M(DrawAtlas) \
M(DrawVertices) \
M(DrawShadowRec) \
M(DrawAnnotation)
// Defines SkRecords::Type, an enum of all record types.
@ -345,6 +347,9 @@ RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
SkPaint paint;
sk_sp<SkVertices> vertices;
SkBlendMode bmode);
RECORD(DrawShadowRec, kDraw_Tag,
SkPath path;
SkDrawShadowRec rec);
RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548
SkRect rect;
SkString key;

View File

@ -92,6 +92,7 @@ public:
void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
const SkPaint& paint, SkDrawFilter* drawFilter) override;
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
const SkColor[], int count, SkBlendMode, const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;

View File

@ -299,6 +299,13 @@ void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4]
}
}
void SkNWayCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
Iter iter(fList);
while (iter.next()) {
iter->private_draw_shadow_rec(path, rec);
}
}
void SkNWayCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) {
Iter iter(fList);
while (iter.next()) {

View File

@ -9,6 +9,8 @@
#include "SkCanvas.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkDevice.h"
#include "SkDrawShadowRec.h"
#include "SkPath.h"
#include "SkPM4f.h"
#include "SkRandom.h"
@ -20,9 +22,9 @@
#if SK_SUPPORT_GPU
#include "GrShape.h"
#include "effects/GrBlurredEdgeFragmentProcessor.h"
#endif
#include "../../src/effects/shadows/SkAmbientShadowMaskFilter.h"
#include "../../src/effects/shadows/SkSpotShadowMaskFilter.h"
#endif
/**
* Gaussian color filter -- produces a Gaussian ramp based on the color's B value,
@ -444,7 +446,9 @@ static void* kNamespace;
* they are first found in SkResourceCache.
*/
template <typename FACTORY>
void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color) {
void draw_shadow(const FACTORY& factory,
std::function<void(const SkVertices*, SkBlendMode, const SkPaint&,
SkScalar tx, SkScalar ty)> drawProc, ShadowedPath& path, SkColor color) {
FindContext<FACTORY> context(&path.viewMatrix(), &factory);
SkResourceCache::Key* key = nullptr;
@ -496,82 +500,83 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
if (translate->fX || translate->fY) {
canvas->save();
canvas->translate(translate->fX, translate->fY);
}
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
if (translate->fX || translate->fY) {
canvas->restore();
}
drawProc(vertices.get(), SkBlendMode::kModulate, paint, translate->fX, translate->fY);
}
}
static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar occluderZ,
const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags) {
// only supported in GPU code
if (!canvas->getGrContext()) {
return false;
}
static bool tilted(const SkPoint3& zPlaneParams) {
return !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
}
SkRect rect;
SkRRect rrect;
const SkMatrix& ctm = canvas->getTotalMatrix();
if (ctm.rectStaysRect() && ctm.isSimilarity()) {
static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
SkPoint3 result;
m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
result.fZ = pt.fZ;
return result;
}
#if SK_SUPPORT_GPU
#include "SkGpuDevice.h"
void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
// check z plane
bool tiltZPlane = tilted(rec.fZPlaneParams);
bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
const SkMatrix& ctm = this->ctm();
if (!tiltZPlane && !skipAnalytic && ctm.rectStaysRect() && ctm.isSimilarity()) {
SkPoint3 devLightPos = map(ctm, rec.fLightPos);
const SkScalar occluderZ = rec.fZPlaneParams.fZ;
SkPaint ambientPaint, spotPaint;
ambientPaint.setColor(rec.fColor);
spotPaint.setColor(rec.fColor);
if (rec.fAmbientAlpha > 0) {
ambientPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ, rec.fAmbientAlpha,
rec.fFlags));
}
if (rec.fSpotAlpha > 0) {
spotPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
rec.fLightRadius, rec.fSpotAlpha,
rec.fFlags));
}
SkRect rect;
SkRRect rrect;
if (path.isRect(&rect)) {
SkPaint newPaint;
newPaint.setColor(color);
if (ambientAlpha > 0) {
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
ambientAlpha, flags));
canvas->drawRect(rect, newPaint);
if (rec.fAmbientAlpha > 0) {
this->drawRect(rect, ambientPaint);
}
if (spotAlpha > 0) {
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
lightRadius, spotAlpha,
flags));
canvas->drawRect(rect, newPaint);
if (rec.fSpotAlpha > 0) {
this->drawRect(rect, spotPaint);
}
return true;
return;
} else if (path.isRRect(&rrect) && rrect.isSimpleCircular() &&
rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero) {
SkPaint newPaint;
newPaint.setColor(color);
if (ambientAlpha > 0) {
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
ambientAlpha, flags));
canvas->drawRRect(rrect, newPaint);
if (rec.fAmbientAlpha > 0) {
this->drawRRect(rrect, ambientPaint);
}
if (spotAlpha > 0) {
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
lightRadius, spotAlpha,
flags));
canvas->drawRRect(rrect, newPaint);
if (rec.fSpotAlpha > 0) {
this->drawRRect(rrect, spotPaint);
}
return true;
return;
} else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
rect.width() > SK_ScalarNearlyZero) {
SkPaint newPaint;
newPaint.setColor(color);
if (ambientAlpha > 0) {
newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
ambientAlpha, flags));
canvas->drawOval(rect, newPaint);
if (rec.fAmbientAlpha > 0) {
this->drawOval(rect, ambientPaint);
}
if (spotAlpha > 0) {
newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
lightRadius, spotAlpha,
flags));
canvas->drawOval(rect, newPaint);
if (rec.fSpotAlpha > 0) {
this->drawOval(rect, spotPaint);
}
return true;
return;
}
}
return false;
// failed to find an accelerated case
this->INHERITED::drawShadow(path, rec);
}
#endif
static SkColor compute_render_color(SkColor color, float alpha) {
return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
@ -583,26 +588,47 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags) {
// check z plane
bool tiltZPlane = !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
// try fast paths
bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag) || tiltZPlane;
if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, devLightPos,
lightRadius, ambientAlpha, spotAlpha, color,
flags)) {
SkMatrix inverse;
if (!canvas->getTotalMatrix().invert(&inverse)) {
return;
}
SkPoint pt = inverse.mapXY(devLightPos.fX, devLightPos.fY);
SkAutoCanvasRestore acr(canvas, true);
SkMatrix viewMatrix = canvas->getTotalMatrix();
canvas->resetMatrix();
SkDrawShadowRec rec;
rec.fZPlaneParams = zPlaneParams;
rec.fLightPos = { pt.fX, pt.fY, devLightPos.fZ };
rec.fLightRadius = lightRadius;
rec.fAmbientAlpha = SkScalarToFloat(ambientAlpha);
rec.fSpotAlpha = SkScalarToFloat(spotAlpha);
rec.fColor = color;
rec.fFlags = flags;
canvas->private_draw_shadow_rec(path, rec);
}
void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
auto drawVertsProc = [this](const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint,
SkScalar tx, SkScalar ty) {
SkAutoDeviceCTMRestore adr(this, SkMatrix::Concat(this->ctm(),
SkMatrix::MakeTrans(tx, ty)));
this->drawVertices(vertices, mode, paint);
};
SkMatrix viewMatrix = this->ctm();
SkAutoDeviceCTMRestore adr(this, SkMatrix::I());
ShadowedPath shadowedPath(&path, &viewMatrix);
bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
bool tiltZPlane = tilted(rec.fZPlaneParams);
bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
bool uncached = tiltZPlane || path.isVolatile();
SkColor color = rec.fColor;
SkPoint3 zPlaneParams = rec.fZPlaneParams;
SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
float lightRadius = rec.fLightRadius;
float ambientAlpha = rec.fAmbientAlpha;
if (ambientAlpha > 0) {
ambientAlpha = SkTMin(ambientAlpha, 1.f);
if (uncached) {
@ -614,19 +640,20 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
} else {
AmbientVerticesFactory factory;
factory.fOccluderHeight = zPlaneParams.fZ;
factory.fTransparent = transparent;
SkColor renderColor = compute_render_color(color, ambientAlpha);
draw_shadow(factory, canvas, shadowedPath, renderColor);
draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
}
}
float spotAlpha = rec.fSpotAlpha;
if (spotAlpha > 0) {
spotAlpha = SkTMin(spotAlpha, 1.f);
if (uncached) {
@ -641,7 +668,7 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
} else {
SpotVerticesFactory factory;
SkScalar occluderHeight = zPlaneParams.fZ;
@ -690,7 +717,7 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
}
#endif
SkColor renderColor = compute_render_color(color, spotAlpha);
draw_shadow(factory, canvas, shadowedPath, renderColor);
draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
}
}
}