Implement GPU-side dither
[blender-staging.git] / intern / opencolorio / gpu_shader_display_transform.glsl
1 uniform sampler2D image_texture;
2 uniform sampler3D lut3d_texture;
3 uniform bool predivide;
4
5 #ifdef USE_DITHER
6 uniform float dither;
7 #endif
8
9 #ifdef USE_CURVE_MAPPING
10 /* Curve mapping parameters
11  *
12  * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
13  * (this ones pretyt much copies stuff from C structure.)
14  */
15 uniform sampler1D curve_mapping_texture;
16 uniform int curve_mapping_lut_size;
17 uniform ivec4 use_curve_mapping_extend_extrapolate;
18 uniform vec4 curve_mapping_mintable;
19 uniform vec4 curve_mapping_range;
20 uniform vec4 curve_mapping_ext_in_x;
21 uniform vec4 curve_mapping_ext_in_y;
22 uniform vec4 curve_mapping_ext_out_x;
23 uniform vec4 curve_mapping_ext_out_y;
24 uniform vec4 curve_mapping_first_x;
25 uniform vec4 curve_mapping_first_y;
26 uniform vec4 curve_mapping_last_x;
27 uniform vec4 curve_mapping_last_y;
28 uniform vec3 curve_mapping_black;
29 uniform vec3 curve_mapping_bwmul;
30
31 float read_curve_mapping(int table, int index)
32 {
33         /* TODO(sergey): Without -1 here image is getting darken after applying unite curve.
34          *               But is it actually correct to subtract 1 here?
35          */
36         float texture_index = float(index) / float(curve_mapping_lut_size  - 1);
37         return texture1D(curve_mapping_texture, texture_index) [table];
38 }
39
40 float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
41 {
42         if (x <= first[0]) {
43                 if (use_curve_mapping_extend_extrapolate[table] == 0) {
44                         /* no extrapolate */
45                         return first[1];
46                 }
47                 else {
48                         if (curve_mapping_ext_in_x[table] == 0.0)
49                                 return first[1] + curve_mapping_ext_in_y[table] * 10000.0;
50                         else
51                                 return first[1] + curve_mapping_ext_in_y[table] * (x - first[0]) / curve_mapping_ext_in_x[table];
52                 }
53         }
54         else if (x >= last[0]) {
55                 if (use_curve_mapping_extend_extrapolate[table] == 0) {
56                         /* no extrapolate */
57                         return last[1];
58                 }
59                 else {
60                         if (curve_mapping_ext_out_x[table] == 0.0)
61                                 return last[1] - curve_mapping_ext_out_y[table] * 10000.0;
62                         else
63                                 return last[1] + curve_mapping_ext_out_y[table] * (x - last[0]) / curve_mapping_ext_out_x[table];
64                 }
65         }
66         return 0.0;
67 }
68
69 float curvemap_evaluateF(int table, float value)
70 {
71         float mintable_ = curve_mapping_mintable[table];
72         float range = curve_mapping_range[table];
73         float mintable = 0.0;
74         int CM_TABLE = curve_mapping_lut_size - 1;
75
76         float fi;
77         int i;
78
79         /* index in table */
80         fi = (value - mintable) * range;
81         i = int(fi);
82
83         /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
84         if (fi < 0.0 || fi > float(CM_TABLE)) {
85                 return curvemap_calc_extend(table, value,
86                                             vec2(curve_mapping_first_x[table], curve_mapping_first_y[table]),
87                                             vec2(curve_mapping_last_x[table], curve_mapping_last_y[table]));
88         }
89         else {
90                 if (i < 0) return read_curve_mapping(table, 0);
91                 if (i >= CM_TABLE) return read_curve_mapping(table, CM_TABLE);
92
93                 fi = fi - float(i);
94                 return (1.0 - fi) * read_curve_mapping(table, i) + fi * read_curve_mapping(table, i + 1);
95         }
96 }
97
98 vec4 curvemapping_evaluate_premulRGBF(vec4 col)
99 {
100         vec4 result = col;
101         result[0] = curvemap_evaluateF(0, (col[0] - curve_mapping_black[0]) * curve_mapping_bwmul[0]);
102         result[1] = curvemap_evaluateF(1, (col[1] - curve_mapping_black[1]) * curve_mapping_bwmul[1]);
103         result[2] = curvemap_evaluateF(2, (col[2] - curve_mapping_black[2]) * curve_mapping_bwmul[2]);
104         result[3] = col[3];
105         return result;
106 }
107 #endif
108
109 #ifdef USE_DITHER
110 float dither_random_value(vec2 co)
111 {
112         return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453) * 0.005 * dither;
113 }
114
115 vec2 round_to_pixel(vec2 st)
116 {
117         vec2 result;
118         vec2 size = textureSize(image_texture, 0);
119         result.x = float(int(st.x * size.x)) / size.x;
120         result.y = float(int(st.y * size.y)) / size.y;
121         return result;
122 }
123
124 vec4 apply_dither(vec2 st, vec4 col)
125 {
126         vec4 result;
127         float random_value = dither_random_value(round_to_pixel(st));
128         result.r = col.r + random_value;
129         result.g = col.g + random_value;
130         result.b = col.b + random_value;
131         result.a = col.a;
132         return result;
133 }
134 #endif
135
136 void main()
137 {
138         vec4 col = texture2D(image_texture, gl_TexCoord[0].st);
139 #ifdef USE_CURVE_MAPPING
140         col = curvemapping_evaluate_premulRGBF(col);
141 #endif
142         if (predivide && col[3] > 0.0 && col[3] < 1.0) {
143                 float inv_alpha = 1.0 / col[3];
144                 col[0] *= inv_alpha;
145                 col[1] *= inv_alpha;
146                 col[2] *= inv_alpha;
147         }
148
149         /* NOTE: This is true we only do de-premul here and NO premul
150          *       and the reason is simple -- opengl is always configured
151          *       for straight alpha at this moment
152          */
153
154         vec4 result = OCIODisplay(col, lut3d_texture);
155
156 #ifdef USE_DITHER
157         result = apply_dither(gl_TexCoord[0].st, result);
158 #endif
159
160         gl_FragColor = result;
161 }