]> git.sesse.net Git - casparcg/blob - accelerator/ogl/image/image_shader.cpp
* Instead of merging the chroma key conditional compilation, the uniform conditional...
[casparcg] / accelerator / ogl / image / image_shader.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../../StdAfx.h"
23
24 #include "image_shader.h"
25
26 #include "../util/shader.h"
27 #include "../util/device.h"
28
29 #include "blending_glsl.h"
30
31 #include <common/gl/gl_check.h>
32 #include <common/env.h>
33
34 #include <tbb/mutex.h>
35
36 namespace caspar { namespace accelerator { namespace ogl {
37
38 std::weak_ptr<shader>   g_shader;
39 tbb::mutex                              g_shader_mutex;
40 bool                                    g_blend_modes = false;
41
42 std::string get_blend_color_func()
43 {
44         return
45
46                 get_adjustement_glsl()
47
48                 +
49
50                 get_blend_glsl()
51
52                 +
53
54                 R"shader(
55                                 vec3 get_blend_color(vec3 back, vec3 fore)
56                                 {
57                                         switch(blend_mode)
58                                         {
59                                         case  0: return BlendNormal(back, fore);
60                                         case  1: return BlendLighten(back, fore);
61                                         case  2: return BlendDarken(back, fore);
62                                         case  3: return BlendMultiply(back, fore);
63                                         case  4: return BlendAverage(back, fore);
64                                         case  5: return BlendAdd(back, fore);
65                                         case  6: return BlendSubstract(back, fore);
66                                         case  7: return BlendDifference(back, fore);
67                                         case  8: return BlendNegation(back, fore);
68                                         case  9: return BlendExclusion(back, fore);
69                                         case 10: return BlendScreen(back, fore);
70                                         case 11: return BlendOverlay(back, fore);
71                                 //      case 12: return BlendSoftLight(back, fore);
72                                         case 13: return BlendHardLight(back, fore);
73                                         case 14: return BlendColorDodge(back, fore);
74                                         case 15: return BlendColorBurn(back, fore);
75                                         case 16: return BlendLinearDodge(back, fore);
76                                         case 17: return BlendLinearBurn(back, fore);
77                                         case 18: return BlendLinearLight(back, fore);
78                                         case 19: return BlendVividLight(back, fore);
79                                         case 20: return BlendPinLight(back, fore);
80                                         case 21: return BlendHardMix(back, fore);
81                                         case 22: return BlendReflect(back, fore);
82                                         case 23: return BlendGlow(back, fore);
83                                         case 24: return BlendPhoenix(back, fore);
84                                         case 25: return BlendHue(back, fore);
85                                         case 26: return BlendSaturation(back, fore);
86                                         case 27: return BlendColor(back, fore);
87                                         case 28: return BlendLuminosity(back, fore);
88                                         }
89                                         return BlendNormal(back, fore);
90                                 }
91
92                                 vec4 blend(vec4 fore)
93                                 {
94                                    vec4 back = texture2D(background, gl_TexCoord[1].st).bgra;
95                                    if(blend_mode != 0)
96                                                 fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a;
97                                         switch(keyer)
98                                         {
99                                                 case 1:  return fore + back; // additive
100                                                 default: return fore + (1.0-fore.a)*back; // linear
101                                         }
102                                 }
103                 )shader";
104 }
105                 
106 std::string get_simple_blend_color_func()
107 {
108         return
109
110                 get_adjustement_glsl()
111
112                 +
113
114                 R"shader(
115                                 vec4 blend(vec4 fore)
116                                 {
117                                         return fore;
118                                 }
119                 )shader";
120 }
121
122 std::string get_chroma_func()
123 {
124         return
125
126                 get_chroma_glsl()
127                 
128                 +
129                 
130                 R"shader(
131                                 vec4 chroma_key(vec4 c)
132                                 {
133                                         switch (chroma_mode)
134                                         {
135                                         case 0: return c;
136                                         case 1: return ChromaOnGreen(c.bgra).bgra;
137                                         case 2: return ChromaOnBlue(c.bgra).bgra;
138                                         }
139
140                                         return c;
141                                 }
142                 )shader";
143 }
144
145 std::string get_vertex()
146 {
147         return R"shader(
148                         void main()
149                         {
150                                 gl_TexCoord[0] = gl_MultiTexCoord0;
151                         //      gl_TexCoord[1] = gl_MultiTexCoord1;
152                                 vec4 pos = ftransform();
153                                 gl_TexCoord[1] = vec4(pos.xy, 0.0, 0.0);
154                                 pos.x = pos.x*2.0 - 1.0;
155                                 pos.y = pos.y*2.0 - 1.0;
156                                 gl_Position    = pos;
157                         }
158         )shader";
159 }
160
161 std::string get_fragment(bool blend_modes)
162 {
163         return R"shader(
164
165                         #version 130
166                         uniform sampler2D       background;
167                         uniform sampler2D       plane[4];
168                         uniform vec2            plane_size[4];
169                         uniform sampler2D       local_key;
170                         uniform sampler2D       layer_key;
171
172                         uniform bool            is_hd;
173                         uniform bool            has_local_key;
174                         uniform bool            has_layer_key;
175                         uniform int                     blend_mode;
176                         uniform int                     keyer;
177                         uniform int                     pixel_format;
178                         uniform int                     deinterlace;
179
180                         uniform float           opacity;
181                         uniform bool            levels;
182                         uniform float           min_input;
183                         uniform float           max_input;
184                         uniform float           gamma;
185                         uniform float           min_output;
186                         uniform float           max_output;
187
188                         uniform bool            csb;
189                         uniform float           brt;
190                         uniform float           sat;
191                         uniform float           con;
192
193                         uniform bool            chroma;
194                         uniform int                     chroma_mode;
195                         uniform vec2            chroma_blend;
196                         uniform float           chroma_spill;
197         )shader"
198
199         +
200
201         (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
202
203         +
204
205         get_chroma_func()
206
207         +
208
209         R"shader(
210
211                         vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)
212                         {
213                                 vec4 rgba;
214                                 rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;
215                                 rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;
216                                 rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;
217                                 rgba.a = A;
218                                 return rgba;
219                         }
220
221                         vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)
222                         {
223                                 vec4 rgba;
224                                 rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;
225                                 rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;
226                                 rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;
227                                 rgba.a = A;
228                                 return rgba;
229                         }
230
231                         vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)
232                         {
233                                 if(is_hd)
234                                         return ycbcra_to_rgba_hd(y, cb, cr, a);
235                                 else
236                                         return ycbcra_to_rgba_sd(y, cb, cr, a);
237                         }
238
239                         vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)
240                         {
241                                 switch(deinterlace)
242                                 {
243                                 case 1: // upper
244                                         return texture2D(sampler, coords);
245                                 case 2: // lower
246                                         return texture2D(sampler, coords);
247                                 default:
248                                         return texture2D(sampler, coords);
249                                 }
250                         }
251
252                         vec4 get_rgba_color()
253                         {
254                                 switch(pixel_format)
255                                 {
256                                 case 0:         //gray
257                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr, 1.0);
258                                 case 1:         //bgra,
259                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgra;
260                                 case 2:         //rgba,
261                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgba;
262                                 case 3:         //argb,
263                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).argb;
264                                 case 4:         //abgr,
265                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).gbar;
266                                 case 5:         //ycbcr,
267                                         {
268                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
269                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
270                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
271                                                 return ycbcra_to_rgba(y, cb, cr, 1.0);
272                                         }
273                                 case 6:         //ycbcra
274                                         {
275                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
276                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
277                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
278                                                 float a  = get_sample(plane[3], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
279                                                 return ycbcra_to_rgba(y, cb, cr, a);
280                                         }
281                                 case 7:         //luma
282                                         {
283                                                 vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr;
284                                                 return vec4((y3-0.065)/0.859, 1.0);
285                                         }
286                                 case 8:         //bgr,
287                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgr, 1.0);
288                                 case 9:         //rgb,
289                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgb, 1.0);
290                                 }
291                                 return vec4(0.0, 0.0, 0.0, 0.0);
292                         }
293
294                         void main()
295                         {
296                                 vec4 color = get_rgba_color();
297                                 if (chroma)
298                                         color = chroma_key(color);
299                                 if(levels)
300                                         color.rgb = LevelsControl(color.rgb, min_input, gamma, max_input, min_output, max_output);
301                                 if(csb)
302                                         color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);
303                                 if(has_local_key)
304                                         color *= texture2D(local_key, gl_TexCoord[1].st).r;
305                                 if(has_layer_key)
306                                         color *= texture2D(layer_key, gl_TexCoord[1].st).r;
307                                 color *= opacity;
308                                 color = blend(color);
309                                 gl_FragColor = color.bgra;
310                         }
311         )shader";
312 }
313
314 std::shared_ptr<shader> get_image_shader(
315                 const spl::shared_ptr<device>& ogl, bool& blend_modes, bool blend_modes_wanted)
316 {
317         tbb::mutex::scoped_lock lock(g_shader_mutex);
318         auto existing_shader = g_shader.lock();
319
320         if(existing_shader)
321         {
322                 blend_modes = g_blend_modes;
323                 return existing_shader;
324         }
325
326         // The deleter is alive until the weak pointer is destroyed, so we have
327         // to weakly reference ogl, to not keep it alive until atexit
328         std::weak_ptr<device> weak_ogl = ogl;
329
330         auto deleter = [weak_ogl](shader* p)
331         {
332                 auto ogl = weak_ogl.lock();
333
334                 if (ogl)
335                         ogl->invoke([=]
336                         {
337                                 delete p;
338                         });
339         };
340                 
341         try
342         {                               
343                 g_blend_modes  = glTextureBarrierNV ? blend_modes_wanted : false;
344                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
345         }
346         catch(...)
347         {
348                 CASPAR_LOG_CURRENT_EXCEPTION();
349                 CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
350                                 
351                 g_blend_modes = false;
352                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
353         }
354                                                 
355         //if(!g_blend_modes)
356         //{
357         //      ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
358         //      CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";
359         //}
360
361
362         blend_modes = g_blend_modes;
363         g_shader = existing_shader;
364         return existing_shader;
365 }
366
367 }}}