2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
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.
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.
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/>.
19 * Author: Robert Nagy, ronag89@gmail.com
22 #include "../../StdAfx.h"
24 #include "image_shader.h"
26 #include "../util/shader.h"
27 #include "../util/device.h"
29 #include "blending_glsl.h"
31 #include <common/gl/gl_check.h>
32 #include <common/env.h>
34 #include <tbb/mutex.h>
36 namespace caspar { namespace accelerator { namespace ogl {
38 std::weak_ptr<shader> g_shader;
39 tbb::mutex g_shader_mutex;
40 bool g_blend_modes = false;
41 bool g_post_processing = false;
43 std::string get_blend_color_func()
47 get_adjustement_glsl()
56 vec3 get_blend_color(vec3 back, vec3 fore)
60 case 0: return BlendNormal(back, fore);
61 case 1: return BlendLighten(back, fore);
62 case 2: return BlendDarken(back, fore);
63 case 3: return BlendMultiply(back, fore);
64 case 4: return BlendAverage(back, fore);
65 case 5: return BlendAdd(back, fore);
66 case 6: return BlendSubstract(back, fore);
67 case 7: return BlendDifference(back, fore);
68 case 8: return BlendNegation(back, fore);
69 case 9: return BlendExclusion(back, fore);
70 case 10: return BlendScreen(back, fore);
71 case 11: return BlendOverlay(back, fore);
72 // case 12: return BlendSoftLight(back, fore);
73 case 13: return BlendHardLight(back, fore);
74 case 14: return BlendColorDodge(back, fore);
75 case 15: return BlendColorBurn(back, fore);
76 case 16: return BlendLinearDodge(back, fore);
77 case 17: return BlendLinearBurn(back, fore);
78 case 18: return BlendLinearLight(back, fore);
79 case 19: return BlendVividLight(back, fore);
80 case 20: return BlendPinLight(back, fore);
81 case 21: return BlendHardMix(back, fore);
82 case 22: return BlendReflect(back, fore);
83 case 23: return BlendGlow(back, fore);
84 case 24: return BlendPhoenix(back, fore);
85 case 25: return BlendHue(back, fore);
86 case 26: return BlendSaturation(back, fore);
87 case 27: return BlendColor(back, fore);
88 case 28: return BlendLuminosity(back, fore);
90 return BlendNormal(back, fore);
95 vec4 back = texture2D(background, gl_TexCoord[1].st).bgra;
97 fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a;
100 case 1: return fore + back; // additive
101 default: return fore + (1.0-fore.a)*back; // linear
107 std::string get_simple_blend_color_func()
111 get_adjustement_glsl()
116 vec4 blend(vec4 fore)
123 std::string get_chroma_func()
132 vec4 chroma_key(vec4 c)
134 return ChromaOnCustomColor(c.bgra).bgra;
139 std::string get_post_process()
144 gl_FragColor = post_process().bgra;
150 std::string get_no_post_process()
155 std::string get_vertex()
160 gl_TexCoord[0] = gl_MultiTexCoord0;
161 // gl_TexCoord[1] = gl_MultiTexCoord1;
162 vec4 pos = ftransform();
163 gl_TexCoord[1] = vec4(pos.xy, 0.0, 0.0);
164 pos.x = pos.x*2.0 - 1.0;
165 pos.y = pos.y*2.0 - 1.0;
171 std::string get_fragment(bool blend_modes, bool post_processing)
176 uniform sampler2D background;
177 uniform sampler2D plane[4];
178 uniform vec2 plane_size[4];
179 uniform sampler2D local_key;
180 uniform sampler2D layer_key;
183 uniform bool has_local_key;
184 uniform bool has_layer_key;
185 uniform int blend_mode;
187 uniform int pixel_format;
188 uniform int deinterlace;
190 uniform float opacity;
192 uniform float min_input;
193 uniform float max_input;
195 uniform float min_output;
196 uniform float max_output;
203 uniform bool post_processing;
204 uniform bool straighten_alpha;
207 uniform bool chroma_show_mask;
208 uniform float chroma_target_hue;
209 uniform float chroma_hue_width;
210 uniform float chroma_min_saturation;
211 uniform float chroma_min_brightness;
212 uniform float chroma_softness;
213 uniform float chroma_spill_suppress;
214 uniform float chroma_spill_suppress_saturation;
219 (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
229 vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)
232 rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;
233 rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;
234 rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;
239 vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)
242 rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;
243 rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;
244 rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;
249 vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)
252 return ycbcra_to_rgba_hd(y, cb, cr, a);
254 return ycbcra_to_rgba_sd(y, cb, cr, a);
257 vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)
262 return texture2D(sampler, coords);
264 return texture2D(sampler, coords);
266 return texture2D(sampler, coords);
270 vec4 get_rgba_color()
275 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr, 1.0);
277 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgra;
279 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgba;
281 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).argb;
283 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).gbar;
286 float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
287 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
288 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
289 return ycbcra_to_rgba(y, cb, cr, 1.0);
293 float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
294 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
295 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
296 float a = get_sample(plane[3], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
297 return ycbcra_to_rgba(y, cb, cr, a);
301 vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr;
302 return vec4((y3-0.065)/0.859, 1.0);
305 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgr, 1.0);
307 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgb, 1.0);
309 return vec4(0.0, 0.0, 0.0, 0.0);
314 vec4 color = texture2D(background, gl_TexCoord[0].st).bgra;
316 if (straighten_alpha)
317 color.rgb /= color.a + 0.0000001;
328 (post_processing ? get_post_process() : get_no_post_process())
334 vec4 color = get_rgba_color();
336 color = chroma_key(color);
338 color.rgb = LevelsControl(color.rgb, min_input, gamma, max_input, min_output, max_output);
340 color.rgb = ContrastSaturationBrightness(color, brt, sat, con);
342 color *= texture2D(local_key, gl_TexCoord[1].st).r;
344 color *= texture2D(layer_key, gl_TexCoord[1].st).r;
346 color = blend(color);
347 gl_FragColor = color.bgra;
353 std::shared_ptr<shader> get_image_shader(
354 const spl::shared_ptr<device>& ogl,
356 bool blend_modes_wanted,
357 bool& post_processing,
358 bool straight_alpha_wanted)
360 tbb::mutex::scoped_lock lock(g_shader_mutex);
361 auto existing_shader = g_shader.lock();
365 blend_modes = g_blend_modes;
366 post_processing = g_post_processing;
367 return existing_shader;
370 // The deleter is alive until the weak pointer is destroyed, so we have
371 // to weakly reference ogl, to not keep it alive until atexit
372 std::weak_ptr<device> weak_ogl = ogl;
374 auto deleter = [weak_ogl](shader* p)
376 auto ogl = weak_ogl.lock();
387 g_blend_modes = glTextureBarrierNV ? blend_modes_wanted : false;
388 g_post_processing = straight_alpha_wanted;
389 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes, g_post_processing)), deleter);
393 CASPAR_LOG_CURRENT_EXCEPTION();
394 CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
396 g_blend_modes = false;
397 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes, g_post_processing)), deleter);
402 // ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
403 // CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";
407 blend_modes = g_blend_modes;
408 post_processing = g_post_processing;
409 g_shader = existing_shader;
410 return existing_shader;