From 3f58cd0eb8bf4499c4f179aa6111d7e005809df8 Mon Sep 17 00:00:00 2001 From: dvonbeck Date: Wed, 6 Jul 2016 20:03:46 -0700 Subject: Abstracted diffuse color map out of SkLightingShaderImpl into a generic SkShader Will not run until after landing https://codereview.chromium.org/2106893003/ This CL's base is the CL for the addition of NormalSource to the API: https://codereview.chromium.org/2063793002/ BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2062703003 Review-Url: https://codereview.chromium.org/2062703003 --- src/core/SkLightingShader.cpp | 205 ++++++++++++------------------------------ 1 file changed, 57 insertions(+), 148 deletions(-) (limited to 'src/core/SkLightingShader.cpp') diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp index b40f4a725b..473028105a 100644 --- a/src/core/SkLightingShader.cpp +++ b/src/core/SkLightingShader.cpp @@ -41,22 +41,18 @@ */ class SkLightingShaderImpl : public SkShader { public: - /** Create a new lighting shader that uses the provided normal map and lights to light the diffuse bitmap. - @param diffuse the diffuse bitmap - @param lights the lights applied to the normal map - @param diffLocalM the local matrix for the diffuse coordinates + @param diffuseShader the shader that provides the diffuse colors @param normalSource the source of normals for lighting computation + @param lights the lights applied to the geometry */ - SkLightingShaderImpl(const SkBitmap& diffuse, - const sk_sp lights, - const SkMatrix* diffLocalM, - sk_sp normalSource) - : INHERITED(diffLocalM) - , fDiffuseMap(diffuse) - , fLights(std::move(lights)) - , fNormalSource(std::move(normalSource)) {} + SkLightingShaderImpl(sk_sp diffuseShader, + sk_sp normalSource, + const sk_sp lights) + : fDiffuseShader(std::move(diffuseShader)) + , fNormalSource(std::move(normalSource)) + , fLights(std::move(lights)) {} bool isOpaque() const override; @@ -73,8 +69,9 @@ 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*, + SkShader::Context* diffuseContext, SkNormalSource::Provider*, void* heapAllocated); + ~LightingShaderContext() override; void shadeSpan(int x, int y, SkPMColor[], int count) override; @@ -82,7 +79,7 @@ public: uint32_t getFlags() const override { return fFlags; } private: - SkBitmapProcState* fDiffuseState; + SkShader::Context* fDiffuseContext; SkNormalSource::Provider* fNormalProvider; uint32_t fFlags; @@ -100,10 +97,9 @@ protected: Context* onCreateContext(const ContextRec&, void*) const override; private: - SkBitmap fDiffuseMap; - sk_sp fLights; - + sk_sp fDiffuseShader; sk_sp fNormalSource; + sk_sp fLights; friend class SkLightingShader; @@ -127,12 +123,7 @@ private: class LightingFP : public GrFragmentProcessor { public: - LightingFP(GrTexture* diffuse, const SkMatrix& diffMatrix, const GrTextureParams& diffParams, - sk_sp lights, sk_sp normalFP) - : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode()) - , fDiffuseTextureAccess(diffuse, diffParams) { - this->addCoordTransform(&fDiffDeviceTransform); - this->addTextureAccess(&fDiffuseTextureAccess); + LightingFP(sk_sp normalFP, sk_sp lights) { // fuse all ambient lights into a single one fAmbientColor.set(0.0f, 0.0f, 0.0f); @@ -179,11 +170,7 @@ public: kVec3f_GrSLType, kDefault_GrSLPrecision, "AmbientColor", &ambientColorUniName); - fragBuilder->codeAppend("vec4 diffuseColor = "); - fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0], - args.fCoords[0].c_str(), - args.fCoords[0].getType()); - fragBuilder->codeAppend(";"); + fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor); SkString dstNormalName("dstNormal"); this->emitChild(0, nullptr, &dstNormalName, args); @@ -258,15 +245,11 @@ private: bool onIsEqual(const GrFragmentProcessor& proc) const override { const LightingFP& lightingFP = proc.cast(); - return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform && - fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess && - fLightDir == lightingFP.fLightDir && + return fLightDir == lightingFP.fLightDir && fLightColor == lightingFP.fLightColor && fAmbientColor == lightingFP.fAmbientColor; } - GrCoordTransform fDiffDeviceTransform; - GrTextureAccess fDiffuseTextureAccess; SkVector3 fLightDir; SkColor3f fLightColor; SkColor3f fAmbientColor; @@ -274,66 +257,21 @@ private: //////////////////////////////////////////////////////////////////////////// -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 SkLightingShaderImpl::asFragmentProcessor( GrContext* context, const SkMatrix& viewM, const SkMatrix* localMatrix, SkFilterQuality filterQuality, SkSourceGammaTreatment gammaTreatment) const { - // we assume diffuse and normal maps have same width and height - // TODO: support different sizes, will be addressed when diffuse maps are factored out of - // SkLightingShader in a future CL - SkMatrix diffM; - - if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) { - return nullptr; - } - - bool doBicubic; - GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode( - SkTMin(filterQuality, kMedium_SkFilterQuality), - viewM, - this->getLocalMatrix(), - &doBicubic); - SkASSERT(!doBicubic); - - // TODO: support other tile modes - GrTextureParams diffParams(kClamp_TileMode, diffFilterMode); - SkAutoTUnref diffuseTexture(GrRefCachedBitmapTexture(context, fDiffuseMap, - diffParams, gammaTreatment)); - if (!diffuseTexture) { - SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); - return nullptr; - } - sk_sp normalFP( fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filterQuality, gammaTreatment)); - sk_sp inner ( - new LightingFP(diffuseTexture, diffM, diffParams, fLights, std::move(normalFP))); + sk_sp fpPipeline[] = { + fDiffuseShader->asFragmentProcessor(context, viewM, localMatrix, filterQuality, + gammaTreatment), + sk_make_sp(std::move(normalFP), fLights) + }; + sk_sp inner(GrFragmentProcessor::RunInSeries(fpPipeline, 2)); return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)); } @@ -343,18 +281,18 @@ sk_sp SkLightingShaderImpl::asFragmentProcessor( //////////////////////////////////////////////////////////////////////////// bool SkLightingShaderImpl::isOpaque() const { - return fDiffuseMap.isOpaque(); + return fDiffuseShader->isOpaque(); } SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( - const SkLightingShaderImpl& shader, const ContextRec& rec, SkBitmapProcState* diffuseState, - SkNormalSource::Provider* normalProvider, void* heapAllocated) + const SkLightingShaderImpl& shader, const ContextRec& rec, + SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider, + void* heapAllocated) : INHERITED(shader, rec) - , fDiffuseState(diffuseState) + , fDiffuseContext(diffuseContext) , fNormalProvider(normalProvider) , fHeapAllocated(heapAllocated) { - const SkPixmap& pixmap = fDiffuseState->fPixmap; - bool isOpaque = pixmap.isOpaque(); + bool isOpaque = shader.isOpaque(); // update fFlags uint32_t flags = 0; @@ -366,9 +304,9 @@ SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( } 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(); + // The dependencies have been created outside of the context on memory that was allocated by + // the onCreateContext() method. Call the destructors and free the memory. + fDiffuseContext->~Context(); fNormalProvider->~Provider(); sk_free(fHeapAllocated); @@ -398,39 +336,23 @@ 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 BUFFER_MAX 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]; - - SkBitmapProcState::MatrixProc diffMProc = fDiffuseState->getMatrixProc(); - SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32(); - - int max = fDiffuseState->maxCountForBufferSize(BUFFER_MAX); - - SkASSERT(fDiffuseState->fPixmap.addr()); - - SkASSERT(max <= BUFFER_MAX); + SkPMColor diffuse[BUFFER_MAX]; SkPoint3 normals[BUFFER_MAX]; do { - int n = count; - if (n > max) { - n = max; - } - - diffMProc(*fDiffuseState, tmpColor, n, x, y); - diffSProc(*fDiffuseState, tmpColor, n, tmpColor2); + int n = SkTMin(count, BUFFER_MAX); + fDiffuseContext->shadeSpan(x, y, diffuse, n); fNormalProvider->fillScanLine(x, y, normals, n); for (int i = 0; i < n; ++i) { - SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]); + SkColor diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]); SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); // This is all done in linear unpremul color space (each component 0..255.0f though) @@ -469,19 +391,10 @@ void SkLightingShaderImpl::toString(SkString* str) const { #endif sk_sp SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { - SkMatrix diffLocalM; - bool hasDiffLocalM = buf.readBool(); - if (hasDiffLocalM) { - buf.readMatrix(&diffLocalM); - } else { - diffLocalM.reset(); - } - SkBitmap diffuse; - if (!buf.readBitmap(&diffuse)) { - return nullptr; - } - diffuse.setImmutable(); + // Discarding SkShader flattenable params + bool hasLocalMatrix = buf.readBool(); + SkAssertResult(!hasLocalMatrix); int numLights = buf.readInt(); @@ -509,16 +422,15 @@ sk_sp SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { sk_sp lights(builder.finish()); sk_sp normalSource(buf.readFlattenable()); + sk_sp diffuseShader(buf.readFlattenable()); - return sk_make_sp(diffuse, std::move(lights), &diffLocalM, - std::move(normalSource)); + return sk_make_sp(std::move(diffuseShader), std::move(normalSource), + std::move(lights)); } void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { this->INHERITED::flatten(buf); - buf.writeBitmap(fDiffuseMap); - buf.writeInt(fLights->numLights()); for (int l = 0; l < fLights->numLights(); ++l) { const SkLights::Light& light = fLights->light(l); @@ -533,6 +445,7 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { } buf.writeFlattenable(fNormalSource.get()); + buf.writeFlattenable(fDiffuseShader.get()); } size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { @@ -541,35 +454,27 @@ size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, void* storage) const { - - SkMatrix diffTotalInv; - // computeTotalInverse was called in SkShader::createContext so we know it will succeed - SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv)); - - size_t heapRequired = sizeof(SkBitmapProcState) + fNormalSource->providerSize(rec); + size_t heapRequired = fDiffuseShader->contextSize(rec) + + fNormalSource->providerSize(rec); void* heapAllocated = sk_malloc_throw(heapRequired); - void* diffuseStateStorage = heapAllocated; - SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - SkMipMap::DeduceTreatment(rec)); - SkASSERT(diffuseState); - if (!diffuseState->setup(diffTotalInv, *rec.fPaint)) { - diffuseState->~SkBitmapProcState(); + void* diffuseContextStorage = heapAllocated; + SkShader::Context* diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage); + if (!diffuseContext) { sk_free(heapAllocated); return nullptr; } - void* normalProviderStorage = (char*)heapAllocated + sizeof(SkBitmapProcState); + void* normalProviderStorage = (char*)heapAllocated + fDiffuseShader->contextSize(rec); SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, normalProviderStorage); if (!normalProvider) { - diffuseState->~SkBitmapProcState(); + diffuseContext->~Context(); sk_free(heapAllocated); return nullptr; } - return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider, + return new (storage) LightingShaderContext(*this, rec, diffuseContext, normalProvider, heapAllocated); } @@ -588,8 +493,12 @@ sk_sp SkLightingShader::Make(const SkBitmap& diffuse, return nullptr; } - return sk_make_sp(diffuse, std::move(lights), diffLocalM, - std::move(normalSource)); + // TODO: support other tile modes + sk_sp diffuseShader = SkBitmapProcShader::MakeBitmapShader(diffuse, + SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, diffLocalM); + + return sk_make_sp(std::move(diffuseShader), std::move(normalSource), + std::move(lights)); } /////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3