]> git.sesse.net Git - casparcg/blob - accelerator/ogl/image/image_shader.cpp
* Merged chroma key feature, but removed unsupported parameters and color names....
[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 int                     chroma_mode;
194                         uniform vec2            chroma_blend;
195                         uniform float           chroma_spill;
196         )shader"
197
198         +
199
200         (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
201
202         +
203
204         get_chroma_func()
205
206         +
207
208         R"shader(
209
210                         vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)
211                         {
212                                 vec4 rgba;
213                                 rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;
214                                 rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;
215                                 rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;
216                                 rgba.a = A;
217                                 return rgba;
218                         }
219
220                         vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)
221                         {
222                                 vec4 rgba;
223                                 rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;
224                                 rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;
225                                 rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;
226                                 rgba.a = A;
227                                 return rgba;
228                         }
229
230                         vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)
231                         {
232                                 if(is_hd)
233                                         return ycbcra_to_rgba_hd(y, cb, cr, a);
234                                 else
235                                         return ycbcra_to_rgba_sd(y, cb, cr, a);
236                         }
237
238                         vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)
239                         {
240                                 switch(deinterlace)
241                                 {
242                                 case 1: // upper
243                                         return texture2D(sampler, coords);
244                                 case 2: // lower
245                                         return texture2D(sampler, coords);
246                                 default:
247                                         return texture2D(sampler, coords);
248                                 }
249                         }
250
251                         vec4 get_rgba_color()
252                         {
253                                 switch(pixel_format)
254                                 {
255                                 case 0:         //gray
256                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr, 1.0);
257                                 case 1:         //bgra,
258                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgra;
259                                 case 2:         //rgba,
260                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgba;
261                                 case 3:         //argb,
262                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).argb;
263                                 case 4:         //abgr,
264                                         return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).gbar;
265                                 case 5:         //ycbcr,
266                                         {
267                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
268                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
269                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
270                                                 return ycbcra_to_rgba(y, cb, cr, 1.0);
271                                         }
272                                 case 6:         //ycbcra
273                                         {
274                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
275                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
276                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
277                                                 float a  = get_sample(plane[3], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
278                                                 return ycbcra_to_rgba(y, cb, cr, a);
279                                         }
280                                 case 7:         //luma
281                                         {
282                                                 vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr;
283                                                 return vec4((y3-0.065)/0.859, 1.0);
284                                         }
285                                 case 8:         //bgr,
286                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgr, 1.0);
287                                 case 9:         //rgb,
288                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgb, 1.0);
289                                 }
290                                 return vec4(0.0, 0.0, 0.0, 0.0);
291                         }
292
293                         void main()
294                         {
295                                 vec4 color = get_rgba_color();
296                                 color = chroma_key(color);
297                                 if(levels)
298                                         color.rgb = LevelsControl(color.rgb, min_input, gamma, max_input, min_output, max_output);
299                                 if(csb)
300                                         color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);
301                                 if(has_local_key)
302                                         color *= texture2D(local_key, gl_TexCoord[1].st).r;
303                                 if(has_layer_key)
304                                         color *= texture2D(layer_key, gl_TexCoord[1].st).r;
305                                 color *= opacity;
306                                 color = blend(color);
307                                 gl_FragColor = color.bgra;
308                         }
309         )shader";
310 }
311
312 std::shared_ptr<shader> get_image_shader(
313                 const spl::shared_ptr<device>& ogl, bool& blend_modes, bool blend_modes_wanted)
314 {
315         tbb::mutex::scoped_lock lock(g_shader_mutex);
316         auto existing_shader = g_shader.lock();
317
318         if(existing_shader)
319         {
320                 blend_modes = g_blend_modes;
321                 return existing_shader;
322         }
323
324         // The deleter is alive until the weak pointer is destroyed, so we have
325         // to weakly reference ogl, to not keep it alive until atexit
326         std::weak_ptr<device> weak_ogl = ogl;
327
328         auto deleter = [weak_ogl](shader* p)
329         {
330                 auto ogl = weak_ogl.lock();
331
332                 if (ogl)
333                         ogl->invoke([=]
334                         {
335                                 delete p;
336                         });
337         };
338                 
339         try
340         {                               
341                 g_blend_modes  = glTextureBarrierNV ? blend_modes_wanted : false;
342                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
343         }
344         catch(...)
345         {
346                 CASPAR_LOG_CURRENT_EXCEPTION();
347                 CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
348                                 
349                 g_blend_modes = false;
350                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
351         }
352                                                 
353         //if(!g_blend_modes)
354         //{
355         //      ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
356         //      CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";
357         //}
358
359
360         blend_modes = g_blend_modes;
361         g_shader = existing_shader;
362         return existing_shader;
363 }
364
365 }}}