]> git.sesse.net Git - casparcg/blob - accelerator/ogl/image/image_shader.cpp
Used raw string literals for shader code and regexes.
[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_vertex()
123 {
124         return R"shader(
125                         void main()
126                         {
127                                 gl_TexCoord[0] = gl_MultiTexCoord0;
128                         //      gl_TexCoord[1] = gl_MultiTexCoord1;
129                                 vec4 pos = ftransform();
130                                 gl_TexCoord[1] = vec4(pos.xy, 0.0, 0.0);
131                                 pos.x = pos.x*2.0 - 1.0;
132                                 pos.y = pos.y*2.0 - 1.0;
133                                 gl_Position    = pos;
134                         }
135         )shader";
136 }
137
138 std::string get_fragment(bool blend_modes)
139 {
140         return R"shader(
141
142                         #version 130
143                         uniform sampler2D       background;
144                         uniform sampler2D       plane[4];
145                         uniform vec2            plane_size[4];
146                         uniform sampler2D       local_key;
147                         uniform sampler2D       layer_key;
148
149                         uniform bool            is_hd;
150                         uniform bool            has_local_key;
151                         uniform bool            has_layer_key;
152                         uniform int                     blend_mode;
153                         uniform int                     keyer;
154                         uniform int                     pixel_format;
155                         uniform int                     deinterlace;
156
157                         uniform float           opacity;
158                         uniform bool            levels;
159                         uniform float           min_input;
160                         uniform float           max_input;
161                         uniform float           gamma;
162                         uniform float           min_output;
163                         uniform float           max_output;
164
165                         uniform bool            csb;
166                         uniform float           brt;
167                         uniform float           sat;
168                         uniform float           con;
169
170         )shader"
171
172         +
173
174         (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
175
176         +
177
178         R"shader(
179
180                         vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)
181                         {
182                                 vec4 rgba;
183                                 rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;
184                                 rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;
185                                 rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;
186                                 rgba.a = A;
187                                 return rgba;
188                         }
189
190                         vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)
191                         {
192                                 vec4 rgba;
193                                 rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;
194                                 rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;
195                                 rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;
196                                 rgba.a = A;
197                                 return rgba;
198                         }
199
200                         vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)
201                         {
202                                 if(is_hd)
203                                         return ycbcra_to_rgba_hd(y, cb, cr, a);
204                                 else
205                                         return ycbcra_to_rgba_sd(y, cb, cr, a);
206                         }
207
208                         vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)
209                         {
210                                 switch(deinterlace)
211                                 {
212                                 case 1: // upper
213                                         return texture2D(sampler, coords);
214                                 case 2: // lower
215                                         return texture2D(sampler, coords);
216                                 default:
217                                         return texture2D(sampler, coords);
218                                 }
219                         }
220
221                         vec4 get_rgba_color()
222                         {
223                                 switch(pixel_format)
224                                 {
225                                 case 0:         //gray
226                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr, 1.0);
227                                 case 1:         //bgra,
228                                         return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgra;
229                                 case 2:         //rgba,
230                                         return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgba;
231                                 case 3:         //argb,
232                                         return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).argb;
233                                 case 4:         //abgr,
234                                         return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).gbar;
235                                 case 5:         //ycbcr,
236                                         {
237                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;
238                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;
239                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;
240                                                 return ycbcra_to_rgba(y, cb, cr, 1.0);
241                                         }
242                                 case 6:         //ycbcra
243                                         {
244                                                 float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;
245                                                 float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;
246                                                 float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;
247                                                 float a  = get_sample(plane[3], gl_TexCoord[0].st, plane_size[0]).r;
248                                                 return ycbcra_to_rgba(y, cb, cr, a);
249                                         }
250                                 case 7:         //luma
251                                         {
252                                                 vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr;
253                                                 return vec4((y3-0.065)/0.859, 1.0);
254                                         }
255                                 case 8:         //bgr,
256                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgr, 1.0);
257                                 case 9:         //rgb,
258                                         return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgb, 1.0);
259                                 }
260                                 return vec4(0.0, 0.0, 0.0, 0.0);
261                         }
262
263                         void main()
264                         {
265                                 vec4 color = get_rgba_color();
266                            if(levels)
267                                         color.rgb = LevelsControl(color.rgb, min_input, gamma, max_input, min_output, max_output);
268                                 if(csb)
269                                         color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);
270                                 if(has_local_key)
271                                         color *= texture2D(local_key, gl_TexCoord[1].st).r;
272                                 if(has_layer_key)
273                                         color *= texture2D(layer_key, gl_TexCoord[1].st).r;
274                                 color *= opacity;
275                                 color = blend(color);
276                                 gl_FragColor = color.bgra;
277                         }
278         )shader";
279 }
280
281 std::shared_ptr<shader> get_image_shader(
282                 const spl::shared_ptr<device>& ogl, bool& blend_modes, bool blend_modes_wanted)
283 {
284         tbb::mutex::scoped_lock lock(g_shader_mutex);
285         auto existing_shader = g_shader.lock();
286
287         if(existing_shader)
288         {
289                 blend_modes = g_blend_modes;
290                 return existing_shader;
291         }
292
293         // The deleter is alive until the weak pointer is destroyed, so we have
294         // to weakly reference ogl, to not keep it alive until atexit
295         std::weak_ptr<device> weak_ogl = ogl;
296
297         auto deleter = [weak_ogl](shader* p)
298         {
299                 auto ogl = weak_ogl.lock();
300
301                 if (ogl)
302                         ogl->invoke([=]
303                         {
304                                 delete p;
305                         });
306         };
307                 
308         try
309         {                               
310                 g_blend_modes  = glTextureBarrierNV ? blend_modes_wanted : false;
311                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
312         }
313         catch(...)
314         {
315                 CASPAR_LOG_CURRENT_EXCEPTION();
316                 CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
317                                 
318                 g_blend_modes = false;
319                 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
320         }
321                                                 
322         //if(!g_blend_modes)
323         //{
324         //      ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
325         //      CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";
326         //}
327
328
329         blend_modes = g_blend_modes;
330         g_shader = existing_shader;
331         return existing_shader;
332 }
333
334 }}}