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

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: As color filter instead of image filter 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..0302c280bd867302c37c56616a29995731158e34
--- /dev/null
+++ b/src/effects/SkColorProfileFilter.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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/GrGLEffect.h"
+#include "gl/builders/GrGLProgramBuilder.h"
+#include "GrTBackendEffectFactory.h"
+#include "SkGr.h"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const int MIN_CUBE_SIZE = 4;
+static const int MAX_CUBE_SIZE = 64;
+
+static bool is_valid_3D_lut(const SkBitmap& bitmap) {
+ int colorCubeSize = bitmap.width();
+ return bitmap.is3DLut() &&
+ (colorCubeSize >= MIN_CUBE_SIZE) &&
+ (colorCubeSize <= MAX_CUBE_SIZE);
+}
+
+SkColorProfileFilter* SkColorProfileFilter::Create(const SkBitmap& bitmap) {
+ if (!is_valid_3D_lut(bitmap)) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkColorProfileFilter, (bitmap));
+}
+
+SkColorProfileFilter::SkColorProfileFilter(const SkBitmap& bitmap)
+ : fColorCube(bitmap)
+ , fLutStorage(0)
+{
+ fColorToIndex[0] = fColorToIndex[1] = NULL;
+ fColorToFactors[0] = fColorToFactors[1] = NULL;
+}
+
+void SkColorProfileFilter::initProcessingLuts() {
+ 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;
+
+ int colorCubeSize = fColorCube.width();
+ SkScalar size = SkIntToScalar(colorCubeSize);
+ 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] < colorCubeSize) {
+ 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();
sugoi1 2014/09/24 19:38:42 Hi Mike and Brian, I have an issue here. initProce
+
+ SkAutoLockPixels alp(fColorCube);
+ if (!fColorCube.getPixels()) {
+ return;
+ }
+
+ int colorCubeSize = fColorCube.width();
+ 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 =
+ *fColorCube.getAddr32(rIndex, gIndex + colorCubeSize * bIndex);
+ 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) {
+ if (buffer.readBitmap(&fColorCube)) {
+ if (fColorCube.is3DLut()) {
+ fColorCube.setIs3DLut(true); // This will validate that the bitmap is a valid 3D lut
+ }
+ buffer.validate(is_valid_3D_lut(fColorCube));
+ }
+}
+#endif
+
+SkFlattenable* SkColorProfileFilter::CreateProc(SkReadBuffer& buffer) {
+ SkBitmap colorCube;
+ return buffer.readBitmap(&colorCube) ? Create(colorCube) : NULL;
+}
+
+void SkColorProfileFilter::flatten(SkWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeBitmap(fColorCube);
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkColorProfileFilter::toString(SkString* str) const {
+ str->append("SkColorProfileFilter ");
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+class GrGLColorProfileEffect : public GrGLEffect {
+public:
+ GrGLColorProfileEffect(const GrBackendEffectFactory& factory,
+ const GrEffect& effect);
+ virtual ~GrGLColorProfileEffect();
+
+ virtual void emitCode(GrGLProgramBuilder*,
+ const GrEffect&,
+ const GrEffectKey&,
+ const char* outputColor,
+ const char* inputColor,
+ const TransformedCoordsArray&,
+ const TextureSamplerArray&) SK_OVERRIDE;
+
+ static inline void GenKey(const GrEffect&, const GrGLCaps&, GrEffectKeyBuilder*);
+
+ virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
+
+private:
+ GrGLProgramDataManager::UniformHandle fColorCubeOffsetUni;
+ GrGLProgramDataManager::UniformHandle fColorCubeScaleUni;
+
+ typedef GrGLEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrColorProfileEffect : public GrEffect {
+public:
+ static GrEffect* Create(GrTexture* colorCube) {
+ return (NULL != colorCube) ? SkNEW_ARGS(GrColorProfileEffect, (colorCube)) : NULL;
+ }
+
+ virtual ~GrColorProfileEffect();
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+ int colorCubeSize() const { return fColorCubeAccess.getTexture()->width(); }
+
+ typedef GrGLColorProfileEffect GLEffect;
+ static const char* Name() { return "ColorProfile"; }
+
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+private:
+ virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
+
+ GrColorProfileEffect(GrTexture* colorCube);
+
+ GR_DECLARE_EFFECT_TEST;
+
+ GrCoordTransform fColorCubeTransform;
+ GrTextureAccess fColorCubeAccess;
+
+ typedef GrEffect 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 GrEffect& sBase) const {
+ const GrColorProfileEffect& s = sBase.cast<GrColorProfileEffect>();
+ return fColorCubeAccess.getTexture() == s.fColorCubeAccess.getTexture();
+}
+
+const GrBackendEffectFactory& GrColorProfileEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrColorProfileEffect>::getInstance();
+}
+
+void GrColorProfileEffect::getConstantColorComponents(GrColor*,
+ uint32_t* validFlags) const {
+ *validFlags = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrColorProfileEffect);
+
+GrEffect* GrColorProfileEffect::TestCreate(SkRandom* random,
+ GrContext*,
+ const GrDrawTargetCaps&,
+ GrTexture* textures[]) {
+ // FIXME: get a 3D texure in the test
+ return GrColorProfileEffect::Create(NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLColorProfileEffect::GrGLColorProfileEffect(const GrBackendEffectFactory& factory,
+ const GrEffect& effect)
+ : INHERITED(factory) {
+}
+
+GrGLColorProfileEffect::~GrGLColorProfileEffect() {
+}
+
+void GrGLColorProfileEffect::emitCode(GrGLProgramBuilder* builder,
+ const GrEffect&,
+ const GrEffectKey& key,
+ 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 GrGLColorProfileEffect::setData(const GrGLProgramDataManager& pdman,
+ const GrEffect& effect) {
+ const GrColorProfileEffect& colorProfile = effect.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 GrGLColorProfileEffect::GenKey(const GrEffect& effect,
+ const GrGLCaps&, GrEffectKeyBuilder* b) {
+ b->add32(1); // Always same shader for now
+}
+
+GrEffect* SkColorProfileFilter::asNewEffect(GrContext* context) const {
+ GrTexture* colorCubeTex = fColorCube.getTexture();
+ if (NULL == colorCubeTex) {
+ colorCubeTex = GrLockAndRefCachedBitmapTexture(context, fColorCube, NULL);
+ }
+ return (NULL == colorCubeTex) ? NULL : GrColorProfileEffect::Create(colorCubeTex);
+}
+#endif

Powered by Google App Engine
This is Rietveld 408576698