Revert of Refactoring of CPU NormalMap handling out into its own class (patchset...
authordvonbeck <dvonbeck@google.com>
Mon, 27 Jun 2016 16:30:19 +0000 (09:30 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 27 Jun 2016 16:30:19 +0000 (09:30 -0700)
Reason for revert:
GMs are crashing on Windows Test trybots

Original issue's description:
> SkLightingShader normal vector CPU computation refactor.
>
> The purpose of this change is to refactor the handling of normal maps out of SkLightingShader, laying the groundwork to eventually allow for multiple normal sources.
>
> This CL's base was the CL for GPU handling: https://codereview.chromium.org/2043393002/
>
> What this CL includes:
>
> - A refactor of the SkLightingShader context's code that deals with reading normals off of a normal map. This is now abstracted out into a NormalSource::Provider class that the context uses.
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2050773002
>
> Committed: https://skia.googlesource.com/skia/+/790a70118327a129cb6b48fabe80f4e184c1e67c

TBR=egdaniel@google.com,reed@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review-Url: https://codereview.chromium.org/2101653002

gyp/core.gypi
include/core/SkFlattenable.h
src/core/SkLightingShader.cpp
src/core/SkLightingShader.h
src/core/SkLightingShader_NormalSource.cpp [new file with mode: 0644]
src/core/SkNormalSource.cpp [deleted file]
src/core/SkNormalSource.h [deleted file]
src/ports/SkGlobalInitialization_default.cpp

index 7c89960e661d85b3977b27ccd13c241d1d06d7d1..516faf3095b11a47bf474d109d79dedd86e5d930 100644 (file)
         '<(skia_src_path)/core/SkLayerInfo.h',
         '<(skia_src_path)/core/SkLightingShader.h',
         '<(skia_src_path)/core/SkLightingShader.cpp',
+        '<(skia_src_path)/core/SkLightingShader_NormalSource.cpp',
         '<(skia_src_path)/core/SkLinearBitmapPipeline.cpp',
         '<(skia_src_path)/core/SkLinearBitmapPipeline.h',
         '<(skia_src_path)/core/SkLinearBitmapPipeline_core.h',
         '<(skia_src_path)/core/SkNextID.h',
         '<(skia_src_path)/core/SkNinePatchIter.cpp',
         '<(skia_src_path)/core/SkNinePatchIter.h',
-        '<(skia_src_path)/core/SkNormalSource.cpp',
-        '<(skia_src_path)/core/SkNormalSource.h',
         '<(skia_src_path)/core/SkNx.h',
         '<(skia_src_path)/core/SkOpts.cpp',
         '<(skia_src_path)/core/SkOpts.h',
index 88aeb7ee38059741b736836ba57885a5ab4b48c2..5eabcb3d6d29c0aea2dda585d2155ece4e6ba06a 100644 (file)
@@ -81,7 +81,7 @@ public:
         kSkShader_Type,
         kSkUnused_Type,     // used to be SkUnitMapper
         kSkXfermode_Type,
-        kSkNormalSource_Type,
+        kNormalSource_Type,
     };
 
     typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);
index 52b208f8df6f2ff848513f8ea1cedc246c7c7bea..ca1c3417b4581ab5c404654e6acc4bd51bd8858c 100644 (file)
@@ -12,7 +12,6 @@
 #include "SkErrorInternals.h"
 #include "SkLightingShader.h"
 #include "SkMathPriv.h"
-#include "SkNormalSource.h"
 #include "SkPoint3.h"
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
@@ -56,7 +55,7 @@ public:
                          const sk_sp<SkLights> lights,
                          const SkVector& invNormRotation,
                          const SkMatrix* diffLocalM, const SkMatrix* normLocalM,
-                         sk_sp<SkNormalSource> normalSource)
+                         sk_sp<SkLightingShader::NormalSource> normalSource)
         : INHERITED(diffLocalM)
         , fDiffuseMap(diffuse)
         , fNormalMap(normal)
@@ -89,7 +88,7 @@ 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, SkNormalSource::Provider*);
+                              SkBitmapProcState* diffuseState, SkBitmapProcState* normalState);
         ~LightingShaderContext() override;
 
         void shadeSpan(int x, int y, SkPMColor[], int count) override;
@@ -97,9 +96,9 @@ public:
         uint32_t getFlags() const override { return fFlags; }
 
     private:
-        SkBitmapProcState*        fDiffuseState;
-        SkNormalSource::Provider* fNormalProvider;
-        uint32_t                  fFlags;
+        SkBitmapProcState* fDiffuseState;
+        SkBitmapProcState* fNormalState;
+        uint32_t           fFlags;
 
         typedef SkShader::Context INHERITED;
     };
@@ -111,6 +110,7 @@ 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 +121,7 @@ private:
     SkMatrix        fNormLocalMatrix;
     SkVector        fInvNormRotation;
 
-    sk_sp<SkNormalSource> fNormalSource;
+    sk_sp<SkLightingShader::NormalSource> fNormalSource;
 
     friend class SkLightingShader;
 
@@ -367,11 +367,13 @@ bool SkLightingShaderImpl::isOpaque() const {
 }
 
 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
-        const SkLightingShaderImpl& shader, const ContextRec& rec, SkBitmapProcState* diffuseState,
-        SkNormalSource::Provider* normalProvider)
+                                                                const SkLightingShaderImpl& shader,
+                                                                const ContextRec& rec,
+                                                                SkBitmapProcState* diffuseState,
+                                                                SkBitmapProcState* normalState)
     : INHERITED(shader, rec)
     , fDiffuseState(diffuseState)
-    , fNormalProvider(normalProvider) {
+    , fNormalState(normalState) {
     const SkPixmap& pixmap = fDiffuseState->fPixmap;
     bool isOpaque = pixmap.isOpaque();
 
@@ -388,7 +390,7 @@ 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();
-    fNormalProvider->~Provider();
+    fNormalState->~SkBitmapProcState();
 }
 
 static inline SkPMColor convert(SkColor3f color, U8CPU a) {
@@ -415,24 +417,29 @@ 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 BUFFER_MAX ((int)(TMP_COUNT * sizeof(uint32_t)))
+#define TMP_COUNT     16
+
 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];
-    SkPMColor tmpColor2[2*TMP_COUNT];
+    uint32_t  tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT];
+    SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT];
 
     SkBitmapProcState::MatrixProc   diffMProc = fDiffuseState->getMatrixProc();
     SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32();
 
-    int max = fDiffuseState->maxCountForBufferSize(BUFFER_MAX);
+    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);
 
     SkASSERT(fDiffuseState->fPixmap.addr());
+    SkASSERT(fNormalState->fPixmap.addr());
 
-    SkASSERT(max <= BUFFER_MAX);
-    SkPoint3 normals[BUFFER_MAX];
+    SkPoint3 norm, xformedNorm;
 
     do {
         int n = count;
@@ -443,9 +450,21 @@ void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
         diffMProc(*fDiffuseState, tmpColor, n, x, y);
         diffSProc(*fDiffuseState, tmpColor, n, tmpColor2);
 
-        fNormalProvider->fillScanLine(x, y, normals, n);
+        normalMProc(*fNormalState, tmpNormal, n, x, y);
+        normalSProc(*fNormalState, tmpNormal, n, tmpNormal2);
 
         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]);
 
@@ -457,7 +476,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 = normals[i].dot(light.dir());
+                    SkScalar NdotL = xformedNorm.dot(light.dir());
                     if (NdotL < 0.0f) {
                         NdotL = 0.0f;
                     }
@@ -544,7 +563,8 @@ sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
         invNormRotation = buf.readPoint();
     }
 
-    sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
+    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));
@@ -579,10 +599,21 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
     buf.writeFlattenable(fNormalSource.get());
 }
 
-size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const {
-    return sizeof(LightingShaderContext) +
-           sizeof(SkBitmapProcState)     +
-           fNormalSource->providerSize(rec);
+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);
 }
 
 SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
@@ -592,6 +623,11 @@ 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;
+    }
+
     void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext);
     SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap,
                                               SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
@@ -601,18 +637,21 @@ SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
         diffuseState->~SkBitmapProcState();
         return nullptr;
     }
-    void* normalProviderStorage = (char*)storage +
-                                  sizeof(LightingShaderContext) +
-                                  sizeof(SkBitmapProcState);
 
-    SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec,
-                                                                         normalProviderStorage);
-    if (!normalProvider) {
+    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)) {
         diffuseState->~SkBitmapProcState();
+        normalState->~SkBitmapProcState();
         return nullptr;
     }
 
-    return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider);
+    return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -629,12 +668,8 @@ sk_sp<SkShader> SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap&
     }
     SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
 
-    // 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);
+    sk_sp<SkLightingShader::NormalSource> normalSource =
+            SkLightingShader::NormalSource::MakeMap(normal, invNormRotation, normLocalM);
 
     return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights),
             invNormRotation, diffLocalM, normLocalM, std::move(normalSource));
index e21b94266eebdb970a7400f5431bb3c698b68018..c2b65472b924f35d5d757ca751d1aae6fdf0b9ed 100644 (file)
@@ -16,6 +16,55 @@ class SkMatrix;
 
 class SK_API SkLightingShader {
 public:
+    /** Abstract class that generates or reads in normals for use by SkLightingShader. Currently
+        implements the GPU side only. Not to be used as part of the API yet. Used internally by
+        SkLightingShader.
+    */
+    class SK_API NormalSource : public SkFlattenable {
+    public:
+        virtual ~NormalSource();
+
+#if SK_SUPPORT_GPU
+        /** Returns a fragment processor that takes no input and outputs a normal (already rotated)
+            as its output color. To be used as a child fragment processor.
+        */
+        virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(
+                GrContext* context,
+                const SkMatrix& viewM,
+                const SkMatrix* localMatrix,
+                SkFilterQuality filterQuality,
+                SkSourceGammaTreatment gammaTreatment) const = 0;
+#endif
+
+        /** Returns a normal source that provides normals sourced from the the normal map argument.
+              Not to be used as part of the API yet. Used internally by SkLightingShader.
+
+              @param  normal                the normal map
+              @param  invNormRotation       rotation applied to the normal map's normals
+              @param  normLocalM            the local matrix for the normal map
+
+              nullptr will be returned if
+                  'normal' is empty
+                  'normal' too big (> 65535 on either side)
+
+              The normal map is currently assumed to be an 8888 image where the normal at a texel
+              is retrieved by:
+                  N.x = R-127;
+                  N.y = G-127;
+                  N.z = B-127;
+                  N.normalize();
+              The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
+              (127, 127, 0).
+        */
+        static sk_sp<NormalSource> MakeMap(const SkBitmap& normal, const SkVector& invNormRotation,
+                                           const SkMatrix* normLocalM);
+
+        SK_DEFINE_FLATTENABLE_TYPE(NormalSource)
+        SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+    };
+
+
+
     /** Returns a shader that lights the diffuse and normal maps with a set of lights.
 
         It returns a shader with a reference count of 1.
@@ -25,12 +74,8 @@ public:
         @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  diffLocalMatrix the local matrix for the diffuse map (transform from
-                                texture coordinates to shape source coordinates). nullptr is
-                                interpreted as an identity matrix.
-        @param  normLocalMatrix the local matrix for the normal map (transform from
-                                texture coordinates to shape source coordinates). nullptr is
-                                interpreted as an identity matrix.
+        @param  diffLocalMatrix the local matrix for the diffuse texture
+        @param  normLocalMatrix the local matrix for the normal map
 
         nullptr will be returned if:
             either 'diffuse' or 'normal' are empty
diff --git a/src/core/SkLightingShader_NormalSource.cpp b/src/core/SkLightingShader_NormalSource.cpp
new file mode 100644 (file)
index 0000000..b96b1bf
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapProcShader.h"
+#include "SkError.h"
+#include "SkErrorInternals.h"
+#include "SkLightingShader.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+// Genretating vtable
+SkLightingShader::NormalSource::~NormalSource() {}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class NormalMapSourceImpl : public SkLightingShader::NormalSource {
+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();
+    }
+
+#if SK_SUPPORT_GPU
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
+                                                   const SkMatrix& viewM,
+                                                   const SkMatrix* localMatrix,
+                                                   SkFilterQuality,
+                                                   SkSourceGammaTreatment) const override;
+#endif
+
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(NormalMapSourceImpl)
+
+protected:
+    void flatten(SkWriteBuffer& buf) const override;
+
+private:
+    SkBitmap        fNormalMap;
+    SkMatrix        fNormLocalMatrix;
+    SkVector        fInvNormRotation;
+
+    friend class SkLightingShader::NormalSource;
+
+    typedef SkLightingShader::NormalSource INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+
+#include "GrCoordTransform.h"
+#include "GrInvariantOutput.h"
+#include "GrTextureParams.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "SkGr.h"
+
+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);
+
+        this->initClassID<NormalMapFP>();
+    }
+
+    class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
+    public:
+        GLSLNormalMapFP() {
+            fInvNormRotation.set(0.0f, 0.0f);
+        }
+
+        void emitCode(EmitArgs& args) override {
+
+            GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+
+            // add uniform
+            const char* xformUniName = nullptr;
+            fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
+                                                   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);");
+
+            // TODO: inverse map the light direction vectors in the vertex shader rather than
+            // transforming all the normals here!
+            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);
+
+            fragBuilder->codeAppend("normal = normalize(m*normal);");
+            fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor);
+        }
+
+        static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
+                           GrProcessorKeyBuilder* b) {
+            b->add32(0x0);
+        }
+
+    protected:
+        void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
+            const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
+
+            const SkVector& invNormRotation = normalMapFP.invNormRotation();
+            if (invNormRotation != fInvNormRotation) {
+                pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
+                fInvNormRotation = invNormRotation;
+            }
+        }
+
+    private:
+        SkVector fInvNormRotation;
+        GrGLSLProgramDataManager::UniformHandle fXformUni;
+    };
+
+    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
+        GLSLNormalMapFP::GenKey(*this, caps, b);
+    }
+
+    const char* name() const override { return "NormalMapFP"; }
+
+    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+        inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
+    }
+
+    const SkVector& invNormRotation() const { return fInvNormRotation; }
+
+private:
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
+
+    bool onIsEqual(const GrFragmentProcessor& proc) const override {
+        const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
+        return fNormDeviceTransform == normalMapFP.fNormDeviceTransform &&
+               fNormalTextureAccess == normalMapFP.fNormalTextureAccess &&
+               fInvNormRotation     == normalMapFP.fInvNormRotation;
+    }
+
+    GrCoordTransform fNormDeviceTransform;
+    GrTextureAccess  fNormalTextureAccess;
+    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,
+                                                     const SkMatrix *localMatrix,
+                                                     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
+
+    SkMatrix normM;
+    if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
+        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.");
+        return nullptr;
+    }
+
+    return sk_make_sp<NormalMapFP>(normalTexture, normM, normParams, fInvNormRotation);
+}
+
+#endif // SK_SUPPORT_GPU
+
+////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
+
+    SkMatrix normLocalM;
+    bool hasNormLocalM = buf.readBool();
+    if (hasNormLocalM) {
+        buf.readMatrix(&normLocalM);
+    } else {
+        normLocalM.reset();
+    }
+
+    SkBitmap normal;
+    if (!buf.readBitmap(&normal)) {
+        return nullptr;
+    }
+    normal.setImmutable();
+
+    SkVector invNormRotation = {1,0};
+    if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
+        invNormRotation = buf.readPoint();
+    }
+
+    return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, &normLocalM);
+}
+
+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.writePoint(fInvNormRotation);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkLightingShader::NormalSource> SkLightingShader::NormalSource::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);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader::NormalSource)
+    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkNormalSource.cpp b/src/core/SkNormalSource.cpp
deleted file mode 100644 (file)
index 2f52530..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkError.h"
-#include "SkErrorInternals.h"
-#include "SkLightingShader.h"
-#include "SkNormalSource.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-
-// Genretating vtable
-SkNormalSource::~SkNormalSource() {}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class NormalMapSourceImpl : public SkNormalSource {
-public:
-    NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkVector &normRotation)
-        : fMapShader(std::move(mapShader))
-        , fNormRotation(normRotation) {}
-
-#if SK_SUPPORT_GPU
-    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
-                                                   const SkMatrix& viewM,
-                                                   const SkMatrix* localMatrix,
-                                                   SkFilterQuality,
-                                                   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:
-    class Provider : public SkNormalSource::Provider {
-    public:
-        Provider(const NormalMapSourceImpl& source, SkShader::Context* fMapContext);
-
-        virtual ~Provider() override;
-
-        void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
-    private:
-        const NormalMapSourceImpl& fSource;
-        SkShader::Context* fMapContext;
-
-        typedef SkNormalSource::Provider INHERITED;
-    };
-
-    sk_sp<SkShader> fMapShader;
-    SkVector        fNormRotation;
-
-    friend class SkNormalSource;
-
-    typedef SkNormalSource INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "GrCoordTransform.h"
-#include "GrInvariantOutput.h"
-#include "GrTextureParams.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "SkGr.h"
-
-class NormalMapFP : public GrFragmentProcessor {
-public:
-    NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkVector& normRotation)
-        : fNormRotation(normRotation) {
-        this->registerChildProcessor(mapFP);
-
-        this->initClassID<NormalMapFP>();
-    }
-
-    class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
-    public:
-        GLSLNormalMapFP() {
-            fNormRotation.set(0.0f, 0.0f);
-        }
-
-        void emitCode(EmitArgs& args) override {
-
-            GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
-            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
-
-            // add uniform
-            const char* xformUniName = nullptr;
-            fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
-                                                   kVec2f_GrSLType, kDefault_GrSLPrecision,
-                                                   "Xform", &xformUniName);
-
-            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!
-            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);
-
-            fragBuilder->codeAppend("normal = normalize(m*normal);");
-            fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor);
-        }
-
-        static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
-                           GrProcessorKeyBuilder* b) {
-            b->add32(0x0);
-        }
-
-    protected:
-        void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
-            const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
-
-            const SkVector& normRotation = normalMapFP.normRotation();
-            if (normRotation != fNormRotation) {
-                pdman.set2fv(fXformUni, 1, &normRotation.fX);
-                fNormRotation = normRotation;
-            }
-        }
-
-    private:
-        SkVector fNormRotation;
-        GrGLSLProgramDataManager::UniformHandle fXformUni;
-    };
-
-    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
-        GLSLNormalMapFP::GenKey(*this, caps, b);
-    }
-
-    const char* name() const override { return "NormalMapFP"; }
-
-    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
-        inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
-    }
-
-    const SkVector& normRotation() const { return fNormRotation; }
-
-private:
-    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
-
-    bool onIsEqual(const GrFragmentProcessor& proc) const override {
-        const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
-        return fNormRotation == normalMapFP.fNormRotation;
-    }
-
-    SkVector fNormRotation;
-};
-
-sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
-                                                     GrContext *context,
-                                                     const SkMatrix &viewM,
-                                                     const SkMatrix *localMatrix,
-                                                     SkFilterQuality filterQuality,
-                                                     SkSourceGammaTreatment gammaTreatment) const {
-
-    sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM,
-            localMatrix, filterQuality, gammaTreatment);
-
-    return sk_make_sp<NormalMapFP>(std::move(mapFP), fNormRotation);
-}
-
-#endif // SK_SUPPORT_GPU
-
-////////////////////////////////////////////////////////////////////////////
-
-NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source,
-                                        SkShader::Context* mapContext)
-    : fSource(source)
-    , fMapContext(mapContext) {
-}
-
-NormalMapSourceImpl::Provider::~Provider() {
-    fMapContext->~Context();
-}
-
-SkNormalSource::Provider* NormalMapSourceImpl::asProvider(
-        const SkShader::ContextRec &rec, void *storage) const {
-    SkMatrix normTotalInv;
-    if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
-        return nullptr;
-    }
-
-    void* mapContextStorage = (char*)storage + sizeof(Provider);
-    SkShader::Context* context = fMapShader->createContext(rec, mapContextStorage);
-    if (!context) {
-        return nullptr;
-    }
-
-    return new (storage) Provider(*this, context);
-}
-
-size_t NormalMapSourceImpl::providerSize(const SkShader::ContextRec& rec) const {
-    return sizeof(Provider) + fMapShader->contextSize(rec);
-}
-
-bool NormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec,
-                                                  SkMatrix* normTotalInverse) const {
-    SkMatrix total;
-    total.setConcat(*rec.fMatrix, fMapShader->getLocalMatrix());
-
-    const SkMatrix* m = &total;
-    if (rec.fLocalMatrix) {
-        total.setConcat(*m, *rec.fLocalMatrix);
-        m = &total;
-    }
-    return m->invert(normTotalInverse);
-}
-
-#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);
-
-        fMapContext->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.fNormRotation.fX * tempNorm.fX +
-                           fSource.fNormRotation.fY * tempNorm.fY;
-            output[i].fY = -fSource.fNormRotation.fY * tempNorm.fX +
-                           fSource.fNormRotation.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> mapShader = buf.readFlattenable<SkShader>();
-
-    SkVector normRotation = {1,0};
-    if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
-        normRotation = buf.readPoint();
-    }
-
-    return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), normRotation);
-}
-
-void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
-    this->INHERITED::flatten(buf);
-
-    buf.writeFlattenable(fMapShader.get());
-    buf.writePoint(fNormRotation);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map,
-                                                        const SkVector &normRotation) {
-    SkASSERT(SkScalarNearlyEqual(normRotation.lengthSqd(), SK_Scalar1));
-    if (!map) {
-        return nullptr;
-    }
-
-    return sk_make_sp<NormalMapSourceImpl>(std::move(map), normRotation);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource)
-    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-
-////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkNormalSource.h b/src/core/SkNormalSource.h
deleted file mode 100644 (file)
index 0d0c672..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkNormalSource_DEFINED
-#define SkNormalSource_DEFINED
-
-#include "SkFlattenable.h"
-
-/** Abstract class that generates or reads in normals for use by SkLightingShader. Not to be
-    used as part of the API yet. Used internally by SkLightingShader.
-*/
-class SK_API SkNormalSource : public SkFlattenable {
-public:
-    virtual ~SkNormalSource() override;
-
-#if SK_SUPPORT_GPU
-    /** Returns a fragment processor that takes no input and outputs a normal (already rotated)
-        as its output color. To be used as a child fragment processor.
-    */
-    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(
-            GrContext* context,
-            const SkMatrix& viewM,
-            const SkMatrix* localMatrix,
-            SkFilterQuality filterQuality,
-            SkSourceGammaTreatment gammaTreatment) const = 0;
-#endif
-
-    class Provider {
-    public:
-        virtual ~Provider() {};
-
-        /** Called for each span of the object being drawn on the CPU. Your subclass should set
-            the appropriate normals that correspond to the specified device coordinates.
-        */
-        virtual void fillScanLine(int x, int y, SkPoint3 output[], int count) const = 0;
-    };
-
-    /** Returns an instance of 'Provider' that provides normals for the CPU pipeline. The
-        necessary data will be initialized in place at 'storage'.
-    */
-    virtual Provider* asProvider(const SkShader::ContextRec&, void* storage) const = 0;
-
-    /** Amount of memory needed to store a provider object and its dependencies.
-     */
-    virtual size_t providerSize(const SkShader::ContextRec&) const = 0;
-
-    /** Returns a normal source that provides normals sourced from the the normal map argument.
-        Not to be used as part of the API yet. Used internally by SkLightingShader.
-
-        @param  map              a shader that outputs the normal map
-        @param  normRotation     rotation applied to the normal map's normals, in the
-                                 [cos a, sin a] form.
-
-        nullptr will be returned if 'map' is null
-
-        The normal map is currently assumed to be an 8888 image where the normal at a texel
-        is retrieved by:
-            N.x = R-127;
-            N.y = G-127;
-            N.z = B-127;
-            N.normalize();
-        The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
-        (127, 127, 0).
-    */
-    static sk_sp<SkNormalSource> MakeFromNormalMap(sk_sp<SkShader> map,
-                                                   const SkVector& normRotation);
-
-    SK_DEFINE_FLATTENABLE_TYPE(SkNormalSource)
-    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-};
-
-#endif
index cc697ce0bae23fd7c4507a200aa9e6cf56856f6e..933973eb93a5668f018f76a61de4981610dc26a8 100644 (file)
@@ -36,7 +36,6 @@
 #include "SkMatrixConvolutionImageFilter.h"
 #include "SkMergeImageFilter.h"
 #include "SkMorphologyImageFilter.h"
-#include "SkNormalSource.h"
 #include "SkOffsetImageFilter.h"
 #include "SkPaintImageFilter.h"
 #include "SkPerlinNoiseShader.h"
@@ -88,7 +87,7 @@ void SkFlattenable::PrivateInitializer::InitEffects() {
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader)
     SkGradientShader::InitializeFlattenables();
     SkLightingShader::InitializeFlattenables();
-    SkNormalSource::InitializeFlattenables();
+    SkLightingShader::NormalSource::InitializeFlattenables();
 
 
     // PathEffect