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

Side by Side Diff: src/effects/SkColorCubeFilter.cpp

Issue 580863004: Adding 3D lut color filter (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Update to ToT Created 6 years, 2 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 unified diff | Download patch
« no previous file with comments | « include/effects/SkColorCubeFilter.h ('k') | src/ports/SkGlobalInitialization_chromium.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkColorCubeFilter.h"
9 #include "SkColorPriv.h"
10 #include "SkOnce.h"
11 #include "SkReadBuffer.h"
12 #include "SkUnPreMultiply.h"
13 #include "SkWriteBuffer.h"
14 #if SK_SUPPORT_GPU
15 #include "GrContext.h"
16 #include "GrCoordTransform.h"
17 #include "gl/GrGLProcessor.h"
18 #include "gl/builders/GrGLProgramBuilder.h"
19 #include "GrTBackendProcessorFactory.h"
20 #include "GrTexturePriv.h"
21 #include "SkGr.h"
22 #endif
23
24 ///////////////////////////////////////////////////////////////////////////////
25 namespace {
26
27 int32_t SkNextColorProfileUniqueID() {
28 static int32_t gColorProfileUniqueID;
29 // do a loop in case our global wraps around, as we never want to return a 0
30 int32_t genID;
31 do {
32 genID = sk_atomic_inc(&gColorProfileUniqueID) + 1;
33 } while (0 == genID);
34 return genID;
35 }
36
37 } // end namespace
38
39 static const int MIN_CUBE_SIZE = 4;
40 static const int MAX_CUBE_SIZE = 64;
41
42 static bool is_valid_3D_lut(SkData* cubeData, int cubeDimension) {
43 size_t minMemorySize = sizeof(uint8_t) * 4 * cubeDimension * cubeDimension * cubeDimension;
44 return (cubeDimension >= MIN_CUBE_SIZE) && (cubeDimension <= MAX_CUBE_SIZE) &&
45 (NULL != cubeData) && (cubeData->size() >= minMemorySize);
46 }
47
48 SkColorFilter* SkColorCubeFilter::Create(SkData* cubeData, int cubeDimension) {
49 if (!is_valid_3D_lut(cubeData, cubeDimension)) {
50 return NULL;
51 }
52
53 return SkNEW_ARGS(SkColorCubeFilter, (cubeData, cubeDimension));
54 }
55
56 SkColorCubeFilter::SkColorCubeFilter(SkData* cubeData, int cubeDimension)
57 : fCubeData(SkRef(cubeData))
58 , fUniqueID(SkNextColorProfileUniqueID())
59 , fCache(cubeDimension) {
60 }
61
62 uint32_t SkColorCubeFilter::getFlags() const {
63 return this->INHERITED::getFlags() | kAlphaUnchanged_Flag;
64 }
65
66 SkColorCubeFilter::ColorCubeProcesingCache::ColorCubeProcesingCache(int cubeDime nsion)
67 : fCubeDimension(cubeDimension)
68 , fLutsInited(false) {
69 fColorToIndex[0] = fColorToIndex[1] = NULL;
70 fColorToFactors[0] = fColorToFactors[1] = NULL;
71 fColorToScalar = NULL;
72 }
73
74 void SkColorCubeFilter::ColorCubeProcesingCache::getProcessingLuts(
75 const int* (*colorToIndex)[2], const SkScalar* (*colorToFactors)[2],
76 const SkScalar** colorToScalar) {
77 SkOnce(&fLutsInited, &fLutsMutex,
78 SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts, this) ;
79 SkASSERT((fColorToIndex[0] != NULL) &&
80 (fColorToIndex[1] != NULL) &&
81 (fColorToFactors[0] != NULL) &&
82 (fColorToFactors[1] != NULL) &&
83 (fColorToScalar != NULL));
84 (*colorToIndex)[0] = fColorToIndex[0];
85 (*colorToIndex)[1] = fColorToIndex[1];
86 (*colorToFactors)[0] = fColorToFactors[0];
87 (*colorToFactors)[1] = fColorToFactors[1];
88 (*colorToScalar) = fColorToScalar;
89 }
90
91 void SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts(
92 SkColorCubeFilter::ColorCubeProcesingCache* cache) {
93 static const SkScalar inv8bit = SkScalarInvert(SkIntToScalar(255));
94
95 // We need 256 int * 2 for fColorToIndex, so a total of 512 int.
96 // We need 256 SkScalar * 2 for fColorToFactors and 256 SkScalar
97 // for fColorToScalar, so a total of 768 SkScalar.
98 cache->fLutStorage.reset(512 * sizeof(int) + 768 * sizeof(SkScalar));
99 uint8_t* storage = (uint8_t*)cache->fLutStorage.get();
100 cache->fColorToIndex[0] = (int*)storage;
101 cache->fColorToIndex[1] = cache->fColorToIndex[0] + 256;
102 cache->fColorToFactors[0] = (SkScalar*)(storage + (512 * sizeof(int)));
103 cache->fColorToFactors[1] = cache->fColorToFactors[0] + 256;
104 cache->fColorToScalar = cache->fColorToFactors[1] + 256;
105
106 SkScalar size = SkIntToScalar(cache->fCubeDimension);
107 SkScalar scale = (size - SK_Scalar1) * inv8bit;
108
109 for (int i = 0; i < 256; ++i) {
110 SkScalar index = scale * i;
111 cache->fColorToIndex[0][i] = SkScalarFloorToInt(index);
112 cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i] + 1;
113 cache->fColorToScalar[i] = inv8bit * i;
114 if (cache->fColorToIndex[1][i] < cache->fCubeDimension) {
115 cache->fColorToFactors[1][i] = index - SkIntToScalar(cache->fColorTo Index[0][i]);
116 cache->fColorToFactors[0][i] = SK_Scalar1 - cache->fColorToFactors[1 ][i];
117 } else {
118 cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i];
119 cache->fColorToFactors[0][i] = SK_Scalar1;
120 cache->fColorToFactors[1][i] = 0;
121 }
122 }
123 }
124
125 void SkColorCubeFilter::filterSpan(const SkPMColor src[], int count, SkPMColor d st[]) const {
126 const int* colorToIndex[2];
127 const SkScalar* colorToFactors[2];
128 const SkScalar* colorToScalar;
129 fCache.getProcessingLuts(&colorToIndex, &colorToFactors, &colorToScalar);
130
131 const int dim = fCache.cubeDimension();
132 SkColor* colorCube = (SkColor*)fCubeData->data();
133 for (int i = 0; i < count; ++i) {
134 SkColor inputColor = SkUnPreMultiply::PMColorToColor(src[i]);
135 uint8_t r = SkColorGetR(inputColor);
136 uint8_t g = SkColorGetG(inputColor);
137 uint8_t b = SkColorGetB(inputColor);
138 uint8_t a = SkColorGetA(inputColor);
139 SkScalar rOut(0), gOut(0), bOut(0);
140 for (int x = 0; x < 2; ++x) {
141 for (int y = 0; y < 2; ++y) {
142 for (int z = 0; z < 2; ++z) {
143 SkColor lutColor = colorCube[colorToIndex[x][r] +
144 (colorToIndex[y][g] +
145 colorToIndex[z][b] * dim) * dim ];
146 SkScalar factor = colorToFactors[x][r] *
147 colorToFactors[y][g] *
148 colorToFactors[z][b];
149 rOut += colorToScalar[SkColorGetR(lutColor)] * factor;
150 gOut += colorToScalar[SkColorGetG(lutColor)] * factor;
151 bOut += colorToScalar[SkColorGetB(lutColor)] * factor;
152 }
153 }
154 }
155 const SkScalar aOut = SkIntToScalar(a);
156 dst[i] = SkPackARGB32(a,
157 SkScalarRoundToInt(rOut * aOut),
158 SkScalarRoundToInt(gOut * aOut),
159 SkScalarRoundToInt(bOut * aOut));
160 }
161 }
162
163 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
164 SkColorCubeFilter::SkColorCubeFilter(SkReadBuffer& buffer)
165 : fCache(buffer.readInt()) {
166 fCubeData.reset(buffer.readByteArrayAsData());
167 buffer.validate(is_valid_3D_lut(fCubeData, fCache.cubeDimension()));
168 fUniqueID = SkNextColorProfileUniqueID();
169 }
170 #endif
171
172 SkFlattenable* SkColorCubeFilter::CreateProc(SkReadBuffer& buffer) {
173 int cubeDimension = buffer.readInt();
174 SkData* cubeData = buffer.readByteArrayAsData();
175 if (!buffer.validate(is_valid_3D_lut(cubeData, cubeDimension))) {
176 SkSafeUnref(cubeData);
177 return NULL;
178 }
179 return Create(cubeData, cubeDimension);
180 }
181
182 void SkColorCubeFilter::flatten(SkWriteBuffer& buffer) const {
183 this->INHERITED::flatten(buffer);
184 buffer.writeInt(fCache.cubeDimension());
185 buffer.writeDataAsByteArray(fCubeData);
186 }
187
188 #ifndef SK_IGNORE_TO_STRING
189 void SkColorCubeFilter::toString(SkString* str) const {
190 str->append("SkColorCubeFilter ");
191 }
192 #endif
193
194 ///////////////////////////////////////////////////////////////////////////////
195 #if SK_SUPPORT_GPU
196 class GrColorProfileEffect : public GrFragmentProcessor {
197 public:
198 static GrFragmentProcessor* Create(GrTexture* colorCube) {
199 return (NULL != colorCube) ? SkNEW_ARGS(GrColorProfileEffect, (colorCube )) : NULL;
200 }
201
202 virtual ~GrColorProfileEffect();
203
204 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERR IDE;
205 int colorCubeSize() const { return fColorCubeAccess.getTexture()->width(); }
206
207 static const char* Name() { return "ColorProfile"; }
208
209 virtual void onComputeInvariantOutput(GrProcessor::InvariantOutput*) const S K_OVERRIDE;
210
211 class GLProcessor : public GrGLFragmentProcessor {
212 public:
213 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor& );
214 virtual ~GLProcessor();
215
216 virtual void emitCode(GrGLProgramBuilder*,
217 const GrFragmentProcessor&,
218 const GrProcessorKey&,
219 const char* outputColor,
220 const char* inputColor,
221 const TransformedCoordsArray&,
222 const TextureSamplerArray&) SK_OVERRIDE;
223
224 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcess orKeyBuilder*);
225
226 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
227
228 private:
229 GrGLProgramDataManager::UniformHandle fColorCubeSizeUni;
230 GrGLProgramDataManager::UniformHandle fColorCubeInvSizeUni;
231
232 typedef GrGLFragmentProcessor INHERITED;
233 };
234
235 private:
236 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
237
238 GrColorProfileEffect(GrTexture* colorCube);
239
240 GrCoordTransform fColorCubeTransform;
241 GrTextureAccess fColorCubeAccess;
242
243 typedef GrFragmentProcessor INHERITED;
244 };
245
246 ///////////////////////////////////////////////////////////////////////////////
247
248 GrColorProfileEffect::GrColorProfileEffect(GrTexture* colorCube)
249 : fColorCubeTransform(kLocal_GrCoordSet, colorCube)
250 , fColorCubeAccess(colorCube, "bgra", GrTextureParams::kBilerp_FilterMode) {
251 this->addCoordTransform(&fColorCubeTransform);
252 this->addTextureAccess(&fColorCubeAccess);
253 }
254
255 GrColorProfileEffect::~GrColorProfileEffect() {
256 }
257
258 bool GrColorProfileEffect::onIsEqual(const GrProcessor& sBase) const {
259 const GrColorProfileEffect& s = sBase.cast<GrColorProfileEffect>();
260 return fColorCubeAccess.getTexture() == s.fColorCubeAccess.getTexture();
261 }
262
263 const GrBackendFragmentProcessorFactory& GrColorProfileEffect::getFactory() cons t {
264 return GrTBackendFragmentProcessorFactory<GrColorProfileEffect>::getInstance ();
265 }
266
267 void GrColorProfileEffect::onComputeInvariantOutput(InvariantOutput* inout) cons t {
268 inout->fValidFlags = 0;
269 inout->fIsSingleComponent = false;
270 }
271
272 ///////////////////////////////////////////////////////////////////////////////
273
274 GrColorProfileEffect::GLProcessor::GLProcessor(const GrBackendProcessorFactory& factory,
275 const GrProcessor&)
276 : INHERITED(factory) {
277 }
278
279 GrColorProfileEffect::GLProcessor::~GLProcessor() {
280 }
281
282 void GrColorProfileEffect::GLProcessor::emitCode(GrGLProgramBuilder* builder,
283 const GrFragmentProcessor&,
284 const GrProcessorKey&,
285 const char* outputColor,
286 const char* inputColor,
287 const TransformedCoordsArray& c oords,
288 const TextureSamplerArray& samp lers) {
289 if (NULL == inputColor) {
290 inputColor = "vec4(1)";
291 }
292
293 fColorCubeSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibi lity,
294 kFloat_GrSLType, "Size");
295 const char* colorCubeSizeUni = builder->getUniformCStr(fColorCubeSizeUni);
296 fColorCubeInvSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vis ibility,
297 kFloat_GrSLType, "InvSize");
298 const char* colorCubeInvSizeUni = builder->getUniformCStr(fColorCubeInvSizeU ni);
299
300 const char* nonZeroAlpha = "nonZeroAlpha";
301 const char* unPMColor = "unPMColor";
302 const char* cubeIdx = "cubeIdx";
303 const char* cCoords1 = "cCoords1";
304 const char* cCoords2 = "cCoords2";
305
306 // Note: if implemented using texture3D in OpenGL ES older than OpenGL ES 3. 0,
307 // the shader might need "#extension GL_OES_texture_3D : enable".
308
309 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
310
311 // Unpremultiply color
312 fsBuilder->codeAppendf("\tfloat %s = max(%s.a, 0.00001);\n", nonZeroAlpha, i nputColor);
313 fsBuilder->codeAppendf("\tvec4 %s = vec4(%s.rgb / %s, %s);\n",
314 unPMColor, inputColor, nonZeroAlpha, nonZeroAlpha);
315
316 // Fit input color into the cube.
317 fsBuilder->codeAppendf(
318 "vec3 %s = vec3(%s.rg * vec2((%s - 1.0) * %s) + vec2(0.5 * %s), %s.b * ( %s - 1.0));\n",
319 cubeIdx, unPMColor, colorCubeSizeUni, colorCubeInvSizeUni, colorCubeInvS izeUni,
320 unPMColor, colorCubeSizeUni);
321
322 // Compute y coord for for texture fetches.
323 fsBuilder->codeAppendf("vec2 %s = vec2(%s.r, (floor(%s.b) + %s.g) * %s);\n",
324 cCoords1, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSize Uni);
325 fsBuilder->codeAppendf("vec2 %s = vec2(%s.r, (ceil(%s.b) + %s.g) * %s);\n",
326 cCoords2, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSize Uni);
327
328 // Apply the cube.
329 fsBuilder->codeAppendf("%s = vec4(mix(", outputColor);
330 fsBuilder->appendTextureLookup(samplers[0], cCoords1, coords[0].getType());
331 fsBuilder->codeAppend(".rgb, ");
332 fsBuilder->appendTextureLookup(samplers[0], cCoords2, coords[0].getType());
333
334 // Premultiply color by alpha. Note that the input alpha is not modified by this shader.
335 fsBuilder->codeAppendf(".rgb, fract(%s.b)) * vec3(%s), %s.a);\n",
336 cubeIdx, nonZeroAlpha, inputColor);
337 }
338
339 void GrColorProfileEffect::GLProcessor::setData(const GrGLProgramDataManager& pd man,
340 const GrProcessor& proc) {
341 const GrColorProfileEffect& colorProfile = proc.cast<GrColorProfileEffect>() ;
342 SkScalar size = SkIntToScalar(colorProfile.colorCubeSize());
343 pdman.set1f(fColorCubeSizeUni, SkScalarToFloat(size));
344 pdman.set1f(fColorCubeInvSizeUni, SkScalarToFloat(SkScalarInvert(size)));
345 }
346
347 void GrColorProfileEffect::GLProcessor::GenKey(const GrProcessor& proc,
348 const GrGLCaps&, GrProcessorKeyBu ilder* b) {
349 b->add32(1); // Always same shader for now
350 }
351
352 GrFragmentProcessor* SkColorCubeFilter::asFragmentProcessor(GrContext* context) const {
353 static const GrCacheID::Domain gCubeDomain = GrCacheID::GenerateDomain();
354
355 GrCacheID::Key key;
356 key.fData32[0] = fUniqueID;
357 key.fData32[1] = fCache.cubeDimension();
358 key.fData64[1] = 0;
359 GrCacheID cacheID(gCubeDomain, key);
360
361 GrTextureDesc desc;
362 desc.fWidth = fCache.cubeDimension();
363 desc.fHeight = fCache.cubeDimension() * fCache.cubeDimension();
364 desc.fConfig = kRGBA_8888_GrPixelConfig;
365
366 SkAutoTUnref<GrTexture> textureCube(
367 static_cast<GrTexture*>(context->findAndRefCachedResource(
368 GrTexturePriv::ComputeKey(context->getGpu(), NULL, desc, cacheID)))) ;
369
370 if (!textureCube) {
371 textureCube.reset(context->createTexture(NULL, desc, cacheID, fCubeData- >data(), 0));
372 }
373
374 return textureCube ? GrColorProfileEffect::Create(textureCube) : NULL;
375 }
376 #endif
OLDNEW
« no previous file with comments | « include/effects/SkColorCubeFilter.h ('k') | src/ports/SkGlobalInitialization_chromium.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698