aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/shadowmaps.cpp103
-rw-r--r--samplecode/SampleShadowing.cpp142
-rw-r--r--src/core/SkCanvas.cpp122
3 files changed, 149 insertions, 218 deletions
diff --git a/gm/shadowmaps.cpp b/gm/shadowmaps.cpp
index 1ae95fb68f..b343d9b142 100644
--- a/gm/shadowmaps.cpp
+++ b/gm/shadowmaps.cpp
@@ -15,21 +15,6 @@
#ifdef SK_EXPERIMENTAL_SHADOWING
-static sk_sp<SkShader> make_shadow_shader(sk_sp<SkImage> povDepth,
- sk_sp<SkImage> diffuse,
- sk_sp<SkLights> lights) {
-
- sk_sp<SkShader> povDepthShader = povDepth->makeShader(SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
-
- sk_sp<SkShader> diffuseShader = diffuse->makeShader(SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
-
- return SkShadowShader::Make(std::move(povDepthShader),
- std::move(diffuseShader),
- std::move(lights),
- diffuse->width(), diffuse->height());
-}
static sk_sp<SkPicture> make_test_picture(int width, int height) {
SkPictureRecorder recorder;
@@ -109,96 +94,12 @@ protected:
// This picture stores the picture of the scene.
// It's used to generate the depth maps.
sk_sp<SkPicture> pic(make_test_picture(kWidth, kHeight));
-
- for (int i = 0; i < fLights->numLights(); ++i) {
- // skip over ambient lights; they don't cast shadows
- if (SkLights::Light::kAmbient_LightType == fLights->light(i).type()) {
- continue;
- }
- // TODO: compute the correct size of the depth map from the light properties
- // TODO: maybe add a kDepth_8_SkColorType
-
- // TODO: find actual max depth of picture
- SkISize shMapSize = SkShadowPaintFilterCanvas::
- ComputeDepthMapSize(fLights->light(i), 255, kWidth, kHeight);
-
- SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- // Create a new surface (that matches the backend of canvas)
- // for each shadow map
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
-
- // Wrap another SPFCanvas around the surface
- sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
- sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
-
- // set the depth map canvas to have the light we're drawing.
- SkLights::Builder builder;
- builder.add(fLights->light(i));
- sk_sp<SkLights> curLight = builder.finish();
-
- depthMapCanvas->setLights(std::move(curLight));
- depthMapCanvas->drawPicture(pic);
-
- fLights->light(i).setShadowMap(surf->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
- {
- SkLights::Builder builder;
- builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
- SkVector3::Make(0.0f, 0.0f, 1.0f)));
- sk_sp<SkLights> povLight = builder.finish();
-
- SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- // Create a new surface (that matches the backend of canvas)
- // to create the povDepthMap
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
-
- // Wrap another SPFCanvas around the surface
- sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
- sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
-
- // set the depth map canvas to have the light as the user's POV
- depthMapCanvas->setLights(std::move(povLight));
-
- depthMapCanvas->drawPicture(pic);
-
- povDepthMap = surf->makeImageSnapshot();
- }
-
- // diffuseMap
- {
- SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
- surf->getCanvas()->drawPicture(pic);
-
- diffuseMap = surf->makeImageSnapshot();
- }
-
- SkPaint paint;
- paint.setShader(make_shadow_shader(std::move(povDepthMap), std::move(diffuseMap), fLights));
-
- canvas->drawRect(SkRect::MakeIWH(kWidth, kHeight), paint);
+ canvas->setLights(fLights);
+ canvas->drawShadowedPicture(pic, nullptr, nullptr);
}
private:
sk_sp<SkLights> fLights;
-
typedef GM INHERITED;
};
diff --git a/samplecode/SampleShadowing.cpp b/samplecode/SampleShadowing.cpp
index 3907db30cc..7b434bca80 100644
--- a/samplecode/SampleShadowing.cpp
+++ b/samplecode/SampleShadowing.cpp
@@ -13,22 +13,6 @@
#ifdef SK_EXPERIMENTAL_SHADOWING
-static sk_sp<SkShader> make_shadow_shader(sk_sp<SkImage> povDepth,
- sk_sp<SkImage> diffuse,
- sk_sp<SkLights> lights) {
-
- sk_sp<SkShader> povDepthShader = povDepth->makeShader(SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
-
- sk_sp<SkShader> diffuseShader = diffuse->makeShader(SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
-
- return SkShadowShader::Make(std::move(povDepthShader),
- std::move(diffuseShader),
- std::move(lights),
- diffuse->width(), diffuse->height());
-}
-
class ShadowingView : public SampleView {
public:
ShadowingView() {
@@ -36,9 +20,9 @@ public:
this->setBGColor(0xFFCCCCCC);
SkLights::Builder builder;
builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.3f, 0.4f),
- SkVector3::Make(0.27f, 0.07f, 1.0f)));
+ SkVector3::Make(0.2f, 0.05f, 1.0f)));
builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.3f, 0.2f),
- SkVector3::Make(0.03f, 0.27f, 1.0f)));
+ SkVector3::Make(0.05f, 0.2f, 1.0f)));
builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
fLights = builder.finish();
@@ -59,6 +43,8 @@ public:
fSelectedRect = -1;
fMoveLight = false;
+
+ fClearShadowMaps = false;
}
protected:
@@ -74,6 +60,13 @@ protected:
case 'L':
fMoveLight = !fMoveLight;
break;
+ case 'd':
+ // Raster generated shadow maps have their origin in the UL corner
+ // GPU shadow maps can have an arbitrary origin.
+ // We override the 'd' keypress so that when the device is cycled,
+ // the shadow maps will be re-generated according to the new backend.
+ fClearShadowMaps = true;
+ break;
default:
break;
}
@@ -111,103 +104,22 @@ protected:
return recorder.finishRecordingAsPicture();
}
- void updateDepthMaps(SkCanvas *canvas) {
- for (int i = 0; i < fLights->numLights(); ++i) {
- // skip over ambient lights; they don't cast shadows
- if (SkLights::Light::kAmbient_LightType == fLights->light(i).type()) {
- continue;
- }
-
- // TODO: maybe add a kDepth_8_SkColorType when vertices have depth
- // assume max depth is 255.
- // TODO: find actual max depth of picture
- SkISize shMapSize = SkShadowPaintFilterCanvas::
- ComputeDepthMapSize(fLights->light(i), 255, kWidth, kHeight);
-
- SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- // Create a new surface (that matches the backend of canvas)
- // for each shadow map
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
-
- // Wrap another SPFCanvas around the surface
- sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
- sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
-
- // set the depth map canvas to have the light we're drawing.
- SkLights::Builder builder;
- builder.add(fLights->light(i));
- sk_sp<SkLights> curLight = builder.finish();
-
- depthMapCanvas->setLights(std::move(curLight));
- depthMapCanvas->drawPicture(fPicture);
-
- fLights->light(i).setShadowMap(surf->makeImageSnapshot());
- }
- }
-
- void updatePovDepthMap(SkCanvas* canvas) {
- // TODO: pass the depth to the shader in vertices, or uniforms
- // so we don't have to render depth and color separately
-
- SkLights::Builder builder;
- builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
- SkVector3::Make(0.0f, 0.0f, 1.0f)));
- sk_sp<SkLights> povLight = builder.finish();
-
- SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- // Create a new surface (that matches the backend of canvas)
- // to create the povDepthMap
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
-
- // Wrap another SPFCanvas around the surface
- sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
- sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
-
- // set the depth map canvas to have the light as the user's POV
- depthMapCanvas->setLights(std::move(povLight));
-
- depthMapCanvas->drawPicture(fPicture);
-
- fPovDepthMap = surf->makeImageSnapshot();
- }
-
- void updateDiffuseMap(SkCanvas* canvas) {
- SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
- kBGRA_8888_SkColorType,
- kOpaque_SkAlphaType);
-
- sk_sp<SkSurface> surf(canvas->makeSurface(info));
- surf->getCanvas()->drawPicture(fPicture);
-
- fDiffuseMap = surf->makeImageSnapshot();
- }
-
void onDrawContent(SkCanvas *canvas) override {
- if (fSceneChanged || !fPovDepthMap) {
+ if (fSceneChanged) {
fPicture = this->makeTestPicture(kWidth, kHeight);
- this->updateDepthMaps(canvas);
- this->updatePovDepthMap(canvas);
- this->updateDiffuseMap(canvas);
}
- if (fLightsChanged) {
- this->updateDepthMaps(canvas);
- }
+ if (fSceneChanged || fLightsChanged || fClearShadowMaps) {
+ for (int i = 0; i < fLights->numLights(); i++) {
+ fLights->light(i).setShadowMap(nullptr);
+ }
+ fSceneChanged = false;
+ fLightsChanged = false;
+ fClearShadowMaps = false;
- if (fSceneChanged || fLightsChanged || !fShadowShader) {
- fShadowShader = make_shadow_shader(fPovDepthMap, fDiffuseMap, fLights);
+ canvas->setLights(fLights);
+ canvas->drawShadowedPicture(fPicture, nullptr, nullptr);
}
-
- SkPaint paint;
- paint.setShader(fShadowShader);
-
- canvas->drawRect(SkRect::MakeIWH(kWidth, kHeight), paint);
}
SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
@@ -228,12 +140,12 @@ protected:
SkLights::Builder builder;
builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.3f, 0.4f),
- SkVector3::Make(0.12f + (200.0f - x) * recipX,
- -0.08f + (200.0f - y) * recipY,
+ SkVector3::Make(0.2f + (200.0f - x) * recipX,
+ 0.05f + (200.0f - y) * recipY,
1.0f)));
builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.3f, 0.2f),
- SkVector3::Make(-0.12f + (200.0f - x) * recipX,
- 0.12f + (200.0f - y) * recipY,
+ SkVector3::Make(0.05f + (200.0f - x) * recipX,
+ 0.2f + (200.0f - y) * recipY,
1.0f)));
builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
fLights = builder.finish();
@@ -277,6 +189,7 @@ private:
static const int kWidth = 400;
static const int kHeight = 400;
+ bool fClearShadowMaps;
struct {
SkRect fGeometry;
@@ -287,10 +200,7 @@ private:
int fSelectedRect;
bool fMoveLight;
- sk_sp<SkImage> fPovDepthMap;
- sk_sp<SkImage> fDiffuseMap;
sk_sp<SkPicture> fPicture;
- sk_sp<SkShader> fShadowShader;
bool fSceneChanged;
bool fLightsChanged;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index d42c726c6c..24d9506bd7 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -28,6 +28,8 @@
#include "SkRasterClip.h"
#include "SkReadPixelsRec.h"
#include "SkRRect.h"
+#include "SkShadowPaintFilterCanvas.h"
+#include "SkShadowShader.h"
#include "SkSmallAllocator.h"
#include "SkSpecialImage.h"
#include "SkSurface_Base.h"
@@ -3069,7 +3071,125 @@ void SkCanvas::drawShadowedPicture(const SkPicture* picture,
void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
const SkMatrix* matrix,
const SkPaint* paint) {
- this->onDrawPicture(picture, matrix, paint);
+ if (!paint || paint->canComputeFastBounds()) {
+ SkRect bounds = picture->cullRect();
+ if (paint) {
+ paint->computeFastBounds(bounds, &bounds);
+ }
+ if (matrix) {
+ matrix->mapRect(&bounds);
+ }
+ if (this->quickReject(bounds)) {
+ return;
+ }
+ }
+
+ SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
+
+ for (int i = 0; i < fLights->numLights(); ++i) {
+ // skip over ambient lights; they don't cast shadows
+ // lights that have shadow maps do not need updating (because lights are immutable)
+
+ if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() ||
+ fLights->light(i).getShadowMap() != nullptr) {
+ continue;
+ }
+
+ // TODO: compute the correct size of the depth map from the light properties
+ // TODO: maybe add a kDepth_8_SkColorType
+ // TODO: find actual max depth of picture
+ SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
+ fLights->light(i), 255,
+ picture->cullRect().width(),
+ picture->cullRect().height());
+
+ SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
+ kBGRA_8888_SkColorType,
+ kOpaque_SkAlphaType);
+
+ // Create a new surface (that matches the backend of canvas)
+ // for each shadow map
+ sk_sp<SkSurface> surf(this->makeSurface(info));
+
+ // Wrap another SPFCanvas around the surface
+ sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
+ sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
+
+ // set the depth map canvas to have the light we're drawing.
+ SkLights::Builder builder;
+ builder.add(fLights->light(i));
+ sk_sp<SkLights> curLight = builder.finish();
+
+ depthMapCanvas->setLights(std::move(curLight));
+ depthMapCanvas->drawPicture(picture);
+
+ fLights->light(i).setShadowMap(surf->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
+ {
+ SkLights::Builder builder;
+ builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
+ SkVector3::Make(0.0f, 0.0f, 1.0f)));
+ sk_sp<SkLights> povLight = builder.finish();
+
+ SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
+ picture->cullRect().height(),
+ kBGRA_8888_SkColorType,
+ kOpaque_SkAlphaType);
+
+ // Create a new surface (that matches the backend of canvas)
+ // to create the povDepthMap
+ sk_sp<SkSurface> surf(this->makeSurface(info));
+
+ // Wrap another SPFCanvas around the surface
+ sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
+ sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
+
+ // set the depth map canvas to have the light as the user's POV
+ depthMapCanvas->setLights(std::move(povLight));
+
+ depthMapCanvas->drawPicture(picture);
+
+ povDepthMap = surf->makeImageSnapshot();
+ }
+
+ // diffuseMap
+ {
+ SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
+ picture->cullRect().height(),
+ kBGRA_8888_SkColorType,
+ kOpaque_SkAlphaType);
+
+ sk_sp<SkSurface> surf(this->makeSurface(info));
+ surf->getCanvas()->drawPicture(picture);
+
+ diffuseMap = surf->makeImageSnapshot();
+ }
+
+ SkPaint shadowPaint;
+
+ sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+
+ sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+
+ sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
+ std::move(diffuseShader),
+ std::move(fLights),
+ diffuseMap->width(),
+ diffuseMap->height());
+
+ shadowPaint.setShader(shadowShader);
+
+ this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
}
#endif