Index: src/core/SkLightingShader.cpp |
diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp |
index ca1c3417b4581ab5c404654e6acc4bd51bd8858c..f32aa9f411b1f30a93c6f081713f0385c87f1051 100644 |
--- a/src/core/SkLightingShader.cpp |
+++ b/src/core/SkLightingShader.cpp |
@@ -12,6 +12,7 @@ |
#include "SkErrorInternals.h" |
#include "SkLightingShader.h" |
#include "SkMathPriv.h" |
+#include "SkNormalSource.h" |
#include "SkPoint3.h" |
#include "SkReadBuffer.h" |
#include "SkWriteBuffer.h" |
@@ -55,7 +56,7 @@ public: |
const sk_sp<SkLights> lights, |
const SkVector& invNormRotation, |
const SkMatrix* diffLocalM, const SkMatrix* normLocalM, |
- sk_sp<SkLightingShader::NormalSource> normalSource) |
+ sk_sp<SkNormalSource> normalSource) |
: INHERITED(diffLocalM) |
, fDiffuseMap(diffuse) |
, fNormalMap(normal) |
@@ -88,7 +89,8 @@ public: |
// The context takes ownership of the states. It will call their destructors |
// but will NOT free the memory. |
LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&, |
- SkBitmapProcState* diffuseState, SkBitmapProcState* normalState); |
+ SkBitmapProcState* diffuseState, SkNormalSource::Provider*, |
+ void* heapAllocated); |
~LightingShaderContext() override; |
void shadeSpan(int x, int y, SkPMColor[], int count) override; |
@@ -96,9 +98,11 @@ public: |
uint32_t getFlags() const override { return fFlags; } |
private: |
- SkBitmapProcState* fDiffuseState; |
- SkBitmapProcState* fNormalState; |
- uint32_t fFlags; |
+ SkBitmapProcState* fDiffuseState; |
+ SkNormalSource::Provider* fNormalProvider; |
+ uint32_t fFlags; |
+ |
+ void* fHeapAllocated; |
typedef SkShader::Context INHERITED; |
}; |
@@ -110,7 +114,6 @@ protected: |
void flatten(SkWriteBuffer&) const override; |
size_t onContextSize(const ContextRec&) const override; |
Context* onCreateContext(const ContextRec&, void*) const override; |
- bool computeNormTotalInverse(const ContextRec& rec, SkMatrix* normTotalInverse) const; |
private: |
SkBitmap fDiffuseMap; |
@@ -121,7 +124,7 @@ private: |
SkMatrix fNormLocalMatrix; |
SkVector fInvNormRotation; |
- sk_sp<SkLightingShader::NormalSource> fNormalSource; |
+ sk_sp<SkNormalSource> fNormalSource; |
friend class SkLightingShader; |
@@ -367,13 +370,12 @@ bool SkLightingShaderImpl::isOpaque() const { |
} |
SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( |
- const SkLightingShaderImpl& shader, |
- const ContextRec& rec, |
- SkBitmapProcState* diffuseState, |
- SkBitmapProcState* normalState) |
+ const SkLightingShaderImpl& shader, const ContextRec& rec, SkBitmapProcState* diffuseState, |
+ SkNormalSource::Provider* normalProvider, void* heapAllocated) |
: INHERITED(shader, rec) |
, fDiffuseState(diffuseState) |
- , fNormalState(normalState) { |
+ , fNormalProvider(normalProvider) |
+ , fHeapAllocated(heapAllocated) { |
const SkPixmap& pixmap = fDiffuseState->fPixmap; |
bool isOpaque = pixmap.isOpaque(); |
@@ -390,7 +392,9 @@ SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { |
// The bitmap proc states have been created outside of the context on memory that will be freed |
// elsewhere. Call the destructors but leave the freeing of the memory to the caller. |
fDiffuseState->~SkBitmapProcState(); |
- fNormalState->~SkBitmapProcState(); |
+ fNormalProvider->~Provider(); |
+ |
+ sk_free(fHeapAllocated); |
} |
static inline SkPMColor convert(SkColor3f color, U8CPU a) { |
@@ -417,29 +421,24 @@ static inline SkPMColor convert(SkColor3f color, U8CPU a) { |
// larger is better (fewer times we have to loop), but we shouldn't |
// take up too much stack-space (each one here costs 16 bytes) |
-#define TMP_COUNT 16 |
- |
+#define TMP_COUNT 16 |
+#define BUFFER_MAX ((int)(TMP_COUNT * sizeof(uint32_t))) |
void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, |
SkPMColor result[], int count) { |
const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader); |
- uint32_t tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT]; |
- SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT]; |
+ uint32_t tmpColor[TMP_COUNT]; |
+ SkPMColor tmpColor2[2*TMP_COUNT]; |
SkBitmapProcState::MatrixProc diffMProc = fDiffuseState->getMatrixProc(); |
SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32(); |
- SkBitmapProcState::MatrixProc normalMProc = fNormalState->getMatrixProc(); |
- SkBitmapProcState::SampleProc32 normalSProc = fNormalState->getSampleProc32(); |
- |
- int diffMax = fDiffuseState->maxCountForBufferSize(sizeof(tmpColor[0]) * TMP_COUNT); |
- int normMax = fNormalState->maxCountForBufferSize(sizeof(tmpNormal[0]) * TMP_COUNT); |
- int max = SkTMin(diffMax, normMax); |
+ int max = fDiffuseState->maxCountForBufferSize(BUFFER_MAX); |
SkASSERT(fDiffuseState->fPixmap.addr()); |
- SkASSERT(fNormalState->fPixmap.addr()); |
- SkPoint3 norm, xformedNorm; |
+ SkASSERT(max <= BUFFER_MAX); |
+ SkPoint3 normals[BUFFER_MAX]; |
do { |
int n = count; |
@@ -450,21 +449,9 @@ void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, |
diffMProc(*fDiffuseState, tmpColor, n, x, y); |
diffSProc(*fDiffuseState, tmpColor, n, tmpColor2); |
- normalMProc(*fNormalState, tmpNormal, n, x, y); |
- normalSProc(*fNormalState, tmpNormal, n, tmpNormal2); |
+ fNormalProvider->fillScanLine(x, y, normals, n); |
for (int i = 0; i < n; ++i) { |
- SkASSERT(0xFF == SkColorGetA(tmpNormal2[i])); // opaque -> unpremul |
- norm.set(SkIntToScalar(SkGetPackedR32(tmpNormal2[i]))-127.0f, |
- SkIntToScalar(SkGetPackedG32(tmpNormal2[i]))-127.0f, |
- SkIntToScalar(SkGetPackedB32(tmpNormal2[i]))-127.0f); |
- norm.normalize(); |
- |
- xformedNorm.fX = lightShader.fInvNormRotation.fX * norm.fX + |
- lightShader.fInvNormRotation.fY * norm.fY; |
- xformedNorm.fY = -lightShader.fInvNormRotation.fY * norm.fX + |
- lightShader.fInvNormRotation.fX * norm.fY; |
- xformedNorm.fZ = norm.fZ; |
SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]); |
@@ -476,7 +463,7 @@ void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, |
if (SkLights::Light::kAmbient_LightType == light.type()) { |
accum += light.color().makeScale(255.0f); |
} else { |
- SkScalar NdotL = xformedNorm.dot(light.dir()); |
+ SkScalar NdotL = normals[i].dot(light.dir()); |
if (NdotL < 0.0f) { |
NdotL = 0.0f; |
} |
@@ -563,8 +550,7 @@ sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { |
invNormRotation = buf.readPoint(); |
} |
- sk_sp<SkLightingShader::NormalSource> normalSource( |
- buf.readFlattenable<SkLightingShader::NormalSource>()); |
+ sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>()); |
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), invNormRotation, |
&diffLocalM, &normLocalM, std::move(normalSource)); |
@@ -599,21 +585,8 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { |
buf.writeFlattenable(fNormalSource.get()); |
} |
-bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec, |
- SkMatrix* normTotalInverse) const { |
- SkMatrix total; |
- total.setConcat(*rec.fMatrix, fNormLocalMatrix); |
- |
- const SkMatrix* m = &total; |
- if (rec.fLocalMatrix) { |
- total.setConcat(*m, *rec.fLocalMatrix); |
- m = &total; |
- } |
- return m->invert(normTotalInverse); |
-} |
- |
-size_t SkLightingShaderImpl::onContextSize(const ContextRec&) const { |
- return 2 * sizeof(SkBitmapProcState) + sizeof(LightingShaderContext); |
+size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { |
+ return sizeof(LightingShaderContext); |
} |
SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, |
@@ -623,35 +596,31 @@ SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, |
// computeTotalInverse was called in SkShader::createContext so we know it will succeed |
SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv)); |
- SkMatrix normTotalInv; |
- if (!this->computeNormTotalInverse(rec, &normTotalInv)) { |
- return nullptr; |
- } |
+ size_t heapRequired = sizeof(SkBitmapProcState) + fNormalSource->providerSize(rec); |
+ void* heapAllocated = sk_malloc_throw(heapRequired); |
- void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext); |
+ void* diffuseStateStorage = heapAllocated; |
SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap, |
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, |
SkMipMap::DeduceTreatment(rec)); |
SkASSERT(diffuseState); |
if (!diffuseState->setup(diffTotalInv, *rec.fPaint)) { |
diffuseState->~SkBitmapProcState(); |
+ sk_free(heapAllocated); |
return nullptr; |
} |
+ void* normalProviderStorage = (char*)heapAllocated + sizeof(SkBitmapProcState); |
- void* normalStateStorage = (char*)storage + |
- sizeof(LightingShaderContext) + |
- sizeof(SkBitmapProcState); |
- SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap, |
- SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, |
- SkMipMap::DeduceTreatment(rec)); |
- SkASSERT(normalState); |
- if (!normalState->setup(normTotalInv, *rec.fPaint)) { |
+ SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, |
+ normalProviderStorage); |
+ if (!normalProvider) { |
diffuseState->~SkBitmapProcState(); |
- normalState->~SkBitmapProcState(); |
+ sk_free(heapAllocated); |
return nullptr; |
} |
- return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState); |
+ return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider, |
+ heapAllocated); |
} |
/////////////////////////////////////////////////////////////////////////////// |
@@ -668,8 +637,12 @@ sk_sp<SkShader> SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap& |
} |
SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); |
- sk_sp<SkLightingShader::NormalSource> normalSource = |
- SkLightingShader::NormalSource::MakeMap(normal, invNormRotation, normLocalM); |
+ // TODO: support other tile modes |
+ sk_sp<SkShader> mapShader = SkMakeBitmapShader(normal, SkShader::kClamp_TileMode, |
+ SkShader::kClamp_TileMode, normLocalM, nullptr); |
+ |
+ sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(mapShader, |
+ invNormRotation); |
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), |
invNormRotation, diffLocalM, normLocalM, std::move(normalSource)); |