1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkLights.h"
9 #include "SkPoint3.h"
10 #include "SkRadialShadowMapShader.h"
11
12 ////////////////////////////////////////////////////////////////////////////
13 #ifdef SK_EXPERIMENTAL_SHADOWING
14
15
16 /** \class SkRadialShadowMapShaderImpl
17 This subclass of shader applies shadowing radially around a light
18 */
19 class SkRadialShadowMapShaderImpl : public SkShader {
20 public:
21 /** Create a new shadowing shader that shadows radially around a light
22 */
SkRadialShadowMapShaderImpl(sk_sp<SkShader> occluderShader,sk_sp<SkLights> lights,int diffuseWidth,int diffuseHeight)23 SkRadialShadowMapShaderImpl(sk_sp<SkShader> occluderShader,
24 sk_sp<SkLights> lights,
25 int diffuseWidth, int diffuseHeight)
26 : fOccluderShader(std::move(occluderShader))
27 , fLight(std::move(lights))
28 , fWidth(diffuseWidth)
29 , fHeight(diffuseHeight) { }
30
31 bool isOpaque() const override;
32
33 #if SK_SUPPORT_GPU
34 sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
35 #endif
36
37 class ShadowMapRadialShaderContext : public SkShader::Context {
38 public:
39 // The context takes ownership of the states. It will call their destructors
40 // but will NOT free the memory.
41 ShadowMapRadialShaderContext(const SkRadialShadowMapShaderImpl&, const ContextRec&,
42 SkShader::Context* occluderContext,
43 void* heapAllocated);
44
45 ~ShadowMapRadialShaderContext() override;
46
47 void shadeSpan(int x, int y, SkPMColor[], int count) override;
48
getFlags() const49 uint32_t getFlags() const override { return fFlags; }
50
51 private:
52 SkShader::Context* fOccluderContext;
53 uint32_t fFlags;
54
55 void* fHeapAllocated;
56
57 typedef SkShader::Context INHERITED;
58 };
59
60 SK_TO_STRING_OVERRIDE()
61 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRadialShadowMapShaderImpl)
62
63 protected:
64 void flatten(SkWriteBuffer&) const override;
65 size_t onContextSize(const ContextRec&) const override;
66 Context* onCreateContext(const ContextRec&, void*) const override;
67
68 private:
69 sk_sp<SkShader> fOccluderShader;
70 sk_sp<SkLights> fLight;
71
72 int fWidth;
73 int fHeight;
74
75 friend class SkRadialShadowMapShader;
76
77 typedef SkShader INHERITED;
78 };
79
80 ////////////////////////////////////////////////////////////////////////////
81
82 #if SK_SUPPORT_GPU
83
84 #include "GrContext.h"
85 #include "GrCoordTransform.h"
86 #include "GrFragmentProcessor.h"
87 #include "glsl/GrGLSLFragmentProcessor.h"
88 #include "glsl/GrGLSLFragmentShaderBuilder.h"
89 #include "SkGr.h"
90 #include "SkImage_Base.h"
91 #include "GrInvariantOutput.h"
92 #include "SkSpecialImage.h"
93
94 class RadialShadowMapFP : public GrFragmentProcessor {
95 public:
RadialShadowMapFP(sk_sp<GrFragmentProcessor> occluder,sk_sp<SkLights> light,int diffuseWidth,int diffuseHeight,GrContext * context)96 RadialShadowMapFP(sk_sp<GrFragmentProcessor> occluder,
97 sk_sp<SkLights> light,
98 int diffuseWidth, int diffuseHeight,
99 GrContext* context) {
100 fLightPos = light->light(0).pos();
101
102 fWidth = diffuseWidth;
103 fHeight = diffuseHeight;
104
105 this->registerChildProcessor(std::move(occluder));
106 this->initClassID<RadialShadowMapFP>();
107 }
108
109 class GLSLRadialShadowMapFP : public GrGLSLFragmentProcessor {
110 public:
GLSLRadialShadowMapFP()111 GLSLRadialShadowMapFP() { }
112
emitCode(EmitArgs & args)113 void emitCode(EmitArgs& args) override {
114
115 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
116 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
117
118 const char* lightPosUniName = nullptr;
119
120 fLightPosUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
121 kVec3f_GrSLType,
122 kDefault_GrSLPrecision,
123 "lightPos",
124 &lightPosUniName);
125
126 const char* widthUniName = nullptr;
127 const char* heightUniName = nullptr;
128
129 fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
130 kInt_GrSLType,
131 kDefault_GrSLPrecision,
132 "width", &widthUniName);
133 fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
134 kInt_GrSLType,
135 kDefault_GrSLPrecision,
136 "height", &heightUniName);
137
138
139 SkString occluder("occluder");
140 this->emitChild(0, nullptr, &occluder, args);
141
142 // Modify the input texture coordinates to index into our 1D output
143 fragBuilder->codeAppend("float distHere;");
144
145 // we use a max shadow distance of 2 times the max of width/height
146 fragBuilder->codeAppend("float closestDistHere = 2;");
147 fragBuilder->codeAppend("vec2 coords = vMatrixCoord_0_0_Stage0;");
148 fragBuilder->codeAppend("coords.y = 0;");
149 fragBuilder->codeAppend("vec2 destCoords = vec2(0,0);");
150 fragBuilder->codeAppendf("float step = 1.0 / %s;", heightUniName);
151
152 // assume that we are at 0, 0 light pos
153 // TODO use correct light positions
154
155 // this goes through each depth value in the final output buffer,
156 // basically raycasting outwards, and finding the first collision.
157 // we also increment coords.y to 2 instead 1 so our shadows stretch the whole screen.
158 fragBuilder->codeAppendf("for (coords.y = 0; coords.y <= 2; coords.y += step) {");
159
160 fragBuilder->codeAppend("float theta = (coords.x * 2.0 - 1.0) * 3.1415;");
161 fragBuilder->codeAppend("float r = coords.y;");
162 fragBuilder->codeAppend("destCoords = "
163 "vec2(r * cos(theta), - r * sin(theta)) /2.0 + 0.5;");
164 fragBuilder->codeAppendf("vec2 lightOffset = (vec2(%s)/vec2(%s,%s) - 0.5)"
165 "* vec2(1.0, 1.0);",
166 lightPosUniName, widthUniName, heightUniName);
167
168 fragBuilder->codeAppend("distHere = texture(uTextureSampler0_Stage1,"
169 "destCoords + lightOffset).b;");
170 fragBuilder->codeAppend("if (distHere > 0.0) {"
171 "closestDistHere = coords.y;"
172 "break;}");
173 fragBuilder->codeAppend("}");
174
175 fragBuilder->codeAppendf("%s = vec4(vec3(closestDistHere / 2.0),1);", args.fOutputColor);
176 }
177
GenKey(const GrProcessor & proc,const GrShaderCaps &,GrProcessorKeyBuilder * b)178 static void GenKey(const GrProcessor& proc, const GrShaderCaps&,
179 GrProcessorKeyBuilder* b) {
180 b->add32(0); // nothing to add here
181 }
182
183 protected:
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)184 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
185 const RadialShadowMapFP &radialShadowMapFP = proc.cast<RadialShadowMapFP>();
186
187 const SkVector3& lightPos = radialShadowMapFP.lightPos();
188 if (lightPos != fLightPos) {
189 pdman.set3fv(fLightPosUni, 1, &lightPos.fX);
190 fLightPos = lightPos;
191 }
192
193 int width = radialShadowMapFP.width();
194 if (width != fWidth) {
195 pdman.set1i(fWidthUni, width);
196 fWidth = width;
197 }
198 int height = radialShadowMapFP.height();
199 if (height != fHeight) {
200 pdman.set1i(fHeightUni, height);
201 fHeight = height;
202 }
203 }
204
205 private:
206 SkVector3 fLightPos;
207 GrGLSLProgramDataManager::UniformHandle fLightPosUni;
208
209 int fWidth;
210 GrGLSLProgramDataManager::UniformHandle fWidthUni;
211 int fHeight;
212 GrGLSLProgramDataManager::UniformHandle fHeightUni;
213 };
214
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const215 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
216 GLSLRadialShadowMapFP::GenKey(*this, caps, b);
217 }
218
name() const219 const char* name() const override { return "RadialShadowMapFP"; }
220
lightPos() const221 const SkVector3& lightPos() const {
222 return fLightPos;
223 }
224
width() const225 int width() const { return fWidth; }
height() const226 int height() const { return fHeight; }
227
228 private:
onCreateGLSLInstance() const229 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
230 return new GLSLRadialShadowMapFP;
231 }
232
onIsEqual(const GrFragmentProcessor & proc) const233 bool onIsEqual(const GrFragmentProcessor& proc) const override {
234 const RadialShadowMapFP& radialShadowMapFP = proc.cast<RadialShadowMapFP>();
235
236 if (fWidth != radialShadowMapFP.fWidth || fHeight != radialShadowMapFP.fHeight) {
237 return false;
238 }
239
240 if (fLightPos != radialShadowMapFP.fLightPos) {
241 return false;
242 }
243
244 return true;
245 }
246
247 SkVector3 fLightPos;
248
249 int fHeight;
250 int fWidth;
251 };
252
253 ////////////////////////////////////////////////////////////////////////////
254
asFragmentProcessor(const AsFPArgs & fpargs) const255 sk_sp<GrFragmentProcessor> SkRadialShadowMapShaderImpl::asFragmentProcessor
256 (const AsFPArgs& fpargs) const {
257
258 sk_sp<GrFragmentProcessor> occluderFP = fOccluderShader->asFragmentProcessor(fpargs);
259
260 sk_sp<GrFragmentProcessor> shadowFP = sk_make_sp<RadialShadowMapFP>(std::move(occluderFP),
261 fLight, fWidth, fHeight,
262 fpargs.fContext);
263 return shadowFP;
264 }
265
266 #endif
267
268 ////////////////////////////////////////////////////////////////////////////
269
isOpaque() const270 bool SkRadialShadowMapShaderImpl::isOpaque() const {
271 return fOccluderShader->isOpaque();
272 }
273
ShadowMapRadialShaderContext(const SkRadialShadowMapShaderImpl & shader,const ContextRec & rec,SkShader::Context * occluderContext,void * heapAllocated)274 SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::ShadowMapRadialShaderContext(
275 const SkRadialShadowMapShaderImpl& shader, const ContextRec& rec,
276 SkShader::Context* occluderContext,
277 void* heapAllocated)
278 : INHERITED(shader, rec)
279 , fOccluderContext(occluderContext)
280 , fHeapAllocated(heapAllocated) {
281 bool isOpaque = shader.isOpaque();
282
283 // update fFlags
284 uint32_t flags = 0;
285 if (isOpaque && (255 == this->getPaintAlpha())) {
286 flags |= kOpaqueAlpha_Flag;
287 }
288
289 fFlags = flags;
290 }
291
~ShadowMapRadialShaderContext()292 SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::~ShadowMapRadialShaderContext() {
293 // The dependencies have been created outside of the context on memory that was allocated by
294 // the onCreateContext() method. Call the destructors and free the memory.
295 fOccluderContext->~Context();
296
297 sk_free(fHeapAllocated);
298 }
299
convert(SkColor3f color,U8CPU a)300 static inline SkPMColor convert(SkColor3f color, U8CPU a) {
301 if (color.fX <= 0.0f) {
302 color.fX = 0.0f;
303 } else if (color.fX >= 255.0f) {
304 color.fX = 255.0f;
305 }
306
307 if (color.fY <= 0.0f) {
308 color.fY = 0.0f;
309 } else if (color.fY >= 255.0f) {
310 color.fY = 255.0f;
311 }
312
313 if (color.fZ <= 0.0f) {
314 color.fZ = 0.0f;
315 } else if (color.fZ >= 255.0f) {
316 color.fZ = 255.0f;
317 }
318
319 return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ);
320 }
321
322 // larger is better (fewer times we have to loop), but we shouldn't
323 // take up too much stack-space (each one here costs 16 bytes)
324 #define BUFFER_MAX 16
shadeSpan(int x,int y,SkPMColor result[],int count)325 void SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::shadeSpan
326 (int x, int y, SkPMColor result[], int count) {
327 do {
328 int n = SkTMin(count, BUFFER_MAX);
329
330 // just fill with white for now
331 SkPMColor accum = convert(SkColor3f::Make(1.0f, 1.0f, 1.0f), 0xFF);
332
333 for (int i = 0; i < n; ++i) {
334 result[i] = accum;
335 }
336
337 result += n;
338 x += n;
339 count -= n;
340 } while (count > 0);
341 }
342
343 ////////////////////////////////////////////////////////////////////////////
344
345 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const346 void SkRadialShadowMapShaderImpl::toString(SkString* str) const {
347 str->appendf("RadialShadowMapShader: ()");
348 }
349 #endif
350
CreateProc(SkReadBuffer & buf)351 sk_sp<SkFlattenable> SkRadialShadowMapShaderImpl::CreateProc(SkReadBuffer& buf) {
352
353 // Discarding SkShader flattenable params
354 bool hasLocalMatrix = buf.readBool();
355 SkAssertResult(!hasLocalMatrix);
356
357 sk_sp<SkLights> light = SkLights::MakeFromBuffer(buf);
358
359 int diffuseWidth = buf.readInt();
360 int diffuseHeight = buf.readInt();
361
362 sk_sp<SkShader> occluderShader(buf.readFlattenable<SkShader>());
363
364 return sk_make_sp<SkRadialShadowMapShaderImpl>(std::move(occluderShader),
365 std::move(light),
366 diffuseWidth, diffuseHeight);
367 }
368
flatten(SkWriteBuffer & buf) const369 void SkRadialShadowMapShaderImpl::flatten(SkWriteBuffer& buf) const {
370 this->INHERITED::flatten(buf);
371
372 fLight->flatten(buf);
373
374 buf.writeInt(fWidth);
375 buf.writeInt(fHeight);
376
377 buf.writeFlattenable(fOccluderShader.get());
378 }
379
onContextSize(const ContextRec & rec) const380 size_t SkRadialShadowMapShaderImpl::onContextSize(const ContextRec& rec) const {
381 return sizeof(ShadowMapRadialShaderContext);
382 }
383
onCreateContext(const ContextRec & rec,void * storage) const384 SkShader::Context* SkRadialShadowMapShaderImpl::onCreateContext(const ContextRec& rec,
385 void* storage) const {
386 size_t heapRequired = fOccluderShader->contextSize(rec);
387
388 void* heapAllocated = sk_malloc_throw(heapRequired);
389
390 void* occluderContextStorage = heapAllocated;
391
392 SkShader::Context* occluderContext =
393 fOccluderShader->createContext(rec, occluderContextStorage);
394
395 if (!occluderContext) {
396 sk_free(heapAllocated);
397 return nullptr;
398 }
399
400 return new (storage) ShadowMapRadialShaderContext(*this, rec, occluderContext, heapAllocated);
401 }
402
403 ///////////////////////////////////////////////////////////////////////////////
404
Make(sk_sp<SkShader> occluderShader,sk_sp<SkLights> light,int diffuseWidth,int diffuseHeight)405 sk_sp<SkShader> SkRadialShadowMapShader::Make(sk_sp<SkShader> occluderShader,
406 sk_sp<SkLights> light,
407 int diffuseWidth, int diffuseHeight) {
408 if (!occluderShader) {
409 // TODO: Use paint's color in absence of a diffuseShader
410 // TODO: Use a default implementation of normalSource instead
411 return nullptr;
412 }
413
414 return sk_make_sp<SkRadialShadowMapShaderImpl>(std::move(occluderShader),
415 std::move(light),
416 diffuseWidth, diffuseHeight);
417 }
418
419 ///////////////////////////////////////////////////////////////////////////////
420
421 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRadialShadowMapShader)
422 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialShadowMapShaderImpl)
423 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
424
425 ///////////////////////////////////////////////////////////////////////////////
426
427 #endif
428