| Index: src/core/SkLightingShader.cpp
|
| diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp
|
| index 473028105a9c5a295b90dd438a43a3c6be0af353..b40f4a725b0129ee6261d6357edd831f55ff5f47 100644
|
| --- a/src/core/SkLightingShader.cpp
|
| +++ b/src/core/SkLightingShader.cpp
|
| @@ -41,18 +41,22 @@
|
| */
|
| class SkLightingShaderImpl : public SkShader {
|
| public:
|
| +
|
| /** Create a new lighting shader that uses the provided normal map and
|
| lights to light the diffuse bitmap.
|
| - @param diffuseShader the shader that provides the diffuse colors
|
| + @param diffuse the diffuse bitmap
|
| + @param lights the lights applied to the normal map
|
| + @param diffLocalM the local matrix for the diffuse coordinates
|
| @param normalSource the source of normals for lighting computation
|
| - @param lights the lights applied to the geometry
|
| */
|
| - SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,
|
| - sk_sp<SkNormalSource> normalSource,
|
| - const sk_sp<SkLights> lights)
|
| - : fDiffuseShader(std::move(diffuseShader))
|
| - , fNormalSource(std::move(normalSource))
|
| - , fLights(std::move(lights)) {}
|
| + SkLightingShaderImpl(const SkBitmap& diffuse,
|
| + const sk_sp<SkLights> lights,
|
| + const SkMatrix* diffLocalM,
|
| + sk_sp<SkNormalSource> normalSource)
|
| + : INHERITED(diffLocalM)
|
| + , fDiffuseMap(diffuse)
|
| + , fLights(std::move(lights))
|
| + , fNormalSource(std::move(normalSource)) {}
|
|
|
| bool isOpaque() const override;
|
|
|
| @@ -69,9 +73,8 @@
|
| // The context takes ownership of the states. It will call their destructors
|
| // but will NOT free the memory.
|
| LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
|
| - SkShader::Context* diffuseContext, SkNormalSource::Provider*,
|
| + SkBitmapProcState* diffuseState, SkNormalSource::Provider*,
|
| void* heapAllocated);
|
| -
|
| ~LightingShaderContext() override;
|
|
|
| void shadeSpan(int x, int y, SkPMColor[], int count) override;
|
| @@ -79,7 +82,7 @@
|
| uint32_t getFlags() const override { return fFlags; }
|
|
|
| private:
|
| - SkShader::Context* fDiffuseContext;
|
| + SkBitmapProcState* fDiffuseState;
|
| SkNormalSource::Provider* fNormalProvider;
|
| uint32_t fFlags;
|
|
|
| @@ -97,9 +100,10 @@
|
| Context* onCreateContext(const ContextRec&, void*) const override;
|
|
|
| private:
|
| - sk_sp<SkShader> fDiffuseShader;
|
| + SkBitmap fDiffuseMap;
|
| + sk_sp<SkLights> fLights;
|
| +
|
| sk_sp<SkNormalSource> fNormalSource;
|
| - sk_sp<SkLights> fLights;
|
|
|
| friend class SkLightingShader;
|
|
|
| @@ -123,7 +127,12 @@
|
|
|
| class LightingFP : public GrFragmentProcessor {
|
| public:
|
| - LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights) {
|
| + LightingFP(GrTexture* diffuse, const SkMatrix& diffMatrix, const GrTextureParams& diffParams,
|
| + sk_sp<SkLights> lights, sk_sp<GrFragmentProcessor> normalFP)
|
| + : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode())
|
| + , fDiffuseTextureAccess(diffuse, diffParams) {
|
| + this->addCoordTransform(&fDiffDeviceTransform);
|
| + this->addTextureAccess(&fDiffuseTextureAccess);
|
|
|
| // fuse all ambient lights into a single one
|
| fAmbientColor.set(0.0f, 0.0f, 0.0f);
|
| @@ -170,7 +179,11 @@
|
| kVec3f_GrSLType, kDefault_GrSLPrecision,
|
| "AmbientColor", &ambientColorUniName);
|
|
|
| - fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor);
|
| + fragBuilder->codeAppend("vec4 diffuseColor = ");
|
| + fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0],
|
| + args.fCoords[0].c_str(),
|
| + args.fCoords[0].getType());
|
| + fragBuilder->codeAppend(";");
|
|
|
| SkString dstNormalName("dstNormal");
|
| this->emitChild(0, nullptr, &dstNormalName, args);
|
| @@ -245,17 +258,44 @@
|
|
|
| bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
| const LightingFP& lightingFP = proc.cast<LightingFP>();
|
| - return fLightDir == lightingFP.fLightDir &&
|
| + return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform &&
|
| + fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess &&
|
| + fLightDir == lightingFP.fLightDir &&
|
| fLightColor == lightingFP.fLightColor &&
|
| fAmbientColor == lightingFP.fAmbientColor;
|
| }
|
|
|
| + GrCoordTransform fDiffDeviceTransform;
|
| + GrTextureAccess fDiffuseTextureAccess;
|
| SkVector3 fLightDir;
|
| SkColor3f fLightColor;
|
| SkColor3f fAmbientColor;
|
| };
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
| +
|
| +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> SkLightingShaderImpl::asFragmentProcessor(
|
| GrContext* context,
|
| @@ -263,15 +303,37 @@
|
| 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<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDiffuseMap,
|
| + diffParams, gammaTreatment));
|
| + if (!diffuseTexture) {
|
| + SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
| + return nullptr;
|
| + }
|
| +
|
| sk_sp<GrFragmentProcessor> normalFP(
|
| fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filterQuality,
|
| gammaTreatment));
|
| - sk_sp<GrFragmentProcessor> fpPipeline[] = {
|
| - fDiffuseShader->asFragmentProcessor(context, viewM, localMatrix, filterQuality,
|
| - gammaTreatment),
|
| - sk_make_sp<LightingFP>(std::move(normalFP), fLights)
|
| - };
|
| - sk_sp<GrFragmentProcessor> inner(GrFragmentProcessor::RunInSeries(fpPipeline, 2));
|
| + sk_sp<GrFragmentProcessor> inner (
|
| + new LightingFP(diffuseTexture, diffM, diffParams, fLights, std::move(normalFP)));
|
|
|
| return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
| }
|
| @@ -281,18 +343,18 @@
|
| ////////////////////////////////////////////////////////////////////////////
|
|
|
| bool SkLightingShaderImpl::isOpaque() const {
|
| - return fDiffuseShader->isOpaque();
|
| + return fDiffuseMap.isOpaque();
|
| }
|
|
|
| SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
|
| - const SkLightingShaderImpl& shader, const ContextRec& rec,
|
| - SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
|
| - void* heapAllocated)
|
| + const SkLightingShaderImpl& shader, const ContextRec& rec, SkBitmapProcState* diffuseState,
|
| + SkNormalSource::Provider* normalProvider, void* heapAllocated)
|
| : INHERITED(shader, rec)
|
| - , fDiffuseContext(diffuseContext)
|
| + , fDiffuseState(diffuseState)
|
| , fNormalProvider(normalProvider)
|
| , fHeapAllocated(heapAllocated) {
|
| - bool isOpaque = shader.isOpaque();
|
| + const SkPixmap& pixmap = fDiffuseState->fPixmap;
|
| + bool isOpaque = pixmap.isOpaque();
|
|
|
| // update fFlags
|
| uint32_t flags = 0;
|
| @@ -304,9 +366,9 @@
|
| }
|
|
|
| SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() {
|
| - // 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();
|
| + // 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();
|
|
|
| sk_free(fHeapAllocated);
|
| @@ -336,23 +398,39 @@
|
|
|
| // 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 BUFFER_MAX 16
|
| +#define TMP_COUNT 16
|
| +#define BUFFER_MAX ((int)(TMP_COUNT * sizeof(uint32_t)))
|
| void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
|
| SkPMColor result[], int count) {
|
| const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
|
|
|
| - SkPMColor diffuse[BUFFER_MAX];
|
| + 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);
|
| SkPoint3 normals[BUFFER_MAX];
|
|
|
| do {
|
| - int n = SkTMin(count, BUFFER_MAX);
|
| -
|
| - fDiffuseContext->shadeSpan(x, y, diffuse, n);
|
| + int n = count;
|
| + if (n > max) {
|
| + n = max;
|
| + }
|
| +
|
| + diffMProc(*fDiffuseState, tmpColor, n, x, y);
|
| + diffSProc(*fDiffuseState, tmpColor, n, tmpColor2);
|
| +
|
| fNormalProvider->fillScanLine(x, y, normals, n);
|
|
|
| for (int i = 0; i < n; ++i) {
|
|
|
| - SkColor diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]);
|
| + SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[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)
|
| @@ -391,10 +469,19 @@
|
| #endif
|
|
|
| sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
|
| -
|
| - // Discarding SkShader flattenable params
|
| - bool hasLocalMatrix = buf.readBool();
|
| - SkAssertResult(!hasLocalMatrix);
|
| + SkMatrix diffLocalM;
|
| + bool hasDiffLocalM = buf.readBool();
|
| + if (hasDiffLocalM) {
|
| + buf.readMatrix(&diffLocalM);
|
| + } else {
|
| + diffLocalM.reset();
|
| + }
|
| +
|
| + SkBitmap diffuse;
|
| + if (!buf.readBitmap(&diffuse)) {
|
| + return nullptr;
|
| + }
|
| + diffuse.setImmutable();
|
|
|
| int numLights = buf.readInt();
|
|
|
| @@ -422,14 +509,15 @@
|
| sk_sp<SkLights> lights(builder.finish());
|
|
|
| sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
|
| - sk_sp<SkShader> diffuseShader(buf.readFlattenable<SkShader>());
|
| -
|
| - return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
|
| - std::move(lights));
|
| +
|
| + return sk_make_sp<SkLightingShaderImpl>(diffuse, std::move(lights), &diffLocalM,
|
| + std::move(normalSource));
|
| }
|
|
|
| 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) {
|
| @@ -445,7 +533,6 @@
|
| }
|
|
|
| buf.writeFlattenable(fNormalSource.get());
|
| - buf.writeFlattenable(fDiffuseShader.get());
|
| }
|
|
|
| size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const {
|
| @@ -454,27 +541,35 @@
|
|
|
| SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
|
| void* storage) const {
|
| - size_t heapRequired = fDiffuseShader->contextSize(rec) +
|
| - fNormalSource->providerSize(rec);
|
| +
|
| + 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);
|
| void* heapAllocated = sk_malloc_throw(heapRequired);
|
|
|
| - void* diffuseContextStorage = heapAllocated;
|
| - SkShader::Context* diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage);
|
| - if (!diffuseContext) {
|
| + 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();
|
| sk_free(heapAllocated);
|
| return nullptr;
|
| }
|
| -
|
| - void* normalProviderStorage = (char*)heapAllocated + fDiffuseShader->contextSize(rec);
|
| + void* normalProviderStorage = (char*)heapAllocated + sizeof(SkBitmapProcState);
|
| +
|
| SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec,
|
| normalProviderStorage);
|
| if (!normalProvider) {
|
| - diffuseContext->~Context();
|
| + diffuseState->~SkBitmapProcState();
|
| sk_free(heapAllocated);
|
| return nullptr;
|
| }
|
|
|
| - return new (storage) LightingShaderContext(*this, rec, diffuseContext, normalProvider,
|
| + return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider,
|
| heapAllocated);
|
| }
|
|
|
| @@ -493,12 +588,8 @@
|
| return nullptr;
|
| }
|
|
|
| - // TODO: support other tile modes
|
| - sk_sp<SkShader> diffuseShader = SkBitmapProcShader::MakeBitmapShader(diffuse,
|
| - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, diffLocalM);
|
| -
|
| - return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
|
| - std::move(lights));
|
| + return sk_make_sp<SkLightingShaderImpl>(diffuse, std::move(lights), diffLocalM,
|
| + std::move(normalSource));
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|