Made shadows blurry (thru implementing variance mapping)

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2224163005

Review-Url: https://codereview.chromium.org/2224163005
This commit is contained in:
vjiaoblack 2016-08-25 06:30:23 -07:00 committed by Commit bot
parent 199a2ea665
commit e6f5d56231
24 changed files with 425 additions and 98 deletions

View File

@ -76,6 +76,11 @@ public:
SkVector3::Make(0.1f, 0.2f, 1.0f))); SkVector3::Make(0.1f, 0.2f, 1.0f)));
builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f))); builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
fLights = builder.finish(); fLights = builder.finish();
fShadowParams.fShadowRadius = 4.0f;
fShadowParams.fBiasingConstant = 0.3f;
fShadowParams.fMinVariance = 1024;
fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
} }
protected: protected:
@ -95,11 +100,12 @@ protected:
// It's used to generate the depth maps. // It's used to generate the depth maps.
sk_sp<SkPicture> pic(make_test_picture(kWidth, kHeight)); sk_sp<SkPicture> pic(make_test_picture(kWidth, kHeight));
canvas->setLights(fLights); canvas->setLights(fLights);
canvas->drawShadowedPicture(pic, nullptr, nullptr); canvas->drawShadowedPicture(pic, nullptr, nullptr, fShadowParams);
} }
private: private:
sk_sp<SkLights> fLights; sk_sp<SkLights> fLights;
SkShadowParams fShadowParams;
typedef GM INHERITED; typedef GM INHERITED;
}; };

View File

@ -443,6 +443,7 @@
'<(skia_include_path)/private/SkOnce.h', '<(skia_include_path)/private/SkOnce.h',
'<(skia_include_path)/private/SkRecords.h', '<(skia_include_path)/private/SkRecords.h',
'<(skia_include_path)/private/SkSemaphore.h', '<(skia_include_path)/private/SkSemaphore.h',
'<(skia_include_path)/private/SkShadowParams.h',
'<(skia_include_path)/private/SkSpinlock.h', '<(skia_include_path)/private/SkSpinlock.h',
'<(skia_include_path)/private/SkTemplates.h', '<(skia_include_path)/private/SkTemplates.h',
'<(skia_include_path)/private/SkTArray.h', '<(skia_include_path)/private/SkTArray.h',

View File

@ -18,6 +18,7 @@
#include "SkSurfaceProps.h" #include "SkSurfaceProps.h"
#include "SkXfermode.h" #include "SkXfermode.h"
#include "SkLights.h" #include "SkLights.h"
#include "../private/SkShadowParams.h"
class GrContext; class GrContext;
class GrDrawContext; class GrDrawContext;
@ -1073,7 +1074,7 @@ public:
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
/** /**
* Draw the picture into this canvas. * Draw the picture into this canvas, with shadows!
* *
* We will use the canvas's lights along with the picture information (draw depths of * We will use the canvas's lights along with the picture information (draw depths of
* objects, etc) to first create a set of shadowmaps for the light-picture pairs, and * objects, etc) to first create a set of shadowmaps for the light-picture pairs, and
@ -1088,14 +1089,33 @@ public:
* This is logically equivalent to * This is logically equivalent to
* saveLayer(paint)/drawPicture/restore * saveLayer(paint)/drawPicture/restore
* *
* We also support using variance shadow maps for blurred shadows; the user can specify
* what shadow mapping algorithm to use with params.
* - Variance Shadow Mapping works by storing both the depth and depth^2 in the shadow map.
* - Then, the shadow map can be blurred, and when reading from it, the fragment shader
* can calculate the variance of the depth at a position by doing E(x^2) - E(x)^2.
* - We can then use the depth variance and depth at a fragment to arrive at an upper bound
* of the probability that the current surface is shadowed by using Chebyshev's
* inequality, and then use that to shade the fragment.
*
* - There are a few problems with VSM.
* * Light Bleeding | Areas with high variance, such as near the edges of high up rects,
* will cause their shadow penumbras to overwrite otherwise solid
* shadows.
* * Shape Distortion | We can combat Light Bleeding by biasing the shadow (setting
* mostly shaded fragments to completely shaded) and increasing
* the minimum allowed variance. However, this warps and rounds
* out the shape of the shadow.
*/ */
void drawShadowedPicture(const SkPicture*, void drawShadowedPicture(const SkPicture*,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint); const SkPaint* paint,
const SkShadowParams& params);
void drawShadowedPicture(const sk_sp<SkPicture>& picture, void drawShadowedPicture(const sk_sp<SkPicture>& picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
this->drawShadowedPicture(picture.get(), matrix, paint); const SkShadowParams& params) {
this->drawShadowedPicture(picture.get(), matrix, paint, params);
} }
#endif #endif
@ -1434,7 +1454,8 @@ protected:
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
virtual void onDrawShadowedPicture(const SkPicture*, virtual void onDrawShadowedPicture(const SkPicture*,
const SkMatrix*, const SkMatrix*,
const SkPaint*); const SkPaint*,
const SkShadowParams& params);
#endif #endif
// Returns the canvas to be used by DrawIter. Default implementation // Returns the canvas to be used by DrawIter. Default implementation

View File

@ -268,7 +268,8 @@ RECORD(DrawPicture, kDraw_Tag|kHasPaint_Tag,
RECORD(DrawShadowedPicture, kDraw_Tag|kHasPaint_Tag, RECORD(DrawShadowedPicture, kDraw_Tag|kHasPaint_Tag,
Optional<SkPaint> paint; Optional<SkPaint> paint;
sk_sp<const SkPicture> picture; sk_sp<const SkPicture> picture;
TypedMatrix matrix); TypedMatrix matrix;
const SkShadowParams& params);
RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag, RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag,
SkPaint paint; SkPaint paint;
SkCanvas::PointMode mode; SkCanvas::PointMode mode;

View File

@ -0,0 +1,48 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkShadowParams_DEFINED
#define SkShadowParams_DEFINED
/** \struct SkShadowParams
This struct holds information needed for drawing shadows.
fShadowRadius - radius of the shadow blur
fBiasingConstant - A constant used in variance shadow mapping to directly
0.0 - 1.0 reduce light bleeding. Essentially sets all shadows
~.25 below a certain brightness equal to no light, and does
a linear step on the rest. Essentially makes shadows
darker and more rounded at higher values.
fMinVariance - Too low of a variance (near the outer edges of blurry
~512, 1024 shadows) will lead to ugly sharp shadow brightness
distortions. This enforces a minimum amount of variance
in the calculation to smooth out the outside edges of
blurry shadows. However, too high of a value for this will
cause all shadows to be lighter by visibly different
amounts varying on depth.
fType - Decides which algorithm to use to draw shadows.
*/
struct SkShadowParams {
SkScalar fShadowRadius;
SkScalar fBiasingConstant;
SkScalar fMinVariance;
enum ShadowType {
kNoBlur_ShadowType,
kVariance_ShadowType,
kLast_ShadowType = kVariance_ShadowType
};
static const int kShadowTypeCount = kLast_ShadowType + 1;
ShadowType fType;
};
#endif

View File

@ -38,13 +38,31 @@ public:
fTestRects[2].fDepth = 240; fTestRects[2].fDepth = 240;
fTestRects[2].fGeometry = SkRect::MakeLTRB(100,100,250,250); fTestRects[2].fGeometry = SkRect::MakeLTRB(100,100,250,250);
fSliders[0].fGeometry = SkRect::MakeLTRB(20, 400, 30, 420);
fSliders[0].fOffset = 0.0f;
fSliders[0].fScale = 0.1f;
fSliders[1].fGeometry = SkRect::MakeLTRB(100, 420, 110, 440);
fSliders[1].fOffset = 0.0f;
fSliders[1].fScale = 10.0f;
fSliders[2].fGeometry = SkRect::MakeLTRB(0, 440, 10, 460);
fSliders[2].fOffset = 0.0f;
fSliders[2].fScale = 0.0025f;
fSceneChanged = true; fSceneChanged = true;
fLightsChanged = true; fLightsChanged = true;
fSelectedRect = -1; fSelectedRect = -1;
fSelectedSlider = -1;
fMoveLight = false; fMoveLight = false;
fClearShadowMaps = false; fClearShadowMaps = false;
fShadowParams.fShadowRadius = 2.0f;
fShadowParams.fBiasingConstant = 0.3f;
fShadowParams.fMinVariance = 1024;
fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
} }
protected: protected:
@ -67,6 +85,15 @@ protected:
// the shadow maps will be re-generated according to the new backend. // the shadow maps will be re-generated according to the new backend.
fClearShadowMaps = true; fClearShadowMaps = true;
break; break;
case 'B':
if (SkShadowParams::kVariance_ShadowType == fShadowParams.fType) {
fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
} else if (SkShadowParams::kNoBlur_ShadowType ==
fShadowParams.fType) {
fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
}
fLightsChanged = true;
break;
default: default:
break; break;
} }
@ -113,19 +140,46 @@ protected:
for (int i = 0; i < fLights->numLights(); i++) { for (int i = 0; i < fLights->numLights(); i++) {
fLights->light(i).setShadowMap(nullptr); fLights->light(i).setShadowMap(nullptr);
} }
fSceneChanged = false; fSceneChanged = false;
fLightsChanged = false; fLightsChanged = false;
fClearShadowMaps = false; fClearShadowMaps = false;
} }
canvas->setLights(fLights); canvas->setLights(fLights);
canvas->drawShadowedPicture(fPicture, nullptr, nullptr); canvas->drawShadowedPicture(fPicture, nullptr, nullptr, fShadowParams);
for (int i = 0; i < kNumSliders; i++) {
SkPaint paint;
paint.setColor(SK_ColorBLACK);
canvas->drawRect(fSliders[i].fGeometry, paint);
}
} }
SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
return new SkView::Click(this); return new SkView::Click(this);
} }
void updateFromSelectedSlider() {
SkScalar newValue = fSliders[fSelectedSlider].fGeometry.fLeft *
fSliders[fSelectedSlider].fScale +
fSliders[fSelectedSlider].fOffset;
switch (fSelectedSlider) {
case 0:
fShadowParams.fShadowRadius = newValue;
break;
case 1:
fShadowParams.fMinVariance = newValue;
break;
case 2:
fShadowParams.fBiasingConstant = newValue;
break;
default:
break;
}
}
bool onClick(Click *click) override { bool onClick(Click *click) override {
SkScalar x = click->fCurr.fX; SkScalar x = click->fCurr.fX;
SkScalar y = click->fCurr.fY; SkScalar y = click->fCurr.fY;
@ -161,6 +215,7 @@ protected:
if (click->fState == Click::State::kUp_State) { if (click->fState == Click::State::kUp_State) {
fSelectedRect = -1; fSelectedRect = -1;
fSelectedSlider = -1;
return true; return true;
} }
@ -172,6 +227,16 @@ protected:
return true; return true;
} }
if (fSelectedSlider > -1) {
fSliders[fSelectedSlider].fGeometry.offset(dx, 0);
this->updateFromSelectedSlider();
fLightsChanged = true;
this->inval(nullptr);
return true;
}
// assume last elements are highest // assume last elements are highest
for (int i = kNumTestRects - 1; i >= 0; i--) { for (int i = kNumTestRects - 1; i >= 0; i--) {
if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) { if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
@ -184,30 +249,51 @@ protected:
} }
} }
for (int i = 0; i <= kNumSliders; i++) {
if (fSliders[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
fSelectedSlider = i;
fSliders[i].fGeometry.offset(dx, 0);
this->updateFromSelectedSlider();
fLightsChanged = true;
this->inval(nullptr);
break;
}
}
return true; return true;
} }
private: private:
static constexpr int kNumTestRects = 3; static constexpr int kNumTestRects = 3;
static constexpr int kNumSliders = 3;
static const int kWidth = 400; static const int kWidth = 400;
static const int kHeight = 400; static const int kHeight = 400;
bool fClearShadowMaps;
struct { struct {
SkRect fGeometry; SkRect fGeometry;
int fDepth; int fDepth;
SkColor fColor; SkColor fColor;
} fTestRects[kNumTestRects]; } fTestRects[kNumTestRects];
int fSelectedRect; int fSelectedRect;
struct {
SkRect fGeometry;
SkScalar fOffset;
SkScalar fScale;
} fSliders[kNumSliders];
int fSelectedSlider;
bool fClearShadowMaps;
bool fMoveLight; bool fMoveLight;
sk_sp<SkPicture> fPicture;
bool fSceneChanged; bool fSceneChanged;
bool fLightsChanged; bool fLightsChanged;
sk_sp<SkPicture> fPicture;
SkShadowParams fShadowParams;
sk_sp<SkLights> fLights; sk_sp<SkLights> fLights;
typedef SampleView INHERITED; typedef SampleView INHERITED;

View File

@ -38,13 +38,13 @@
#include "SkTextFormatParams.h" #include "SkTextFormatParams.h"
#include "SkTLazy.h" #include "SkTLazy.h"
#include "SkTraceEvent.h" #include "SkTraceEvent.h"
#include <new> #include <new>
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
#include "GrContext.h" #include "GrContext.h"
#include "GrRenderTarget.h" #include "GrRenderTarget.h"
#include "SkGrPriv.h" #include "SkGrPriv.h"
#endif #endif
#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
@ -3163,17 +3163,19 @@ void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
void SkCanvas::drawShadowedPicture(const SkPicture* picture, void SkCanvas::drawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
const SkShadowParams& params) {
RETURN_ON_NULL(picture); RETURN_ON_NULL(picture);
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()"); TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
this->onDrawShadowedPicture(picture, matrix, paint); this->onDrawShadowedPicture(picture, matrix, paint, params);
} }
void SkCanvas::onDrawShadowedPicture(const SkPicture* picture, void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
const SkShadowParams& params) {
if (!paint || paint->canComputeFastBounds()) { if (!paint || paint->canComputeFastBounds()) {
SkRect bounds = picture->cullRect(); SkRect bounds = picture->cullRect();
if (paint) { if (paint) {
@ -3189,6 +3191,11 @@ void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
sk_sp<SkImage> povDepthMap;
sk_sp<SkImage> diffuseMap;
// TODO: pass the depth to the shader in vertices, or uniforms
// so we don't have to render depth and color separately
for (int i = 0; i < fLights->numLights(); ++i) { for (int i = 0; i < fLights->numLights(); ++i) {
// skip over ambient lights; they don't cast shadows // skip over ambient lights; they don't cast shadows
// lights that have shadow maps do not need updating (because lights are immutable) // lights that have shadow maps do not need updating (because lights are immutable)
@ -3217,23 +3224,36 @@ void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
// Wrap another SPFCanvas around the surface // Wrap another SPFCanvas around the surface
sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas = sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas()); sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
depthMapCanvas->setShadowParams(params);
// set the depth map canvas to have the light we're drawing. // set the depth map canvas to have the light we're drawing.
SkLights::Builder builder; SkLights::Builder builder;
builder.add(fLights->light(i)); builder.add(fLights->light(i));
sk_sp<SkLights> curLight = builder.finish(); sk_sp<SkLights> curLight = builder.finish();
depthMapCanvas->setLights(std::move(curLight)); depthMapCanvas->setLights(std::move(curLight));
depthMapCanvas->drawPicture(picture); depthMapCanvas->drawPicture(picture);
sk_sp<SkImage> depthMap = surf->makeImageSnapshot();
fLights->light(i).setShadowMap(surf->makeImageSnapshot()); if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
fLights->light(i).setShadowMap(std::move(depthMap));
} else if (params.fType == SkShadowParams::kVariance_ShadowType) {
// we blur the variance map
SkPaint blurPaint;
blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
params.fShadowRadius, nullptr));
SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
kBGRA_8888_SkColorType,
kOpaque_SkAlphaType);
sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
}
} }
sk_sp<SkImage> povDepthMap;
sk_sp<SkImage> diffuseMap;
// TODO: pass the depth to the shader in vertices, or uniforms
// so we don't have to render depth and color separately
// povDepthMap // povDepthMap
{ {
@ -3259,7 +3279,6 @@ void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
depthMapCanvas->setLights(std::move(povLight)); depthMapCanvas->setLights(std::move(povLight));
depthMapCanvas->drawPicture(picture); depthMapCanvas->drawPicture(picture);
povDepthMap = surf->makeImageSnapshot(); povDepthMap = surf->makeImageSnapshot();
} }
@ -3275,20 +3294,18 @@ void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
diffuseMap = surf->makeImageSnapshot(); diffuseMap = surf->makeImageSnapshot();
} }
SkPaint shadowPaint; SkPaint shadowPaint;
sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode, sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode); SkShader::kClamp_TileMode);
sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode, sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode); SkShader::kClamp_TileMode);
sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader), sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
std::move(diffuseShader), std::move(diffuseShader),
std::move(fLights), std::move(fLights),
diffuseMap->width(), diffuseMap->width(),
diffuseMap->height()); diffuseMap->height(),
params);
shadowPaint.setShader(shadowShader); shadowPaint.setShader(shadowShader);

View File

@ -270,17 +270,20 @@ namespace {
}; };
struct DrawShadowedPicture final : Op { struct DrawShadowedPicture final : Op {
static const auto kType = Type::DrawShadowedPicture; static const auto kType = Type::DrawShadowedPicture;
DrawShadowedPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) DrawShadowedPicture(const SkPicture* picture, const SkMatrix* matrix,
const SkPaint* paint, const SkShadowParams& params)
: picture(sk_ref_sp(picture)) { : picture(sk_ref_sp(picture)) {
if (matrix) { this->matrix = *matrix; } if (matrix) { this->matrix = *matrix; }
if (paint) { this->paint = *paint; } if (paint) { this->paint = *paint; }
this->params = params;
} }
sk_sp<const SkPicture> picture; sk_sp<const SkPicture> picture;
SkMatrix matrix = SkMatrix::I(); SkMatrix matrix = SkMatrix::I();
SkPaint paint; SkPaint paint;
SkShadowParams params;
void draw(SkCanvas* c, const SkMatrix&) { void draw(SkCanvas* c, const SkMatrix&) {
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
c->drawShadowedPicture(picture.get(), &matrix, &paint); c->drawShadowedPicture(picture.get(), &matrix, &paint, params);
#endif #endif
} }
void makeThreadsafe() { make_threadsafe(nullptr, &matrix); } void makeThreadsafe() { make_threadsafe(nullptr, &matrix); }
@ -615,9 +618,9 @@ void SkLiteDL::drawPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkPaint* paint) { const SkMatrix* matrix, const SkPaint* paint) {
this->push<DrawPicture>(0, picture, matrix, paint); this->push<DrawPicture>(0, picture, matrix, paint);
} }
void SkLiteDL::drawShadowedPicture(const SkPicture* picture, void SkLiteDL::drawShadowedPicture(const SkPicture* picture, const SkMatrix* matrix,
const SkMatrix* matrix, const SkPaint* paint) { const SkPaint* paint, const SkShadowParams& params) {
this->push<DrawShadowedPicture>(0, picture, matrix, paint); push<DrawShadowedPicture>(0, picture, matrix, paint, params);
} }
void SkLiteDL::drawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, const SkPaint* paint) { void SkLiteDL::drawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, const SkPaint* paint) {

View File

@ -48,7 +48,8 @@ public:
void drawAnnotation (const SkRect&, const char*, SkData*); void drawAnnotation (const SkRect&, const char*, SkData*);
void drawDrawable (SkDrawable*, const SkMatrix*); void drawDrawable (SkDrawable*, const SkMatrix*);
void drawPicture (const SkPicture*, const SkMatrix*, const SkPaint*); void drawPicture (const SkPicture*, const SkMatrix*, const SkPaint*);
void drawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*); void drawShadowedPicture(const SkPicture*, const SkMatrix*,
const SkPaint*, const SkShadowParams& params);
void drawText (const void*, size_t, SkScalar, SkScalar, const SkPaint&); void drawText (const void*, size_t, SkScalar, SkScalar, const SkPaint&);
void drawPosText (const void*, size_t, const SkPoint[], const SkPaint&); void drawPosText (const void*, size_t, const SkPoint[], const SkPaint&);

View File

@ -189,6 +189,7 @@ void SkLiteRecorder::didTranslateZ(SkScalar dz) {
} }
void SkLiteRecorder::onDrawShadowedPicture(const SkPicture* picture, void SkLiteRecorder::onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
fDL->drawShadowedPicture(picture, matrix, paint); const SkShadowParams& params) {
fDL->drawShadowedPicture(picture, matrix, paint, params);
} }

View File

@ -76,10 +76,12 @@ public:
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
void didTranslateZ(SkScalar) override; void didTranslateZ(SkScalar) override;
void onDrawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawShadowedPicture(const SkPicture*, const SkMatrix*,
const SkPaint*, const SkShadowParams& params) override;
#else #else
void didTranslateZ(SkScalar); void didTranslateZ(SkScalar);
void onDrawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*); void onDrawShadowedPicture(const SkPicture*, const SkMatrix*,
const SkPaint*, const SkShadowParams& params);
#endif #endif
private: private:

View File

@ -666,11 +666,13 @@ void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* ma
void SkPictureRecord::onDrawShadowedPicture(const SkPicture* picture, void SkPictureRecord::onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
const SkShadowParams& params) {
// op + picture index // op + picture index
size_t size = 2 * kUInt32Size; size_t size = 2 * kUInt32Size;
size_t initialOffset; size_t initialOffset;
// TODO: handle recording params.
if (nullptr == matrix && nullptr == paint) { if (nullptr == matrix && nullptr == paint) {
initialOffset = this->addDraw(DRAW_PICTURE, &size); initialOffset = this->addDraw(DRAW_PICTURE, &size);
this->addPicture(picture); this->addPicture(picture);

View File

@ -212,13 +212,11 @@ protected:
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*, const SkMatrix*,
const SkMatrix*, const SkPaint*, const SkShadowParams& params) override;
const SkPaint*) override;
#else #else
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*, const SkMatrix*,
const SkMatrix*, const SkPaint*, const SkShadowParams& params);
const SkPaint*);
#endif #endif
void onDrawDrawable(SkDrawable*, const SkMatrix*) override; void onDrawDrawable(SkDrawable*, const SkMatrix*) override;

View File

@ -118,7 +118,7 @@ DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode, r.paint));
DRAW(DrawPicture, drawPicture(r.picture.get(), &r.matrix, r.paint)); DRAW(DrawPicture, drawPicture(r.picture.get(), &r.matrix, r.paint));
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
DRAW(DrawShadowedPicture, drawShadowedPicture(r.picture.get(), &r.matrix, r.paint)); DRAW(DrawShadowedPicture, drawShadowedPicture(r.picture.get(), &r.matrix, r.paint, r.params));
#else #else
template <> void Draw::draw(const DrawShadowedPicture& r) { } template <> void Draw::draw(const DrawShadowedPicture& r) { }
#endif #endif

View File

@ -303,15 +303,16 @@ void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, con
} }
} }
void SkRecorder::onDrawShadowedPicture(const SkPicture* pic, void SkRecorder::onDrawShadowedPicture(const SkPicture* pic, const SkMatrix* matrix,
const SkMatrix* matrix, const SkPaint* paint, const SkShadowParams& params) {
const SkPaint* paint) {
if (fDrawPictureMode == Record_DrawPictureMode) { if (fDrawPictureMode == Record_DrawPictureMode) {
fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic); fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic);
APPEND(DrawShadowedPicture, this->copy(paint), APPEND(DrawShadowedPicture, this->copy(paint),
sk_ref_sp(pic), sk_ref_sp(pic),
matrix ? *matrix : SkMatrix::I()); matrix ? *matrix : SkMatrix::I(),
params);
} else { } else {
// TODO update pic->playback(this) to draw the shadowed pic
SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); SkASSERT(fDrawPictureMode == Playback_DrawPictureMode);
SkAutoCanvasMatrixPaint acmp(this, matrix, paint, pic->cullRect()); SkAutoCanvasMatrixPaint acmp(this, matrix, paint, pic->cullRect());
pic->playback(this); pic->playback(this);

View File

@ -141,11 +141,13 @@ public:
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*,
const SkMatrix*, const SkMatrix*,
const SkPaint*) override; const SkPaint*,
const SkShadowParams& params) override;
#else #else
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*,
const SkMatrix*, const SkMatrix*,
const SkPaint*); const SkPaint*,
const SkShadowParams& params);
#endif #endif
void onDrawAnnotation(const SkRect&, const char[], SkData*) override; void onDrawAnnotation(const SkRect&, const char[], SkData*) override;

View File

@ -5,11 +5,9 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkCanvas.h"
#include "SkLights.h"
#include "SkReadBuffer.h" #include "SkReadBuffer.h"
#include "SkShadowShader.h" #include "SkShadowShader.h"
#include "SkPoint3.h"
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
@ -26,12 +24,14 @@ public:
SkShadowShaderImpl(sk_sp<SkShader> povDepthShader, SkShadowShaderImpl(sk_sp<SkShader> povDepthShader,
sk_sp<SkShader> diffuseShader, sk_sp<SkShader> diffuseShader,
sk_sp<SkLights> lights, sk_sp<SkLights> lights,
int diffuseWidth, int diffuseHeight) int diffuseWidth, int diffuseHeight,
const SkShadowParams& params)
: fPovDepthShader(std::move(povDepthShader)) : fPovDepthShader(std::move(povDepthShader))
, fDiffuseShader(std::move(diffuseShader)) , fDiffuseShader(std::move(diffuseShader))
, fLights(std::move(lights)) , fLights(std::move(lights))
, fDiffuseWidth(diffuseWidth) , fDiffuseWidth(diffuseWidth)
, fDiffuseHeight(diffuseHeight) { } , fDiffuseHeight(diffuseHeight)
, fShadowParams(params) { }
bool isOpaque() const override; bool isOpaque() const override;
@ -80,6 +80,8 @@ private:
int fDiffuseWidth; int fDiffuseWidth;
int fDiffuseHeight; int fDiffuseHeight;
SkShadowParams fShadowParams;
friend class SkShadowShader; friend class SkShadowShader;
typedef SkShader INHERITED; typedef SkShader INHERITED;
@ -106,6 +108,7 @@ public:
sk_sp<GrFragmentProcessor> diffuse, sk_sp<GrFragmentProcessor> diffuse,
sk_sp<SkLights> lights, sk_sp<SkLights> lights,
int diffuseWidth, int diffuseHeight, int diffuseWidth, int diffuseHeight,
const SkShadowParams& params,
GrContext* context) { GrContext* context) {
// fuse all ambient lights into a single one // fuse all ambient lights into a single one
@ -137,6 +140,8 @@ public:
fWidth = diffuseWidth; fWidth = diffuseWidth;
fHeight = diffuseHeight; fHeight = diffuseHeight;
fShadowParams = params;
this->registerChildProcessor(std::move(povDepth)); this->registerChildProcessor(std::move(povDepth));
this->registerChildProcessor(std::move(diffuse)); this->registerChildProcessor(std::move(diffuse));
this->initClassID<ShadowFP>(); this->initClassID<ShadowFP>();
@ -155,6 +160,8 @@ public:
int32_t numLights = args.fFp.cast<ShadowFP>().fNumDirLights; int32_t numLights = args.fFp.cast<ShadowFP>().fNumDirLights;
SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights); SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights);
int blurAlgorithm = args.fFp.cast<ShadowFP>().fShadowParams.fType;
const char* lightDirUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; const char* lightDirUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
@ -203,6 +210,17 @@ public:
&depthMapHeightUniName[i]); &depthMapHeightUniName[i]);
} }
const char* shBiasUniName = nullptr;
const char* minVarianceUniName = nullptr;
fBiasingConstantUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kFloat_GrSLType,
kDefault_GrSLPrecision,
"shadowBias", &shBiasUniName);
fMinVarianceUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kFloat_GrSLType,
kDefault_GrSLPrecision,
"minVariance", &minVarianceUniName);
const char* widthUniName = nullptr; const char* widthUniName = nullptr;
const char* heightUniName = nullptr; const char* heightUniName = nullptr;
@ -254,17 +272,17 @@ public:
fragBuilder->codeAppendf("vec2 %s = 1 - %s;\n", fragBuilder->codeAppendf("vec2 %s = 1 - %s;\n",
scaleOffsetVec.c_str(), scaleVec.c_str()); scaleOffsetVec.c_str(), scaleVec.c_str());
fragBuilder->codeAppendf("vec2 %s = (vMatrixCoord_0_1_Stage0 + " fragBuilder->codeAppendf("vec2 %s = (vMatrixCoord_0_1_Stage0 + "
"vec2(%s.x, 0 - %s.y)) " "vec2(%s.x, 0 - %s.y)) "
" * %s + vec2(0,1) * %s;\n", " * %s + vec2(0,1) * %s;\n",
povCoord.c_str(), offset.c_str(), offset.c_str(), povCoord.c_str(), offset.c_str(), offset.c_str(),
scaleVec.c_str(), scaleOffsetVec.c_str()); scaleVec.c_str(), scaleOffsetVec.c_str());
fragBuilder->appendTextureLookup(&depthMaps[i], args.fTexSamplers[i], fragBuilder->appendTextureLookup(&depthMaps[i], args.fTexSamplers[i],
povCoord.c_str(), povCoord.c_str(),
kVec2f_GrSLType); kVec2f_GrSLType);
} }
const char* ambientColorUniName = nullptr; const char* ambientColorUniName = nullptr;
@ -274,25 +292,58 @@ public:
fragBuilder->codeAppendf("vec4 resultDiffuseColor = %s;", diffuseColor.c_str()); fragBuilder->codeAppendf("vec4 resultDiffuseColor = %s;", diffuseColor.c_str());
// Essentially,
// diffColor * (ambientLightTot + foreachDirLight(lightColor * (N . L)))
SkString totalLightColor("totalLightColor"); SkString totalLightColor("totalLightColor");
fragBuilder->codeAppendf("vec3 %s = vec3(0);", totalLightColor.c_str()); fragBuilder->codeAppendf("vec3 %s = vec3(0,0,0);", totalLightColor.c_str());
fragBuilder->codeAppendf("float lightProbability;");
fragBuilder->codeAppendf("float variance;");
fragBuilder->codeAppendf("float d;");
for (int i = 0; i < numLights; i++) { for (int i = 0; i < numLights; i++) {
fragBuilder->codeAppendf("lightProbability = 1;");
// 1/512 is less than half a pixel; imperceptible
fragBuilder->codeAppendf("if (%s.b <= %s.b + 1/512) {",
povDepth.c_str(), depthMaps[i].c_str());
if (blurAlgorithm == SkShadowParams::kVariance_ShadowType) {
fragBuilder->codeAppendf("vec2 moments = vec2(%s.b * 255, %s.g * 255 * 256 );",
depthMaps[i].c_str(), depthMaps[i].c_str());
// variance biasing lessens light bleeding
fragBuilder->codeAppendf("variance = max(moments.y - (moments.x * moments.x),"
"%s);", minVarianceUniName);
fragBuilder->codeAppendf("d = (%s.b * 255) - moments.x;", povDepth.c_str());
fragBuilder->codeAppendf("lightProbability = "
"(variance / (variance + d * d));");
SkString clamp("clamp");
clamp.appendf("%d", i);
// choosing between light artifacts or correct shape shadows
// linstep
fragBuilder->codeAppendf("float %s = clamp((lightProbability - %s) /"
"(1 - %s), 0, 1);",
clamp.c_str(), shBiasUniName, shBiasUniName);
fragBuilder->codeAppendf("lightProbability = %s;", clamp.c_str());
} else {
fragBuilder->codeAppendf("if (%s.b >= %s.b) {", fragBuilder->codeAppendf("if (%s.b >= %s.b) {",
povDepth.c_str(), depthMaps[i].c_str()); povDepth.c_str(), depthMaps[i].c_str());
// Note that dot(vec3(0,0,1), %s) == %s.z * %s fragBuilder->codeAppendf("lightProbability = 1;");
fragBuilder->codeAppendf("%s += %s.z * %s;", fragBuilder->codeAppendf("} else { lightProbability = 0; }");
}
// VSM: The curved shadows near plane edges are mostly light bleeding.
fragBuilder->codeAppendf("}");
fragBuilder->codeAppendf("%s += dot(vec3(0,0,1), %s) * %s * lightProbability;",
totalLightColor.c_str(), totalLightColor.c_str(),
lightDirUniName[i], lightDirUniName[i],
lightColorUniName[i]); lightColorUniName[i]);
fragBuilder->codeAppendf("}");
} }
fragBuilder->codeAppendf("%s += %s;", fragBuilder->codeAppendf("%s += %s;", totalLightColor.c_str(), ambientColorUniName);
totalLightColor.c_str(),
ambientColorUniName);
fragBuilder->codeAppendf("resultDiffuseColor *= vec4(%s, 1);", fragBuilder->codeAppendf("resultDiffuseColor *= vec4(%s, 1);",
totalLightColor.c_str()); totalLightColor.c_str());
@ -304,15 +355,14 @@ public:
GrProcessorKeyBuilder* b) { GrProcessorKeyBuilder* b) {
const ShadowFP& shadowFP = proc.cast<ShadowFP>(); const ShadowFP& shadowFP = proc.cast<ShadowFP>();
b->add32(shadowFP.fNumDirLights); b->add32(shadowFP.fNumDirLights);
b->add32(shadowFP.fShadowParams.fType);
} }
protected: protected:
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
const ShadowFP &shadowFP = proc.cast<ShadowFP>(); const ShadowFP &shadowFP = proc.cast<ShadowFP>();
fNumDirLights = shadowFP.numLights(); for (int i = 0; i < shadowFP.fNumDirLights; i++) {
for (int i = 0; i < fNumDirLights; i++) {
const SkVector3& lightDir = shadowFP.lightDir(i); const SkVector3& lightDir = shadowFP.lightDir(i);
if (lightDir != fLightDir[i]) { if (lightDir != fLightDir[i]) {
pdman.set3fv(fLightDirUni[i], 1, &lightDir.fX); pdman.set3fv(fLightDirUni[i], 1, &lightDir.fX);
@ -336,6 +386,18 @@ public:
} }
} }
SkScalar biasingConstant = shadowFP.shadowParams().fBiasingConstant;
if (biasingConstant != fBiasingConstant) {
pdman.set1f(fBiasingConstantUni, biasingConstant);
fBiasingConstant = biasingConstant;
}
SkScalar minVariance = shadowFP.shadowParams().fMinVariance;
if (minVariance != fMinVariance) {
pdman.set1f(fMinVarianceUni, minVariance);
fMinVariance = minVariance;
}
int width = shadowFP.width(); int width = shadowFP.width();
if (width != fWidth) { if (width != fWidth) {
pdman.set1i(fWidthUni, width); pdman.set1i(fWidthUni, width);
@ -376,10 +438,13 @@ public:
int fHeight; int fHeight;
GrGLSLProgramDataManager::UniformHandle fHeightUni; GrGLSLProgramDataManager::UniformHandle fHeightUni;
SkScalar fBiasingConstant;
GrGLSLProgramDataManager::UniformHandle fBiasingConstantUni;
SkScalar fMinVariance;
GrGLSLProgramDataManager::UniformHandle fMinVarianceUni;
SkColor3f fAmbientColor; SkColor3f fAmbientColor;
GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
int fNumDirLights;
}; };
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
@ -413,6 +478,8 @@ public:
int width() const {return fWidth; } int width() const {return fWidth; }
int height() const {return fHeight; } int height() const {return fHeight; }
const SkShadowParams& shadowParams() const {return fShadowParams; }
private: private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLShadowFP; } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLShadowFP; }
@ -454,6 +521,8 @@ private:
int fHeight; int fHeight;
int fWidth; int fWidth;
SkShadowParams fShadowParams;
SkColor3f fAmbientColor; SkColor3f fAmbientColor;
}; };
@ -469,7 +538,7 @@ sk_sp<GrFragmentProcessor> SkShadowShaderImpl::asFragmentProcessor(const AsFPArg
std::move(diffuseFP), std::move(diffuseFP),
std::move(fLights), std::move(fLights),
fDiffuseWidth, fDiffuseHeight, fDiffuseWidth, fDiffuseHeight,
fpargs.fContext); fShadowParams, fpargs.fContext);
return shadowfp; return shadowfp;
} }
@ -594,6 +663,12 @@ sk_sp<SkFlattenable> SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) {
sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf); sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf);
SkShadowParams params;
params.fMinVariance = buf.readScalar();
params.fBiasingConstant = buf.readScalar();
params.fType = (SkShadowParams::ShadowType) buf.readInt();
params.fShadowRadius = buf.readScalar();
int diffuseWidth = buf.readInt(); int diffuseWidth = buf.readInt();
int diffuseHeight = buf.readInt(); int diffuseHeight = buf.readInt();
@ -603,7 +678,8 @@ sk_sp<SkFlattenable> SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) {
return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader), return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader),
std::move(diffuseShader), std::move(diffuseShader),
std::move(lights), std::move(lights),
diffuseWidth, diffuseHeight); diffuseWidth, diffuseHeight,
params);
} }
void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const { void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const {
@ -611,6 +687,11 @@ void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const {
fLights->flatten(buf); fLights->flatten(buf);
buf.writeScalar(fShadowParams.fMinVariance);
buf.writeScalar(fShadowParams.fBiasingConstant);
buf.writeInt(fShadowParams.fType);
buf.writeScalar(fShadowParams.fShadowRadius);
buf.writeInt(fDiffuseWidth); buf.writeInt(fDiffuseWidth);
buf.writeInt(fDiffuseHeight); buf.writeInt(fDiffuseHeight);
@ -656,7 +737,8 @@ SkShader::Context* SkShadowShaderImpl::onCreateContext(const ContextRec& rec,
sk_sp<SkShader> SkShadowShader::Make(sk_sp<SkShader> povDepthShader, sk_sp<SkShader> SkShadowShader::Make(sk_sp<SkShader> povDepthShader,
sk_sp<SkShader> diffuseShader, sk_sp<SkShader> diffuseShader,
sk_sp<SkLights> lights, sk_sp<SkLights> lights,
int diffuseWidth, int diffuseHeight) { int diffuseWidth, int diffuseHeight,
const SkShadowParams& params) {
if (!povDepthShader || !diffuseShader) { if (!povDepthShader || !diffuseShader) {
// TODO: Use paint's color in absence of a diffuseShader // TODO: Use paint's color in absence of a diffuseShader
// TODO: Use a default implementation of normalSource instead // TODO: Use a default implementation of normalSource instead
@ -666,7 +748,8 @@ sk_sp<SkShader> SkShadowShader::Make(sk_sp<SkShader> povDepthShader,
return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader), return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader),
std::move(diffuseShader), std::move(diffuseShader),
std::move(lights), std::move(lights),
diffuseWidth, diffuseHeight); diffuseWidth, diffuseHeight,
params);
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -23,7 +23,8 @@ public:
static sk_sp<SkShader> Make(sk_sp<SkShader> povDepthShader, static sk_sp<SkShader> Make(sk_sp<SkShader> povDepthShader,
sk_sp<SkShader> diffuseShader, sk_sp<SkShader> diffuseShader,
sk_sp<SkLights> lights, sk_sp<SkLights> lights,
int diffuseWidth, int diffuseHeight); int diffuseWidth, int diffuseHeight,
const SkShadowParams& params);
// The shadow shader supports any number of ambient lights, but only // The shadow shader supports any number of ambient lights, but only
// 4 non-ambient lights (currently just refers to directional lights). // 4 non-ambient lights (currently just refers to directional lights).

View File

@ -11,7 +11,12 @@
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
SkShadowPaintFilterCanvas::SkShadowPaintFilterCanvas(SkCanvas *canvas) SkShadowPaintFilterCanvas::SkShadowPaintFilterCanvas(SkCanvas *canvas)
: SkPaintFilterCanvas(canvas) { } : SkPaintFilterCanvas(canvas) {
fShadowParams.fShadowRadius = 0.0f;
fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
fShadowParams.fBiasingConstant = 0.0f;
fShadowParams.fMinVariance = 0.0f;
}
// TODO use a shader instead // TODO use a shader instead
bool SkShadowPaintFilterCanvas::onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const { bool SkShadowPaintFilterCanvas::onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const {
@ -24,6 +29,17 @@ bool SkShadowPaintFilterCanvas::onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Ty
SkColor color = 0xFF000000; // init color to opaque black SkColor color = 0xFF000000; // init color to opaque black
color |= z; // Put the index into the blue component color |= z; // Put the index into the blue component
if (fShadowParams.fType == SkShadowParams::kVariance_ShadowType) {
int z2 = z * z;
if (z2 > 255 * 256) {
color |= 0xff00;
} else {
// Let's only store the more significant bits of z2 to save space.
// In practice, this should barely impact shadow blur quality.
color |= z2 & 0x0000ff00;
}
}
newPaint.setColor(color); newPaint.setColor(color);
*paint->writable() = newPaint; *paint->writable() = newPaint;
@ -42,6 +58,9 @@ SkISize SkShadowPaintFilterCanvas::ComputeDepthMapSize(const SkLights::Light& li
return SkISize::Make(dMapWidth, dMapHeight); return SkISize::Make(dMapWidth, dMapHeight);
} }
void SkShadowPaintFilterCanvas::setShadowParams(const SkShadowParams &params) {
fShadowParams = params;
}
void SkShadowPaintFilterCanvas::onDrawPicture(const SkPicture *picture, const SkMatrix *matrix, void SkShadowPaintFilterCanvas::onDrawPicture(const SkPicture *picture, const SkMatrix *matrix,
const SkPaint *paint) { const SkPaint *paint) {

View File

@ -35,6 +35,7 @@ public:
static SkISize ComputeDepthMapSize(const SkLights::Light& light, int maxDepth, static SkISize ComputeDepthMapSize(const SkLights::Light& light, int maxDepth,
int width, int height); int width, int height);
void setShadowParams(const SkShadowParams &params);
protected: protected:
void onDrawPicture(const SkPicture *picture, const SkMatrix *matrix, void onDrawPicture(const SkPicture *picture, const SkMatrix *matrix,
const SkPaint *paint) override; const SkPaint *paint) override;
@ -107,6 +108,7 @@ protected:
void onDrawTextBlob(const SkTextBlob *blob, SkScalar x, void onDrawTextBlob(const SkTextBlob *blob, SkScalar x,
SkScalar y, const SkPaint &paint) override; SkScalar y, const SkPaint &paint) override;
private: private:
SkShadowParams fShadowParams;
typedef SkPaintFilterCanvas INHERITED; typedef SkPaintFilterCanvas INHERITED;
}; };

View File

@ -60,9 +60,10 @@ protected:
void onDrawShadowedPicture(const SkPicture* picture, void onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
const SkShadowParams& params) {
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
this->SkCanvas::onDrawShadowedPicture(picture, matrix, paint); this->SkCanvas::onDrawShadowedPicture(picture, matrix, paint, params);
#else #else
this->SkCanvas::onDrawPicture(picture, matrix, paint); this->SkCanvas::onDrawPicture(picture, matrix, paint);
#endif #endif
@ -620,8 +621,9 @@ void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
void SkDebugCanvas::onDrawShadowedPicture(const SkPicture* picture, void SkDebugCanvas::onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) { const SkPaint* paint,
this->addDrawCommand(new SkBeginDrawShadowedPictureCommand(picture, matrix, paint)); const SkShadowParams& params) {
this->addDrawCommand(new SkBeginDrawShadowedPictureCommand(picture, matrix, paint, params));
SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
picture->playback(this); picture->playback(this);
this->addDrawCommand(new SkEndDrawShadowedPictureCommand(SkToBool(matrix) || SkToBool(paint))); this->addDrawCommand(new SkEndDrawShadowedPictureCommand(SkToBool(matrix) || SkToBool(paint)));

View File

@ -258,11 +258,13 @@ protected:
#ifdef SK_EXPERIMENTAL_SHADOWING #ifdef SK_EXPERIMENTAL_SHADOWING
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*,
const SkMatrix*, const SkMatrix*,
const SkPaint*) override; const SkPaint*,
const SkShadowParams& params) override;
#else #else
void onDrawShadowedPicture(const SkPicture*, void onDrawShadowedPicture(const SkPicture*,
const SkMatrix*, const SkMatrix*,
const SkPaint*); const SkPaint*,
const SkShadowParams& params);
#endif #endif
void markActiveCommands(int index); void markActiveCommands(int index);

View File

@ -2449,14 +2449,35 @@ void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const {
SkBeginDrawShadowedPictureCommand::SkBeginDrawShadowedPictureCommand(const SkPicture* picture, SkBeginDrawShadowedPictureCommand::SkBeginDrawShadowedPictureCommand(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint) const SkPaint* paint,
const SkShadowParams& params)
: INHERITED(kBeginDrawShadowedPicture_OpType) : INHERITED(kBeginDrawShadowedPicture_OpType)
#ifdef SK_EXPERIMENTAL_SHADOWING
, fPicture(SkRef(picture))
, fShadowParams(params) {
#else
, fPicture(SkRef(picture)) { , fPicture(SkRef(picture)) {
#endif
SkString* str = new SkString; SkString* str = new SkString;
str->appendf("SkPicture: L: %f T: %f R: %f B: %f", str->appendf("SkPicture: L: %f T: %f R: %f B: %f\n",
picture->cullRect().fLeft, picture->cullRect().fTop, picture->cullRect().fLeft, picture->cullRect().fTop,
picture->cullRect().fRight, picture->cullRect().fBottom); picture->cullRect().fRight, picture->cullRect().fBottom);
str->appendf("SkShadowParams: bias:%f, minVariance:%f, shRadius:%f, shType:",
params.fBiasingConstant,
params.fMinVariance,
params.fShadowRadius);
SkASSERT(SkShadowParams::kShadowTypeCount == 2);
switch (params.fType) {
case SkShadowParams::ShadowType::kNoBlur_ShadowType:
str->append("kNoBlur_ShadowType\n");
break;
case SkShadowParams::ShadowType::kVariance_ShadowType:
str->append("kVariance_ShadowType\n");
break;
}
fInfo.push(str); fInfo.push(str);
if (matrix) { if (matrix) {
@ -2492,9 +2513,11 @@ bool SkBeginDrawShadowedPictureCommand::render(SkCanvas* canvas) const {
canvas->save(); canvas->save();
xlate_and_scale_to_bounds(canvas, fPicture->cullRect()); xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
#ifdef SK_EXPERIMENTAL_SHADOWING
canvas->drawPicture(fPicture.get()); canvas->drawShadowedPicture(fPicture.get(), fMatrix.get(), fPaint.get(), fShadowParams);
#else
canvas->drawPicture(fPicture.get(), fMatrix.get(), fPaint.get());
#endif
canvas->restore(); canvas->restore();
return true; return true;

View File

@ -480,7 +480,8 @@ class SkBeginDrawShadowedPictureCommand : public SkDrawCommand {
public: public:
SkBeginDrawShadowedPictureCommand(const SkPicture* picture, SkBeginDrawShadowedPictureCommand(const SkPicture* picture,
const SkMatrix* matrix, const SkMatrix* matrix,
const SkPaint* paint); const SkPaint* paint,
const SkShadowParams& params);
void execute(SkCanvas* canvas) const override; void execute(SkCanvas* canvas) const override;
bool render(SkCanvas* canvas) const override; bool render(SkCanvas* canvas) const override;
@ -489,6 +490,9 @@ private:
SkAutoTUnref<const SkPicture> fPicture; SkAutoTUnref<const SkPicture> fPicture;
SkTLazy<SkMatrix> fMatrix; SkTLazy<SkMatrix> fMatrix;
SkTLazy<SkPaint> fPaint; SkTLazy<SkPaint> fPaint;
#ifdef SK_EXPERIMENTAL_SHADOWING
SkShadowParams fShadowParams;
#endif
typedef SkDrawCommand INHERITED; typedef SkDrawCommand INHERITED;
}; };
@ -796,3 +800,4 @@ private:
typedef SkDrawCommand INHERITED; typedef SkDrawCommand INHERITED;
}; };
#endif #endif