| Index: src/core/SkLightingShader.cpp
|
| diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp
|
| index 87867a9f269784bb3aae957bb1ad2fad0f3e7d69..aaf29fcf3a344f0bbf8f909f6768bdfb4053ec68 100644
|
| --- a/src/core/SkLightingShader.cpp
|
| +++ b/src/core/SkLightingShader.cpp
|
| @@ -42,19 +42,17 @@
|
|
|
| /** Create a new lighting shader that uses the provided normal map and
|
| lights to light the diffuse bitmap.
|
| - @param diffuse the diffuse bitmap
|
| - @param normal the normal map
|
| - @param lights the lights applied to the normal map
|
| - @param invNormRotation rotation applied to the normal map's normals
|
| - @param diffLocalM the local matrix for the diffuse coordinates
|
| - @param normLocalM the local matrix for the normal coordinates
|
| - @param normalSource the normal source for GPU computations
|
| + @param diffuse the diffuse bitmap
|
| + @param normal the normal map
|
| + @param lights the lights applied to the normal map
|
| + @param invNormRotation rotation applied to the normal map's normals
|
| + @param diffLocalM the local matrix for the diffuse coordinates
|
| + @param normLocalM the local matrix for the normal coordinates
|
| */
|
| SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal,
|
| const sk_sp<SkLights> lights,
|
| const SkVector& invNormRotation,
|
| - const SkMatrix* diffLocalM, const SkMatrix* normLocalM,
|
| - sk_sp<SkLightingShader::NormalSource> normalSource)
|
| + const SkMatrix* diffLocalM, const SkMatrix* normLocalM)
|
| : INHERITED(diffLocalM)
|
| , fDiffuseMap(diffuse)
|
| , fNormalMap(normal)
|
| @@ -69,7 +67,6 @@
|
| // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe.
|
| (void)fNormLocalMatrix.getType();
|
|
|
| - fNormalSource = std::move(normalSource);
|
| }
|
|
|
| bool isOpaque() const override;
|
| @@ -119,8 +116,6 @@
|
|
|
| SkMatrix fNormLocalMatrix;
|
| SkVector fInvNormRotation;
|
| -
|
| - sk_sp<SkLightingShader::NormalSource> fNormalSource;
|
|
|
| friend class SkLightingShader;
|
|
|
| @@ -139,18 +134,24 @@
|
| #include "glsl/GrGLSLFragmentShaderBuilder.h"
|
| #include "glsl/GrGLSLProgramDataManager.h"
|
| #include "glsl/GrGLSLUniformHandler.h"
|
| -#include "SkBitmapProcShader.h"
|
| #include "SkGr.h"
|
| #include "SkGrPriv.h"
|
|
|
| class LightingFP : public GrFragmentProcessor {
|
| public:
|
| - LightingFP(GrTexture* diffuse, const SkMatrix& diffMatrix, const GrTextureParams& diffParams,
|
| - sk_sp<SkLights> lights, sk_sp<GrFragmentProcessor> normalFP)
|
| + LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& diffMatrix,
|
| + const SkMatrix& normMatrix, const GrTextureParams& diffParams,
|
| + const GrTextureParams& normParams, sk_sp<SkLights> lights,
|
| + const SkVector& invNormRotation)
|
| : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode())
|
| - , fDiffuseTextureAccess(diffuse, diffParams) {
|
| + , fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode())
|
| + , fDiffuseTextureAccess(diffuse, diffParams)
|
| + , fNormalTextureAccess(normal, normParams)
|
| + , fInvNormRotation(invNormRotation) {
|
| this->addCoordTransform(&fDiffDeviceTransform);
|
| + this->addCoordTransform(&fNormDeviceTransform);
|
| this->addTextureAccess(&fDiffuseTextureAccess);
|
| + this->addTextureAccess(&fNormalTextureAccess);
|
|
|
| // fuse all ambient lights into a single one
|
| fAmbientColor.set(0.0f, 0.0f, 0.0f);
|
| @@ -164,16 +165,16 @@
|
| }
|
| }
|
|
|
| - this->registerChildProcessor(std::move(normalFP));
|
| this->initClassID<LightingFP>();
|
| }
|
|
|
| - class GLSLLightingFP : public GrGLSLFragmentProcessor {
|
| + class LightingGLFP : public GrGLSLFragmentProcessor {
|
| public:
|
| - GLSLLightingFP() {
|
| + LightingGLFP() {
|
| fLightDir.fX = 10000.0f;
|
| fLightColor.fX = 0.0f;
|
| fAmbientColor.fX = 0.0f;
|
| + fInvNormRotation.set(0.0f, 0.0f);
|
| }
|
|
|
| void emitCode(EmitArgs& args) override {
|
| @@ -197,16 +198,33 @@
|
| kVec3f_GrSLType, kDefault_GrSLPrecision,
|
| "AmbientColor", &ambientColorUniName);
|
|
|
| + const char* xformUniName = nullptr;
|
| + fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| + kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| + "Xform", &xformUniName);
|
| +
|
| fragBuilder->codeAppend("vec4 diffuseColor = ");
|
| fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0],
|
| args.fCoords[0].c_str(),
|
| args.fCoords[0].getType());
|
| fragBuilder->codeAppend(";");
|
|
|
| - SkString dstNormalName("dstNormal");
|
| - this->emitChild(0, nullptr, &dstNormalName, args);
|
| -
|
| - fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str());
|
| + fragBuilder->codeAppend("vec4 normalColor = ");
|
| + fragBuilder->appendTextureLookup(args.fTexSamplers[1],
|
| + args.fCoords[1].c_str(),
|
| + args.fCoords[1].getType());
|
| + fragBuilder->codeAppend(";");
|
| +
|
| + fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);");
|
| +
|
| + fragBuilder->codeAppendf(
|
| + "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
|
| + xformUniName, xformUniName, xformUniName, xformUniName);
|
| +
|
| + // TODO: inverse map the light direction vectors in the vertex shader rather than
|
| + // transforming all the normals here!
|
| + fragBuilder->codeAppend("normal = normalize(m*normal);");
|
| +
|
| fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);",
|
| lightDirUniName);
|
| // diffuse light
|
| @@ -244,6 +262,12 @@
|
| pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
|
| fAmbientColor = ambientColor;
|
| }
|
| +
|
| + const SkVector& invNormRotation = lightingFP.invNormRotation();
|
| + if (invNormRotation != fInvNormRotation) {
|
| + pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
|
| + fInvNormRotation = invNormRotation;
|
| + }
|
| }
|
|
|
| private:
|
| @@ -255,10 +279,13 @@
|
|
|
| SkColor3f fAmbientColor;
|
| GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
|
| +
|
| + SkVector fInvNormRotation;
|
| + GrGLSLProgramDataManager::UniformHandle fXformUni;
|
| };
|
|
|
| void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
|
| - GLSLLightingFP::GenKey(*this, caps, b);
|
| + LightingGLFP::GenKey(*this, caps, b);
|
| }
|
|
|
| const char* name() const override { return "LightingFP"; }
|
| @@ -270,24 +297,32 @@
|
| const SkVector3& lightDir() const { return fLightDir; }
|
| const SkColor3f& lightColor() const { return fLightColor; }
|
| const SkColor3f& ambientColor() const { return fAmbientColor; }
|
| + const SkVector& invNormRotation() const { return fInvNormRotation; }
|
|
|
| private:
|
| - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
|
| + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new LightingGLFP; }
|
|
|
| bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
| const LightingFP& lightingFP = proc.cast<LightingFP>();
|
| return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform &&
|
| + fNormDeviceTransform == lightingFP.fNormDeviceTransform &&
|
| fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess &&
|
| + fNormalTextureAccess == lightingFP.fNormalTextureAccess &&
|
| fLightDir == lightingFP.fLightDir &&
|
| fLightColor == lightingFP.fLightColor &&
|
| - fAmbientColor == lightingFP.fAmbientColor;
|
| + fAmbientColor == lightingFP.fAmbientColor &&
|
| + fInvNormRotation == lightingFP.fInvNormRotation;
|
| }
|
|
|
| GrCoordTransform fDiffDeviceTransform;
|
| + GrCoordTransform fNormDeviceTransform;
|
| GrTextureAccess fDiffuseTextureAccess;
|
| + GrTextureAccess fNormalTextureAccess;
|
| SkVector3 fLightDir;
|
| SkColor3f fLightColor;
|
| SkColor3f fAmbientColor;
|
| +
|
| + SkVector fInvNormRotation;
|
| };
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
| @@ -322,39 +357,56 @@
|
| SkFilterQuality filterQuality,
|
| SkSourceGammaTreatment gammaTreatment) const {
|
| // we assume diffuse and normal maps have same width and height
|
| - // TODO: support different sizes, will be addressed when diffuse maps are factored out of
|
| - // SkLightingShader in a future CL
|
| + // TODO: support different sizes
|
| SkASSERT(fDiffuseMap.width() == fNormalMap.width() &&
|
| fDiffuseMap.height() == fNormalMap.height());
|
| - SkMatrix diffM;
|
| + SkMatrix diffM, normM;
|
|
|
| if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
|
| return nullptr;
|
| }
|
|
|
| bool doBicubic;
|
| GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode(
|
| - SkTMin(filterQuality, kMedium_SkFilterQuality),
|
| - viewM,
|
| - this->getLocalMatrix(),
|
| - &doBicubic);
|
| + SkTMin(filterQuality, kMedium_SkFilterQuality),
|
| + viewM,
|
| + this->getLocalMatrix(),
|
| + &doBicubic);
|
| + SkASSERT(!doBicubic);
|
| +
|
| + GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode(
|
| + SkTMin(filterQuality, kMedium_SkFilterQuality),
|
| + viewM,
|
| + fNormLocalMatrix,
|
| + &doBicubic);
|
| SkASSERT(!doBicubic);
|
|
|
| // TODO: support other tile modes
|
| GrTextureParams diffParams(kClamp_TileMode, diffFilterMode);
|
| - SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDiffuseMap,
|
| - diffParams, gammaTreatment));
|
| + SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context,
|
| + fDiffuseMap, diffParams,
|
| + gammaTreatment));
|
| if (!diffuseTexture) {
|
| SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
| return nullptr;
|
| }
|
|
|
| - sk_sp<GrFragmentProcessor> normalFP(
|
| - fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filterQuality,
|
| - gammaTreatment));
|
| + GrTextureParams normParams(kClamp_TileMode, normFilterMode);
|
| + SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context,
|
| + fNormalMap, normParams,
|
| + gammaTreatment));
|
| + if (!normalTexture) {
|
| + SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
| + return nullptr;
|
| + }
|
| +
|
| sk_sp<GrFragmentProcessor> inner (
|
| - new LightingFP(diffuseTexture, diffM, diffParams, fLights, std::move(normalFP)));
|
| -
|
| + new LightingFP(diffuseTexture, normalTexture, diffM, normM, diffParams, normParams, fLights,
|
| + fInvNormRotation));
|
| return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
| }
|
|
|
| @@ -366,14 +418,14 @@
|
| return fDiffuseMap.isOpaque();
|
| }
|
|
|
| -SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
|
| - const SkLightingShaderImpl& shader,
|
| - const ContextRec& rec,
|
| - SkBitmapProcState* diffuseState,
|
| - SkBitmapProcState* normalState)
|
| +SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLightingShaderImpl& shader,
|
| + const ContextRec& rec,
|
| + SkBitmapProcState* diffuseState,
|
| + SkBitmapProcState* normalState)
|
| : INHERITED(shader, rec)
|
| , fDiffuseState(diffuseState)
|
| - , fNormalState(normalState) {
|
| + , fNormalState(normalState)
|
| +{
|
| const SkPixmap& pixmap = fDiffuseState->fPixmap;
|
| bool isOpaque = pixmap.isOpaque();
|
|
|
| @@ -563,11 +615,8 @@
|
| invNormRotation = buf.readPoint();
|
| }
|
|
|
| - sk_sp<SkLightingShader::NormalSource> normalSource(
|
| - buf.readFlattenable<SkLightingShader::NormalSource>());
|
| -
|
| return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), invNormRotation,
|
| - &diffLocalM, &normLocalM, std::move(normalSource));
|
| + &diffLocalM, &normLocalM);
|
| }
|
|
|
| void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
|
| @@ -595,8 +644,6 @@
|
| }
|
| }
|
| buf.writePoint(fInvNormRotation);
|
| -
|
| - buf.writeFlattenable(fNormalSource.get());
|
| }
|
|
|
| bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec,
|
| @@ -638,9 +685,7 @@
|
| return nullptr;
|
| }
|
|
|
| - void* normalStateStorage = (char*)storage +
|
| - sizeof(LightingShaderContext) +
|
| - 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));
|
| @@ -656,23 +701,31 @@
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +static bool bitmap_is_too_big(const SkBitmap& bm) {
|
| + // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
|
| + // communicates between its matrix-proc and its sampler-proc. Until we can
|
| + // widen that, we have to reject bitmaps that are larger.
|
| + //
|
| + static const int kMaxSize = 65535;
|
| +
|
| + return bm.width() > kMaxSize || bm.height() > kMaxSize;
|
| +}
|
| +
|
| sk_sp<SkShader> SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap& normal,
|
| sk_sp<SkLights> lights,
|
| const SkVector& invNormRotation,
|
| const SkMatrix* diffLocalM, const SkMatrix* normLocalM) {
|
| - if (diffuse.isNull() || SkBitmapProcShader::BitmapIsTooBig(diffuse) ||
|
| - normal.isNull() || SkBitmapProcShader::BitmapIsTooBig(normal) ||
|
| - diffuse.width() != normal.width() ||
|
| + if (diffuse.isNull() || bitmap_is_too_big(diffuse) ||
|
| + normal.isNull() || bitmap_is_too_big(normal) ||
|
| + diffuse.width() != normal.width() ||
|
| diffuse.height() != normal.height()) {
|
| return nullptr;
|
| }
|
| +
|
| SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
|
|
|
| - sk_sp<SkLightingShader::NormalSource> normalSource =
|
| - SkLightingShader::NormalMapSource::Make(normal, invNormRotation, normLocalM);
|
| -
|
| return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights),
|
| - invNormRotation, diffLocalM, normLocalM, std::move(normalSource));
|
| + invNormRotation, diffLocalM, normLocalM);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|