| Index: src/core/SkNormalSource.cpp
|
| diff --git a/src/core/SkLightingShader_NormalSource.cpp b/src/core/SkNormalSource.cpp
|
| similarity index 54%
|
| rename from src/core/SkLightingShader_NormalSource.cpp
|
| rename to src/core/SkNormalSource.cpp
|
| index b96b1bf083c314b4f6e33f94bb21b5c0c5c0fb59..cadf47e29ce5b57dfa96acf13136541a6515d4dd 100644
|
| --- a/src/core/SkLightingShader_NormalSource.cpp
|
| +++ b/src/core/SkNormalSource.cpp
|
| @@ -6,32 +6,24 @@
|
| */
|
|
|
| #include "SkBitmapProcShader.h"
|
| +#include "SkBitmapProcState.h"
|
| #include "SkError.h"
|
| #include "SkErrorInternals.h"
|
| #include "SkLightingShader.h"
|
| +#include "SkNormalSource.h"
|
| #include "SkReadBuffer.h"
|
| #include "SkWriteBuffer.h"
|
|
|
| // Genretating vtable
|
| -SkLightingShader::NormalSource::~NormalSource() {}
|
| +SkNormalSource::~SkNormalSource() {}
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -class NormalMapSourceImpl : public SkLightingShader::NormalSource {
|
| +class NormalMapSourceImpl : public SkNormalSource {
|
| public:
|
| - NormalMapSourceImpl(const SkBitmap &normal, const SkVector &invNormRotation,
|
| - const SkMatrix *normLocalM)
|
| - : fNormalMap(normal)
|
| - , fInvNormRotation(invNormRotation) {
|
| -
|
| - if (normLocalM) {
|
| - fNormLocalMatrix = *normLocalM;
|
| - } else {
|
| - fNormLocalMatrix.reset();
|
| - }
|
| - // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe.
|
| - (void)fNormLocalMatrix.getType();
|
| - }
|
| + NormalMapSourceImpl(sk_sp<SkShader> bitmapShader, const SkVector &invNormRotation)
|
| + : fBitmapShader(std::move(bitmapShader))
|
| + , fInvNormRotation(invNormRotation) {}
|
|
|
| #if SK_SUPPORT_GPU
|
| sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
|
| @@ -41,19 +33,38 @@ public:
|
| SkSourceGammaTreatment) const override;
|
| #endif
|
|
|
| + SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec,
|
| + void* storage) const override;
|
| +
|
| + size_t providerSize(const SkShader::ContextRec& rec) const override;
|
| SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(NormalMapSourceImpl)
|
|
|
| protected:
|
| void flatten(SkWriteBuffer& buf) const override;
|
|
|
| + bool computeNormTotalInverse(const SkShader::ContextRec& rec, SkMatrix* normTotalInverse) const;
|
| +
|
| private:
|
| - SkBitmap fNormalMap;
|
| - SkMatrix fNormLocalMatrix;
|
| + class Provider : public SkNormalSource::Provider {
|
| + public:
|
| + Provider(const NormalMapSourceImpl& source, SkShader::Context* fBitmapContext);
|
| +
|
| + virtual ~Provider();
|
| +
|
| + void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
|
| + private:
|
| + const NormalMapSourceImpl& fSource;
|
| + SkShader::Context* fBitmapContext;
|
| +
|
| + typedef SkNormalSource::Provider INHERITED;
|
| + };
|
| +
|
| + sk_sp<SkShader> fBitmapShader;
|
| SkVector fInvNormRotation;
|
|
|
| - friend class SkLightingShader::NormalSource;
|
| + friend class SkNormalSource;
|
|
|
| - typedef SkLightingShader::NormalSource INHERITED;
|
| + typedef SkNormalSource INHERITED;
|
| };
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
| @@ -69,13 +80,9 @@ private:
|
|
|
| class NormalMapFP : public GrFragmentProcessor {
|
| public:
|
| - NormalMapFP(GrTexture* normal, const SkMatrix& normMatrix, const GrTextureParams& normParams,
|
| - const SkVector& invNormRotation)
|
| - : fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode())
|
| - , fNormalTextureAccess(normal, normParams)
|
| - , fInvNormRotation(invNormRotation) {
|
| - this->addCoordTransform(&fNormDeviceTransform);
|
| - this->addTextureAccess(&fNormalTextureAccess);
|
| + NormalMapFP(sk_sp<GrFragmentProcessor> bitmapFP, const SkVector& invNormRotation)
|
| + : fInvNormRotation(invNormRotation) {
|
| + this->registerChildProcessor(bitmapFP);
|
|
|
| this->initClassID<NormalMapFP>();
|
| }
|
| @@ -97,13 +104,10 @@ public:
|
| kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| "Xform", &xformUniName);
|
|
|
| - fragBuilder->codeAppend("vec4 normalColor = ");
|
| - fragBuilder->appendTextureLookup(args.fTexSamplers[0],
|
| - args.fCoords[0].c_str(),
|
| - args.fCoords[0].getType());
|
| - fragBuilder->codeAppend(";");
|
| -
|
| - fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);");
|
| + SkString dstNormalColorName("dstNormalColor");
|
| + this->emitChild(0, nullptr, &dstNormalColorName, args);
|
| + fragBuilder->codeAppendf("vec3 normal = %s.rgb - vec3(0.5);",
|
| + dstNormalColorName.c_str());
|
|
|
| // TODO: inverse map the light direction vectors in the vertex shader rather than
|
| // transforming all the normals here!
|
| @@ -153,40 +157,12 @@ private:
|
|
|
| bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
| const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
|
| - return fNormDeviceTransform == normalMapFP.fNormDeviceTransform &&
|
| - fNormalTextureAccess == normalMapFP.fNormalTextureAccess &&
|
| - fInvNormRotation == normalMapFP.fInvNormRotation;
|
| + return fInvNormRotation == normalMapFP.fInvNormRotation;
|
| }
|
|
|
| - GrCoordTransform fNormDeviceTransform;
|
| - GrTextureAccess fNormalTextureAccess;
|
| - SkVector fInvNormRotation;
|
| + SkVector fInvNormRotation;
|
| };
|
|
|
| -// TODO same code at SkLightingShader.cpp. Refactor to common source!
|
| -static bool make_mat(const SkBitmap& bm,
|
| - const SkMatrix& localMatrix1,
|
| - const SkMatrix* localMatrix2,
|
| - SkMatrix* result) {
|
| -
|
| - result->setIDiv(bm.width(), bm.height());
|
| -
|
| - SkMatrix lmInverse;
|
| - if (!localMatrix1.invert(&lmInverse)) {
|
| - return false;
|
| - }
|
| - if (localMatrix2) {
|
| - SkMatrix inv;
|
| - if (!localMatrix2->invert(&inv)) {
|
| - return false;
|
| - }
|
| - lmInverse.postConcat(inv);
|
| - }
|
| - result->preConcat(lmInverse);
|
| -
|
| - return true;
|
| -}
|
| -
|
| sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
|
| GrContext *context,
|
| const SkMatrix &viewM,
|
| @@ -194,96 +170,132 @@ sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
|
| SkFilterQuality filterQuality,
|
| SkSourceGammaTreatment gammaTreatment) const {
|
|
|
| - // TODO Here, the old code was checking that diffuse map and normal map are same size, that
|
| - // will be addressed when diffuse maps are factored out of SkLightingShader in a future CL
|
| + sk_sp<GrFragmentProcessor> bitmapFP = fBitmapShader->asFragmentProcessor(context, viewM,
|
| + localMatrix, filterQuality, gammaTreatment);
|
| +
|
| + return sk_make_sp<NormalMapFP>(std::move(bitmapFP), fInvNormRotation);
|
| +}
|
| +
|
| +#endif // SK_SUPPORT_GPU
|
| +
|
| +////////////////////////////////////////////////////////////////////////////
|
| +
|
| +NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source,
|
| + SkShader::Context* bitmapContext)
|
| + : fSource(source)
|
| + , fBitmapContext(bitmapContext) {
|
| +}
|
| +
|
| +NormalMapSourceImpl::Provider::~Provider() {
|
| + fBitmapContext->~Context();
|
| +}
|
|
|
| - SkMatrix normM;
|
| - if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
|
| +SkNormalSource::Provider* NormalMapSourceImpl::asProvider(
|
| + const SkShader::ContextRec &rec, void *storage) const {
|
| + SkMatrix normTotalInv;
|
| + if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
|
| return nullptr;
|
| }
|
|
|
| - bool doBicubic;
|
| - GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode(
|
| - SkTMin(filterQuality, kMedium_SkFilterQuality),
|
| - viewM,
|
| - fNormLocalMatrix,
|
| - &doBicubic);
|
| - SkASSERT(!doBicubic);
|
| -
|
| - // TODO: support other tile modes
|
| - GrTextureParams normParams(SkShader::kClamp_TileMode, normFilterMode);
|
| - SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context,
|
| - fNormalMap,
|
| - normParams,
|
| - gammaTreatment));
|
| - if (!normalTexture) {
|
| - SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
| + void* bitmapContextStorage = (char*)storage + sizeof(Provider);
|
| + SkShader::Context* context = fBitmapShader->createContext(rec, bitmapContextStorage);
|
| + if (!context) {
|
| return nullptr;
|
| }
|
|
|
| - return sk_make_sp<NormalMapFP>(normalTexture, normM, normParams, fInvNormRotation);
|
| + return new (storage) Provider(*this, context);
|
| }
|
|
|
| -#endif // SK_SUPPORT_GPU
|
| -
|
| -////////////////////////////////////////////////////////////////////////////
|
| +size_t NormalMapSourceImpl::providerSize(const SkShader::ContextRec& rec) const {
|
| + return sizeof(Provider) + fBitmapShader->contextSize(rec);
|
| +}
|
|
|
| -sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
|
| +bool NormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec,
|
| + SkMatrix* normTotalInverse) const {
|
| + SkMatrix total;
|
| + total.setConcat(*rec.fMatrix, fBitmapShader->getLocalMatrix());
|
|
|
| - SkMatrix normLocalM;
|
| - bool hasNormLocalM = buf.readBool();
|
| - if (hasNormLocalM) {
|
| - buf.readMatrix(&normLocalM);
|
| - } else {
|
| - normLocalM.reset();
|
| + const SkMatrix* m = &total;
|
| + if (rec.fLocalMatrix) {
|
| + total.setConcat(*m, *rec.fLocalMatrix);
|
| + m = &total;
|
| }
|
| + return m->invert(normTotalInverse);
|
| +}
|
|
|
| - SkBitmap normal;
|
| - if (!buf.readBitmap(&normal)) {
|
| - return nullptr;
|
| - }
|
| - normal.setImmutable();
|
| +#define BUFFER_MAX 16
|
| +void NormalMapSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
|
| + int count) const {
|
| + SkPMColor tmpNormalColors[BUFFER_MAX];
|
| +
|
| + do {
|
| + int n = SkTMin(count, BUFFER_MAX);
|
| +
|
| + fBitmapContext->shadeSpan(x, y, tmpNormalColors, n);
|
| +
|
| + for (int i = 0; i < n; i++) {
|
| + SkPoint3 tempNorm;
|
| +
|
| + tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127.0f,
|
| + SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127.0f,
|
| + SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127.0f);
|
| + tempNorm.normalize();
|
| +
|
| + output[i].fX = fSource.fInvNormRotation.fX * tempNorm.fX +
|
| + fSource.fInvNormRotation.fY * tempNorm.fY;
|
| + output[i].fY = -fSource.fInvNormRotation.fY * tempNorm.fX +
|
| + fSource.fInvNormRotation.fX * tempNorm.fY;
|
| + output[i].fZ = tempNorm.fZ;
|
| + }
|
| +
|
| + output += n;
|
| + x += n;
|
| + count -= n;
|
| + } while (count > 0);
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
|
| +
|
| + sk_sp<SkShader> bitmapShader = buf.readFlattenable<SkShader>();
|
|
|
| SkVector invNormRotation = {1,0};
|
| if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
|
| invNormRotation = buf.readPoint();
|
| }
|
|
|
| - return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, &normLocalM);
|
| + return sk_make_sp<NormalMapSourceImpl>(std::move(bitmapShader), invNormRotation);
|
| }
|
|
|
| void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
|
| this->INHERITED::flatten(buf);
|
|
|
| - bool hasNormLocalM = !fNormLocalMatrix.isIdentity();
|
| - buf.writeBool(hasNormLocalM);
|
| - if (hasNormLocalM) {
|
| - buf.writeMatrix(fNormLocalMatrix);
|
| - }
|
| -
|
| - buf.writeBitmap(fNormalMap);
|
| + buf.writeFlattenable(fBitmapShader.get());
|
| buf.writePoint(fInvNormRotation);
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
|
|
| -sk_sp<SkLightingShader::NormalSource> SkLightingShader::NormalSource::MakeMap(
|
| +sk_sp<SkNormalSource> SkNormalSource::MakeMap(
|
| const SkBitmap &normal, const SkVector &invNormRotation, const SkMatrix *normLocalM) {
|
|
|
| - // TODO not checking normal and diffuse maps to be same size, will be addressed when diffuse
|
| - // maps are factored out of SkLightingShader in a future CL
|
| if (normal.isNull() || SkBitmapProcShader::BitmapIsTooBig(normal)) {
|
| return nullptr;
|
| }
|
|
|
| SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
|
|
|
| - return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, normLocalM);
|
| + // TODO: support other tile modes
|
| + sk_sp<SkShader> bitmapShader = SkMakeBitmapShader(normal, SkShader::kClamp_TileMode,
|
| + SkShader::kClamp_TileMode, normLocalM, nullptr);
|
| +
|
| + return sk_make_sp<NormalMapSourceImpl>(std::move(bitmapShader), invNormRotation);
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
|
|
| -SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader::NormalSource)
|
| +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource)
|
| SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
|
| SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
|
|
|
|