Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Unified Diff: src/effects/SkColorProfileFilter.cpp

Issue 580863004: Adding 3D lut color filter (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Added generationID for 3D texture key Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/effects/SkColorProfileFilter.cpp
diff --git a/src/effects/SkColorProfileFilter.cpp b/src/effects/SkColorProfileFilter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e1f3ba7d92aab7d3b4222ffb90f18ec0fe5864b
--- /dev/null
+++ b/src/effects/SkColorProfileFilter.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorProfileFilter.h"
+#include "SkColorPriv.h"
+#include "SkReadBuffer.h"
+#include "SkUnPreMultiply.h"
+#include "SkWriteBuffer.h"
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrCoordTransform.h"
+#include "gl/GrGLProcessor.h"
+#include "gl/builders/GrGLProgramBuilder.h"
+#include "GrTBackendProcessorFactory.h"
+#include "SkGr.h"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace {
+
+int32_t SkNextColorProfileGenerationID() {
sugoi1 2014/09/25 21:27:46 Added SkNextColorProfileGenerationID(), similar to
+ static int32_t gColorProfileGenerationID;
+ // do a loop in case our global wraps around, as we never want to return a 0
+ int32_t genID;
+ do {
+ genID = sk_atomic_inc(&gColorProfileGenerationID) + 1;
+ } while (0 == genID);
+ return genID;
+}
+
+} // end namespace
+
+static const int MIN_CUBE_SIZE = 4;
+static const int MAX_CUBE_SIZE = 64;
+
+static bool is_valid_3D_lut(SkData* cubeData, int cubeDimension) {
+ size_t minMemorySize = sizeof(uint8_t) * 4 * cubeDimension * cubeDimension * cubeDimension;
+ return (cubeDimension >= MIN_CUBE_SIZE) && (cubeDimension <= MAX_CUBE_SIZE) &&
+ (NULL != cubeData) && (cubeData->size() >= minMemorySize);
+}
+
+SkColorProfileFilter* SkColorProfileFilter::Create(SkData* cubeData, int cubeDimension) {
+ if (!is_valid_3D_lut(cubeData, cubeDimension)) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkColorProfileFilter, (cubeData, cubeDimension));
+}
+
+SkColorProfileFilter::SkColorProfileFilter(SkData* cubeData, int cubeDimension)
+ : fCubeData(cubeData)
+ , fCubeDimension(cubeDimension)
+ , fLutStorage(0) {
+ fCubeData->ref();
+ fColorToIndex[0] = fColorToIndex[1] = NULL;
+ fColorToFactors[0] = fColorToFactors[1] = NULL;
+ fGenerationID = SkNextColorProfileGenerationID();
+}
+
+SkColorProfileFilter::~SkColorProfileFilter() {
+ fCubeData->unref();
+}
+
+void SkColorProfileFilter::initProcessingLuts() {
+ SkAutoMutexAcquire ama(fInitMutex);
+ if ((fColorToIndex[0] != NULL) &&
+ (fColorToIndex[1] != NULL) &&
+ (fColorToFactors[0] != NULL) &&
+ (fColorToFactors[1] != NULL)) {
+ return;
+ }
+ fLutStorage.reset(512 * (sizeof(int) + sizeof(SkScalar)));
+ uint8_t* storage = (uint8_t*)fLutStorage.get();
+ fColorToIndex[0] = (int*)storage;
+ fColorToIndex[1] = fColorToIndex[0] + 256;
+ fColorToFactors[0] = (SkScalar*)(storage + (512 * sizeof(int)));
+ fColorToFactors[1] = fColorToFactors[0] + 256;
+
+ SkScalar size = SkIntToScalar(fCubeDimension);
+ SkScalar scale = SkScalarDiv((size - SK_Scalar1), 255.0f);
+
+ for (int i = 0; i < 256; ++i) {
+ SkScalar index = SkScalarMul(i, scale);
+ fColorToIndex[0][i] = SkScalarFloorToInt(index);
+ fColorToIndex[1][i] = fColorToIndex[0][i] + 1;
+ if (fColorToIndex[1][i] < fCubeDimension) {
+ fColorToFactors[1][i] = index - SkIntToScalar(fColorToIndex[0][i]);
+ fColorToFactors[0][i] = SK_Scalar1 - fColorToFactors[1][i];
+ } else {
+ fColorToIndex[1][i] = fColorToIndex[0][i];
+ fColorToFactors[0][i] = SK_Scalar1;
+ fColorToFactors[1][i] = 0;
+ }
+ }
+}
+
+void SkColorProfileFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
+ const_cast<SkColorProfileFilter*>(this)->initProcessingLuts();
+
+ SkPMColor* colorCube = (SkPMColor*)fCubeData->data();
+ for (int i = 0; i < count; ++i) {
+ SkColor inputColor = SkUnPreMultiply::PMColorToColor(src[i]);
+ uint8_t r = SkColorGetR(inputColor);
+ uint8_t g = SkColorGetG(inputColor);
+ uint8_t b = SkColorGetB(inputColor);
+ uint8_t a = SkColorGetA(inputColor);
+ SkScalar rOut(0), gOut(0), bOut(0);
+ for (int x = 0; x < 2; ++x) {
+ for (int y = 0; y < 2; ++y) {
+ for (int z = 0; z < 2; ++z) {
+ int rIndex = fColorToIndex[x][r];
+ int gIndex = fColorToIndex[y][g];
+ int bIndex = fColorToIndex[z][b];
+ SkScalar factor = SkScalarMul(fColorToFactors[x][r],
+ SkScalarMul(fColorToFactors[y][g],
+ fColorToFactors[z][b]));
+ SkPMColor lutColor =
+ colorCube[rIndex + (gIndex + bIndex * fCubeDimension) * fCubeDimension];
+ rOut += SkScalarMul(SkColorGetR(lutColor), factor);
+ gOut += SkScalarMul(SkColorGetG(lutColor), factor);
+ bOut += SkScalarMul(SkColorGetB(lutColor), factor);
+ }
+ }
+ }
+ dst[i] = SkPreMultiplyColor(SkColorSetARGB(a,
+ SkScalarRoundToInt(rOut),
+ SkScalarRoundToInt(gOut),
+ SkScalarRoundToInt(bOut)));
+ }
+}
+
+#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
+SkColorProfileFilter::SkColorProfileFilter(SkReadBuffer& buffer) {
+ fCubeDimension = buffer.readInt();
+ fCubeData = buffer.readByteArrayAsData();
+ buffer.validate(is_valid_3D_lut(fCubeData, fCubeDimension));
+ fGenerationID = SkNextColorProfileGenerationID();
+}
+#endif
+
+SkFlattenable* SkColorProfileFilter::CreateProc(SkReadBuffer& buffer) {
+ int cubeDimension = buffer.readInt();
+ SkData* cubeData = buffer.readByteArrayAsData();
+ if (!buffer.validate(is_valid_3D_lut(cubeData, cubeDimension))) {
+ SkSafeUnref(cubeData);
+ return NULL;
+ }
+ return Create(cubeData, cubeDimension);
+}
+
+void SkColorProfileFilter::flatten(SkWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeInt(fCubeDimension);
+ buffer.writeDataAsByteArray(fCubeData);
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkColorProfileFilter::toString(SkString* str) const {
+ str->append("SkColorProfileFilter ");
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#if SK_SUPPORT_GPU
+class GrColorProfileEffect : public GrFragmentProcessor {
+public:
+ static GrFragmentProcessor* Create(GrTexture* colorCube) {
+ return (NULL != colorCube) ? SkNEW_ARGS(GrColorProfileEffect, (colorCube)) : NULL;
+ }
+
+ virtual ~GrColorProfileEffect();
+
+ virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
+ int colorCubeSize() const { return fColorCubeAccess.getTexture()->width(); }
+
+ static const char* Name() { return "ColorProfile"; }
+
+ virtual void getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const SK_OVERRIDE;
+
+ class GLProcessor : public GrGLFragmentProcessor {
+ public:
+ GLProcessor(const GrBackendProcessorFactory& factory,
+ const GrProcessor&);
+ virtual ~GLProcessor();
+
+ virtual void emitCode(GrGLProgramBuilder*,
+ const GrFragmentProcessor&,
+ const GrProcessorKey&,
+ const char* outputColor,
+ const char* inputColor,
+ const TransformedCoordsArray&,
+ const TextureSamplerArray&) SK_OVERRIDE;
+
+ static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
+
+ virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
+
+ private:
+ GrGLProgramDataManager::UniformHandle fColorCubeOffsetUni;
+ GrGLProgramDataManager::UniformHandle fColorCubeScaleUni;
+
+ typedef GrGLFragmentProcessor INHERITED;
+ };
+
+private:
+ virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
+
+ GrColorProfileEffect(GrTexture* colorCube);
+
+ GrCoordTransform fColorCubeTransform;
+ GrTextureAccess fColorCubeAccess;
+
+ typedef GrFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrColorProfileEffect::GrColorProfileEffect(GrTexture* colorCube)
+ : fColorCubeTransform(kLocal_GrCoordSet, colorCube)
+ , fColorCubeAccess(colorCube, GrTextureParams::kBilerp_FilterMode) {
+ this->addCoordTransform(&fColorCubeTransform);
+ this->addTextureAccess(&fColorCubeAccess);
+}
+
+GrColorProfileEffect::~GrColorProfileEffect() {
+}
+
+bool GrColorProfileEffect::onIsEqual(const GrProcessor& sBase) const {
+ const GrColorProfileEffect& s = sBase.cast<GrColorProfileEffect>();
+ return fColorCubeAccess.getTexture() == s.fColorCubeAccess.getTexture();
+}
+
+const GrBackendFragmentProcessorFactory& GrColorProfileEffect::getFactory() const {
+ return GrTBackendFragmentProcessorFactory<GrColorProfileEffect>::getInstance();
+}
+
+void GrColorProfileEffect::getConstantColorComponents(GrColor*,
+ uint32_t* validFlags) const {
+ *validFlags = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrColorProfileEffect::GLProcessor::GLProcessor(const GrBackendProcessorFactory& factory,
+ const GrProcessor&)
+ : INHERITED(factory) {
+}
+
+GrColorProfileEffect::GLProcessor::~GLProcessor() {
+}
+
+void GrColorProfileEffect::GLProcessor::emitCode(GrGLProgramBuilder* builder,
+ const GrFragmentProcessor&,
+ const GrProcessorKey&,
+ const char* outputColor,
+ const char* inputColor,
+ const TransformedCoordsArray& coords,
+ const TextureSamplerArray& samplers) {
+ if (NULL == inputColor) {
+ inputColor = "vec4(1)";
+ }
+
+ fColorCubeOffsetUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+ kFloat_GrSLType, "Offset");
+ const char* colorCubeOffsetUni = builder->getUniformCStr(fColorCubeOffsetUni);
+ fColorCubeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+ kFloat_GrSLType, "Scale");
+ const char* colorCubeScaleUni = builder->getUniformCStr(fColorCubeScaleUni);
+
+ const char* cCoords = "cCoords";
+
+ GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+
+ // Fit input color into the cube
+ fsBuilder->codeAppendf("vec3 %s = %s.rgb * vec3(%s) + vec3(%s);\n",
+ cCoords, inputColor, colorCubeScaleUni, colorCubeOffsetUni);
+
+ // Apply the cube
+ fsBuilder->codeAppendf("%s = vec4(", outputColor);
+ fsBuilder->appendTextureLookup(samplers[0], cCoords, coords[0].getType());
+ fsBuilder->codeAppendf(".rgb, %s.a);\n", inputColor); // Alpha is not modified by this
+}
+
+void GrColorProfileEffect::GLProcessor::setData(const GrGLProgramDataManager& pdman,
+ const GrProcessor& proc) {
+ const GrColorProfileEffect& colorProfile = proc.cast<GrColorProfileEffect>();
+ SkScalar size = SkIntToScalar(colorProfile.colorCubeSize());
+ SkScalar invSize = SkScalarInvert(size);
+ pdman.set1f(fColorCubeOffsetUni, SkScalarToFloat(SkScalarHalf(invSize)));
+ pdman.set1f(fColorCubeScaleUni, SkScalarToFloat(SkScalarMul((size - SK_Scalar1), invSize)));
+}
+
+void GrColorProfileEffect::GLProcessor::GenKey(const GrProcessor& proc,
+ const GrGLCaps&, GrProcessorKeyBuilder* b) {
+ b->add32(1); // Always same shader for now
+}
+
+GrFragmentProcessor* SkColorProfileFilter::asFragmentProcessor(GrContext* context) const {
+ static const GrCacheID::Domain gCubeDomain = GrCacheID::GenerateDomain();
+
+ GrCacheID::Key key;
+ key.fData32[0] = fGenerationID;
+ key.fData32[1] = fCubeDimension;
+ GrCacheID cacheID(gCubeDomain, key);
+
+ GrTextureDesc desc;
+ desc.fWidth = desc.fHeight = desc.fDepth = fCubeDimension;
+ desc.fConfig = kBGRA_8888_GrPixelConfig;
+
+ SkAutoTUnref<GrTexture> textureCube(
+ static_cast<GrTexture*>(context->findAndRefCachedResource(
+ GrTextureImpl::ComputeKey(context->getGpu(), NULL, desc, cacheID))));
+
+ if (NULL == textureCube) {
+ textureCube.reset(context->createTexture(NULL, desc, cacheID, fCubeData->data(), 0));
+ }
+
+ return (NULL == textureCube) ? NULL : GrColorProfileEffect::Create(textureCube);
+}
+#endif

Powered by Google App Engine
This is Rietveld 408576698