1/* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17uniform shader texture; 18uniform shader lut; 19uniform float intensity; 20/* 21 * The LUT cube size, in pixels (depth, width and height). If we use the OpenGL coordinate 22 * system (right-handed, Y-up, X-right, negative Z-forward), each direction represents a color change: 23 * - Right changes (width) are related to red changes. 24 * - Up changes (height) are related to blue changes. 25 * - Forward changes (depth) are related to green changes. 26 */ 27const float LUT_CUBE_SIZE = 32.0; 28 29/* 30 * Each height unit of the LUT cube is sliced into an LUT_CUBE_SIZE x LUT_CUBE_SIZE image; 31 * then all the images are concatenated on the texture image width. Thus, the image height 32 * is LUT_CUBE_SIZE and the width is LUT_CUBE_SIZE x LUT_CUBE_SIZE. Each slice will have a 33 * different blue value, and inside each slice, vertical direction means green color changes and 34 * horizontal direction means red color changes. 35 */ 36const float IMAGE_WIDTH = LUT_CUBE_SIZE * LUT_CUBE_SIZE; 37 38// The last slice first pixel index. 39const float LAST_SLICE_FIRST_IDX = IMAGE_WIDTH - LUT_CUBE_SIZE; 40 41// The last pixel index of a slice. 42const float SLICE_LAST_IDX = LUT_CUBE_SIZE - 1.; 43const float SLICE_LAST_IDX_INV = 1. / SLICE_LAST_IDX; 44 45// Applies lut, pass in texture color to apply to. 46vec4 main(float2 fragCoord) { 47 vec4 color = texture.eval(fragCoord); 48 49 /* 50 * When we fetch the new color on the LUT cube, each color can fall in between two values 51 * (pixels) which might not be one next to each other. we need to calculate both values and 52 * interpolate. 53 */ 54 vec3 colorTmp = color.rgb * SLICE_LAST_IDX; 55 56 // Calculate the floor UVs. 57 vec3 colorFloor = floor(colorTmp) * SLICE_LAST_IDX_INV; 58 ivec2 uvFloor = ivec2( 59 int(colorFloor.b * LAST_SLICE_FIRST_IDX + colorFloor.r * SLICE_LAST_IDX), 60 int(colorFloor.g * SLICE_LAST_IDX) 61 ); 62 63 // Calculate the ceil UVs. 64 vec3 colorCeil = ceil(colorTmp) * SLICE_LAST_IDX_INV; 65 ivec2 uvCeil = ivec2( 66 int(colorCeil.b * LAST_SLICE_FIRST_IDX + colorCeil.r * SLICE_LAST_IDX), 67 int(colorCeil.g * SLICE_LAST_IDX) 68 ); 69 70 /* 71 * Fetch the color from the LUT, and combine both floor and ceiling options based on the 72 * fractional part. 73 */ 74 vec4 colorAfterLut = vec4(0., 0., 0., color.a); 75 colorAfterLut.rgb = mix( 76 lut.eval(vec2(uvFloor.x, uvFloor.y)).rgb, 77 lut.eval(vec2(uvCeil.x, uvCeil.y)).rgb, 78 fract(colorTmp) 79 ); 80 81 return mix(color, colorAfterLut, intensity); 82} 83