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;
42 std::string get_blend_color_func()
46 get_adjustement_glsl()
55 vec3 get_blend_color(vec3 back, vec3 fore)
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);
89 return BlendNormal(back, fore);
94 vec4 back = texture2D(background, gl_TexCoord[1].st).bgra;
96 fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a;
99 case 1: return fore + back; // additive
100 default: return fore + (1.0-fore.a)*back; // linear
106 std::string get_simple_blend_color_func()
110 get_adjustement_glsl()
115 vec4 blend(vec4 fore)
122 std::string get_vertex()
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;
138 std::string get_fragment(bool blend_modes)
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;
150 uniform bool has_local_key;
151 uniform bool has_layer_key;
152 uniform int blend_mode;
154 uniform int pixel_format;
155 uniform int deinterlace;
157 uniform float opacity;
159 uniform float min_input;
160 uniform float max_input;
162 uniform float min_output;
163 uniform float max_output;
174 (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
180 vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)
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;
190 vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)
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;
200 vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)
203 return ycbcra_to_rgba_hd(y, cb, cr, a);
205 return ycbcra_to_rgba_sd(y, cb, cr, a);
208 vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)
213 return texture2D(sampler, coords);
215 return texture2D(sampler, coords);
217 return texture2D(sampler, coords);
221 vec4 get_rgba_color()
226 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr, 1.0);
228 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgra;
230 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgba;
232 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).argb;
234 return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).gbar;
237 float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
238 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
239 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
240 return ycbcra_to_rgba(y, cb, cr, 1.0);
244 float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
245 float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
246 float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
247 float a = get_sample(plane[3], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).r;
248 return ycbcra_to_rgba(y, cb, cr, a);
252 vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rrr;
253 return vec4((y3-0.065)/0.859, 1.0);
256 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).bgr, 1.0);
258 return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q, plane_size[0]).rgb, 1.0);
260 return vec4(0.0, 0.0, 0.0, 0.0);
265 vec4 color = get_rgba_color();
267 color.rgb = LevelsControl(color.rgb, min_input, gamma, max_input, min_output, max_output);
269 color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);
271 color *= texture2D(local_key, gl_TexCoord[1].st).r;
273 color *= texture2D(layer_key, gl_TexCoord[1].st).r;
275 color = blend(color);
276 gl_FragColor = color.bgra;
281 std::shared_ptr<shader> get_image_shader(
282 const spl::shared_ptr<device>& ogl, bool& blend_modes, bool blend_modes_wanted)
284 tbb::mutex::scoped_lock lock(g_shader_mutex);
285 auto existing_shader = g_shader.lock();
289 blend_modes = g_blend_modes;
290 return existing_shader;
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;
297 auto deleter = [weak_ogl](shader* p)
299 auto ogl = weak_ogl.lock();
310 g_blend_modes = glTextureBarrierNV ? blend_modes_wanted : false;
311 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
315 CASPAR_LOG_CURRENT_EXCEPTION();
316 CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
318 g_blend_modes = false;
319 existing_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)), deleter);
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.";
329 blend_modes = g_blend_modes;
330 g_shader = existing_shader;
331 return existing_shader;