From 2c80711f90a5dafe3b726bc6562b1e769702c34b Mon Sep 17 00:00:00 2001 From: dvonbeck Date: Mon, 27 Jun 2016 09:30:19 -0700 Subject: [PATCH] Revert of Refactoring of CPU NormalMap handling out into its own class (patchset #13 id:240001 of https://codereview.chromium.org/2050773002/ ) 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 | 3 +- include/core/SkFlattenable.h | 2 +- src/core/SkLightingShader.cpp | 111 ++++--- src/core/SkLightingShader.h | 57 +++- src/core/SkLightingShader_NormalSource.cpp | 290 ++++++++++++++++++ src/core/SkNormalSource.cpp | 294 ------------------- src/core/SkNormalSource.h | 76 ----- src/ports/SkGlobalInitialization_default.cpp | 3 +- 8 files changed, 417 insertions(+), 419 deletions(-) create mode 100644 src/core/SkLightingShader_NormalSource.cpp delete mode 100644 src/core/SkNormalSource.cpp delete mode 100644 src/core/SkNormalSource.h diff --git a/gyp/core.gypi b/gyp/core.gypi index 7c89960e66..516faf3095 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -154,6 +154,7 @@ '<(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', @@ -189,8 +190,6 @@ '<(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', diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h index 88aeb7ee38..5eabcb3d6d 100644 --- a/include/core/SkFlattenable.h +++ b/include/core/SkFlattenable.h @@ -81,7 +81,7 @@ public: kSkShader_Type, kSkUnused_Type, // used to be SkUnitMapper kSkXfermode_Type, - kSkNormalSource_Type, + kNormalSource_Type, }; typedef sk_sp (*Factory)(SkReadBuffer&); diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp index 52b208f8df..ca1c3417b4 100644 --- a/src/core/SkLightingShader.cpp +++ b/src/core/SkLightingShader.cpp @@ -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 lights, const SkVector& invNormRotation, const SkMatrix* diffLocalM, const SkMatrix* normLocalM, - sk_sp normalSource) + sk_sp 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 fNormalSource; + sk_sp 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(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 SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { invNormRotation = buf.readPoint(); } - sk_sp normalSource(buf.readFlattenable()); + sk_sp normalSource( + buf.readFlattenable()); return sk_make_sp(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 SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap& } SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); - // TODO: support other tile modes - sk_sp mapShader = SkMakeBitmapShader(normal, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, normLocalM, nullptr); - - sk_sp normalSource = SkNormalSource::MakeFromNormalMap(mapShader, - invNormRotation); + sk_sp normalSource = + SkLightingShader::NormalSource::MakeMap(normal, invNormRotation, normLocalM); return sk_make_sp(diffuse, normal, std::move(lights), invNormRotation, diffLocalM, normLocalM, std::move(normalSource)); diff --git a/src/core/SkLightingShader.h b/src/core/SkLightingShader.h index e21b94266e..c2b65472b9 100644 --- a/src/core/SkLightingShader.h +++ b/src/core/SkLightingShader.h @@ -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 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 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 index 0000000000..b96b1bf083 --- /dev/null +++ b/src/core/SkLightingShader_NormalSource.cpp @@ -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 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(); + } + + 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(); + + 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(); + 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 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 normalTexture(GrRefCachedBitmapTexture(context, + fNormalMap, + normParams, + gammaTreatment)); + if (!normalTexture) { + SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); + return nullptr; + } + + return sk_make_sp(normalTexture, normM, normParams, fInvNormRotation); +} + +#endif // SK_SUPPORT_GPU + +//////////////////////////////////////////////////////////////////////////// + +sk_sp 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(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::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(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 index 2f52530382..0000000000 --- a/src/core/SkNormalSource.cpp +++ /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 mapShader, const SkVector &normRotation) - : fMapShader(std::move(mapShader)) - , fNormRotation(normRotation) {} - -#if SK_SUPPORT_GPU - sk_sp 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 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 mapFP, const SkVector& normRotation) - : fNormRotation(normRotation) { - this->registerChildProcessor(mapFP); - - this->initClassID(); - } - - 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(); - - 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(); - return fNormRotation == normalMapFP.fNormRotation; - } - - SkVector fNormRotation; -}; - -sk_sp NormalMapSourceImpl::asFragmentProcessor( - GrContext *context, - const SkMatrix &viewM, - const SkMatrix *localMatrix, - SkFilterQuality filterQuality, - SkSourceGammaTreatment gammaTreatment) const { - - sk_sp mapFP = fMapShader->asFragmentProcessor(context, viewM, - localMatrix, filterQuality, gammaTreatment); - - return sk_make_sp(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 NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { - - sk_sp mapShader = buf.readFlattenable(); - - SkVector normRotation = {1,0}; - if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) { - normRotation = buf.readPoint(); - } - - return sk_make_sp(std::move(mapShader), normRotation); -} - -void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const { - this->INHERITED::flatten(buf); - - buf.writeFlattenable(fMapShader.get()); - buf.writePoint(fNormRotation); -} - -//////////////////////////////////////////////////////////////////////////// - -sk_sp SkNormalSource::MakeFromNormalMap(sk_sp map, - const SkVector &normRotation) { - SkASSERT(SkScalarNearlyEqual(normRotation.lengthSqd(), SK_Scalar1)); - if (!map) { - return nullptr; - } - - return sk_make_sp(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 index 0d0c672fa3..0000000000 --- a/src/core/SkNormalSource.h +++ /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 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 MakeFromNormalMap(sk_sp map, - const SkVector& normRotation); - - SK_DEFINE_FLATTENABLE_TYPE(SkNormalSource) - SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() -}; - -#endif diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp index cc697ce0ba..933973eb93 100644 --- a/src/ports/SkGlobalInitialization_default.cpp +++ b/src/ports/SkGlobalInitialization_default.cpp @@ -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 -- 2.34.1