From: Ronag Date: Sun, 14 Aug 2011 14:57:58 +0000 (+0000) Subject: 2.0. - Removed alpha-mode. X-Git-Tag: 2.0.1~171 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=02aff8c59fe36ba41cef2929ec0f6f7a555b9b3b;p=casparcg 2.0. - Removed alpha-mode. - Use global shader for all channels. - Return pre-allocated empty buffer when channel is empty, reduces load on gpu for empty channels. - Refactored image_kernel. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1169 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/common/diagnostics/graph.cpp b/common/diagnostics/graph.cpp index bcce96aa4..5378f5156 100644 --- a/common/diagnostics/graph.cpp +++ b/common/diagnostics/graph.cpp @@ -232,7 +232,7 @@ public: target.Draw(*guide_); glBegin(GL_LINE_STRIP); - glColor4f(c_.red, c_.green, c_.blue, 0.7f); + glColor4f(c_.red, c_.green, c_.blue, 0.8f); for(size_t n = 0; n < line_data_.size(); ++n) if(line_data_[n].first > -0.5) glVertex3d(x+n*dx, std::max(0.05, std::min(0.95, (1.0f-line_data_[n].first)*0.8 + 0.1f)), 0.0); diff --git a/core/core.vcxproj b/core/core.vcxproj index c0eb616c8..36394f632 100644 --- a/core/core.vcxproj +++ b/core/core.vcxproj @@ -250,6 +250,7 @@ + @@ -296,6 +297,12 @@ ../../../StdAfx.h ../../../StdAfx.h + + ../../StdAfx.h + ../../StdAfx.h + ../../StdAfx.h + ../../StdAfx.h + ../StdAfx.h diff --git a/core/core.vcxproj.filters b/core/core.vcxproj.filters index e4ddfd6ff..f6a853479 100644 --- a/core/core.vcxproj.filters +++ b/core/core.vcxproj.filters @@ -124,6 +124,9 @@ source\mixer\gpu + + source\mixer\image + @@ -202,5 +205,8 @@ source\mixer\gpu + + source\mixer\image + \ No newline at end of file diff --git a/core/mixer/gpu/shader.cpp b/core/mixer/gpu/shader.cpp index 03f34dc23..293c285c6 100644 --- a/core/mixer/gpu/shader.cpp +++ b/core/mixer/gpu/shader.cpp @@ -92,6 +92,11 @@ public: return it->second; } + void set(const std::string& name, bool value) + { + set(name, value ? 1 : 0); + } + void set(const std::string& name, int value) { GL(glUniform1i(get_location(name.c_str()), value)); @@ -110,6 +115,7 @@ public: shader::shader(const std::string& vertex_source_str, const std::string& fragment_source_str) : impl_(new implementation(vertex_source_str, fragment_source_str)){} +void shader::set(const std::string& name, bool value){impl_->set(name, value);} void shader::set(const std::string& name, int value){impl_->set(name, value);} void shader::set(const std::string& name, float value){impl_->set(name, value);} void shader::set(const std::string& name, double value){impl_->set(name, value);} diff --git a/core/mixer/gpu/shader.h b/core/mixer/gpu/shader.h index 0595edbcc..88fd3525c 100644 --- a/core/mixer/gpu/shader.h +++ b/core/mixer/gpu/shader.h @@ -12,6 +12,7 @@ class shader : boost::noncopyable { public: shader(const std::string& vertex_source_str, const std::string& fragment_source_str); + void set(const std::string& name, bool value); void set(const std::string& name, int value); void set(const std::string& name, float value); void set(const std::string& name, double value); diff --git a/core/mixer/image/image_kernel.cpp b/core/mixer/image/image_kernel.cpp index 2777bb3c4..06f4e05be 100644 --- a/core/mixer/image/image_kernel.cpp +++ b/core/mixer/image/image_kernel.cpp @@ -21,6 +21,8 @@ #include "image_kernel.h" +#include "image_shader.h" + #include "blending_glsl.h" #include "../gpu/shader.h" #include "../gpu/device_buffer.h" @@ -58,268 +60,9 @@ GLubyte lower_pattern[] = { struct image_kernel::implementation : boost::noncopyable { - std::unique_ptr shader_; + std::shared_ptr shader_; bool blend_modes_; - - implementation() : blend_modes_(true) - { - } - - std::string get_blend_color_func() - { - return - - get_adjustement_glsl() - - + - - get_blend_glsl() - - + - - "vec3 get_blend_color(vec3 back, vec3 fore) \n" - "{ \n" - " switch(blend_mode) \n" - " { \n" - " case 0: return BlendNormal(back, fore); \n" - " case 1: return BlendLighten(back, fore); \n" - " case 2: return BlendDarken(back, fore); \n" - " case 3: return BlendMultiply(back, fore); \n" - " case 4: return BlendAverage(back, fore); \n" - " case 5: return BlendAdd(back, fore); \n" - " case 6: return BlendSubstract(back, fore); \n" - " case 7: return BlendDifference(back, fore); \n" - " case 8: return BlendNegation(back, fore); \n" - " case 9: return BlendExclusion(back, fore); \n" - " case 10: return BlendScreen(back, fore); \n" - " case 11: return BlendOverlay(back, fore); \n" - //" case 12: return BlendSoftLight(back, fore); \n" - " case 13: return BlendHardLight(back, fore); \n" - " case 14: return BlendColorDodge(back, fore); \n" - " case 15: return BlendColorBurn(back, fore); \n" - " case 16: return BlendLinearDodge(back, fore); \n" - " case 17: return BlendLinearBurn(back, fore); \n" - " case 18: return BlendLinearLight(back, fore); \n" - " case 19: return BlendVividLight(back, fore); \n" - " case 20: return BlendPinLight(back, fore); \n" - " case 21: return BlendHardMix(back, fore); \n" - " case 22: return BlendReflect(back, fore); \n" - " case 23: return BlendGlow(back, fore); \n" - " case 24: return BlendPhoenix(back, fore); \n" - " case 25: return BlendHue(back, fore); \n" - " case 26: return BlendSaturation(back, fore); \n" - " case 27: return BlendColor(back, fore); \n" - " case 28: return BlendLuminosity(back, fore); \n" - " } \n" - " return BlendNormal(back, fore); \n" - "} \n" - " \n" - "vec4 blend(vec4 fore) \n" - "{ \n" - " vec4 back = texture2D(background, gl_TexCoord[1].st); \n" - " fore.rgb = get_blend_color(back.rgb, fore.rgb); \n" - " return vec4(mix(back.bgr, fore.rgb, fore.a), back.a + fore.a); \n" - "} \n"; - } - - std::string get_simple_blend_color_func() - { - return - - get_adjustement_glsl() - - + - - "vec4 blend(vec4 fore) \n" - "{ \n" - " return fore; \n" - "} \n"; - } - - std::string get_vertex() - { - return - - "void main() \n" - "{ \n" - " gl_TexCoord[0] = gl_MultiTexCoord0; \n" - " gl_TexCoord[1] = gl_MultiTexCoord1; \n" - " gl_FrontColor = gl_Color; \n" - " gl_Position = ftransform(); \n" - "} \n"; - } - - std::string get_fragment() - { - return - - "#version 120 \n" - "uniform sampler2D background; \n" - "uniform sampler2D plane[4]; \n" - "uniform sampler2D local_key; \n" - "uniform sampler2D layer_key; \n" - " \n" - "uniform bool is_hd; \n" - "uniform bool has_local_key; \n" - "uniform bool has_layer_key; \n" - "uniform int blend_mode; \n" - "uniform int alpha_mode; \n" - "uniform int pixel_format; \n" - " \n" - "uniform bool levels; \n" - "uniform float min_input; \n" - "uniform float max_input; \n" - "uniform float gamma; \n" - "uniform float min_output; \n" - "uniform float max_output; \n" - " \n" - "uniform bool csb; \n" - "uniform float brt; \n" - "uniform float sat; \n" - "uniform float con; \n" - " \n" - - + - - (blend_modes_ ? get_blend_color_func() : get_simple_blend_color_func()) - - + - - " \n" - "//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n" - "vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n" - "{ \n" - " // YUV offset \n" - " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n" - " \n" - " // RGB coefficients \n" - " const vec3 Rcoeff = vec3(1.164, 0.000, 1.596); \n" - " const vec3 Gcoeff = vec3(1.164, -0.391, -0.813); \n" - " const vec3 Bcoeff = vec3(1.164, 2.018, 0.000); \n" - " \n" - " vec3 yuv = vec3(y, cr, cb); \n" - " vec4 rgba; \n" - " \n" - " yuv += offset; \n" - " rgba.r = dot(yuv, Rcoeff); \n" - " rgba.g = dot(yuv, Gcoeff); \n" - " rgba.b = dot(yuv, Bcoeff); \n" - " rgba.a = a; \n" - " \n" - " return rgba; \n" - "} \n" - " \n" - "vec4 ycbcra_to_rgba_hd(float y, float cb, float cr, float a) \n" - "{ \n" - " // YUV offset \n" - " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n" - " \n" - " // RGB coefficients \n" - " const vec3 Rcoeff = vec3(1.164, 0.000, 1.793); \n" - " const vec3 Gcoeff = vec3(1.164, -0.213, -0.534); \n" - " const vec3 Bcoeff = vec3(1.164, 2.115, 0.000); \n" - " \n" - " vec3 yuv = vec3(y, cr, cb); \n" - " vec4 rgba; \n" - " \n" - " yuv += offset; \n" - " rgba.r = dot(yuv, Rcoeff); \n" - " rgba.g = dot(yuv, Gcoeff); \n" - " rgba.b = dot(yuv, Bcoeff); \n" - " rgba.a = a; \n" - " \n" - " return rgba; \n" - "} \n" - " \n" - "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a) \n" - "{ \n" - " if(is_hd) \n" - " return ycbcra_to_rgba_hd(y, cb, cr, a); \n" - " else \n" - " return ycbcra_to_rgba_sd(y, cb, cr, a); \n" - "} \n" - " \n" - "vec4 get_rgba_color() \n" - "{ \n" - " switch(pixel_format) \n" - " { \n" - " case 0: //gray \n" - " return vec4(texture2D(plane[0], gl_TexCoord[0].st).rrr, 1.0); \n" - " case 1: //bgra, \n" - " return texture2D(plane[0], gl_TexCoord[0].st).bgra; \n" - " case 2: //rgba, \n" - " return texture2D(plane[0], gl_TexCoord[0].st).rgba; \n" - " case 3: //argb, \n" - " return texture2D(plane[0], gl_TexCoord[0].st).argb; \n" - " case 4: //abgr, \n" - " return texture2D(plane[0], gl_TexCoord[0].st).gbar; \n" - " case 5: //ycbcr, \n" - " { \n" - " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n" - " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n" - " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n" - " return ycbcra_to_rgba(y, cb, cr, 1.0); \n" - " } \n" - " case 6: //ycbcra \n" - " { \n" - " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n" - " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n" - " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n" - " float a = texture2D(plane[3], gl_TexCoord[0].st).r; \n" - " return ycbcra_to_rgba(y, cb, cr, a); \n" - " } \n" - " case 7: //luma \n" - " { \n" - " vec3 y3 = texture2D(plane[0], gl_TexCoord[0].st).rrr; \n" - " return vec4((y3-0.065)/0.859, 1.0); \n" - " } \n" - " } \n" - " return vec4(0.0, 0.0, 0.0, 0.0); \n" - "} \n" - " \n" - "void main() \n" - "{ \n" - " vec4 color = get_rgba_color(); \n" - " if(levels) \n" - " color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n" - " if(csb) \n" - " color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con); \n" - " if(has_local_key) \n" - " color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n" - " if(has_layer_key) \n" - " color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n" - " color *= gl_Color; \n" - " color = blend(color); \n" - " gl_FragColor = color.bgra; \n" - "} \n"; - } - - void init_shader(ogl_device& ogl) - { - try - { - blend_modes_ = glTextureBarrierNV ? env::properties().get("configuration.mixers.blend-modes", false) : false; - shader_.reset(new shader(get_vertex(), get_fragment())); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes."; - - blend_modes_ = false; - shader_.reset(new shader(get_vertex(), get_fragment())); - } - - ogl.enable(GL_TEXTURE_2D); - - if(!blend_modes_) - { - ogl.enable(GL_BLEND); - GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE)); - CASPAR_LOG(info) << L"[shader] Blend-modes are disabled."; - } - } - + void draw(ogl_device& ogl, render_item&& item, const safe_ptr& background, @@ -335,46 +78,34 @@ struct image_kernel::implementation : boost::noncopyable if(item.transform.get_opacity() < epsilon) return; - - if(!shader_) - init_shader(ogl); - - if(item.mode == core::video_mode::progressive) - ogl.disable(GL_POLYGON_STIPPLE); - else - { - ogl.enable(GL_POLYGON_STIPPLE); - - if(item.mode == core::video_mode::upper) - ogl.stipple_pattern(upper_pattern); - else if(item.mode == core::video_mode::lower) - ogl.stipple_pattern(lower_pattern); - } - + // Bind textures for(size_t n = 0; n < item.textures.size(); ++n) item.textures[n]->bind(n); if(local_key) - local_key->bind(4); + local_key->bind(texture_id::local_key); if(layer_key) - layer_key->bind(5); - + layer_key->bind(texture_id::layer_key); + // Setup shader + if(!shader_) + shader_ = get_image_shader(ogl, blend_modes_); + ogl.use(*shader_); - shader_->set("plane[0]", 0); - shader_->set("plane[1]", 1); - shader_->set("plane[2]", 2); - shader_->set("plane[3]", 3); - shader_->set("local_key", 4); - shader_->set("layer_key", 5); - shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0); - shader_->set("has_local_key", local_key ? 1 : 0); - shader_->set("has_layer_key", layer_key ? 1 : 0); + shader_->set("plane[0]", texture_id::plane0); + shader_->set("plane[1]", texture_id::plane1); + shader_->set("plane[2]", texture_id::plane2); + shader_->set("plane[3]", texture_id::plane3); + shader_->set("local_key", texture_id::local_key); + shader_->set("layer_key", texture_id::layer_key); + shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0); + shader_->set("has_local_key", local_key); + shader_->set("has_layer_key", layer_key); shader_->set("pixel_format", item.pix_desc.pix_fmt); // Setup blend_func @@ -383,11 +114,12 @@ struct image_kernel::implementation : boost::noncopyable { background->bind(6); - shader_->set("background", 6); - shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode()); - shader_->set("alpha_mode", item.transform.get_alpha_mode()); + shader_->set("background", texture_id::background); + shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode()); } + // Setup image-adjustements + auto levels = item.transform.get_levels(); if(levels.min_input > epsilon || @@ -419,6 +151,20 @@ struct image_kernel::implementation : boost::noncopyable else shader_->set("csb", false); + // Setup interlacing + + if(item.mode == core::video_mode::progressive) + ogl.disable(GL_POLYGON_STIPPLE); + else + { + ogl.enable(GL_POLYGON_STIPPLE); + + if(item.mode == core::video_mode::upper) + ogl.stipple_pattern(upper_pattern); + else if(item.mode == core::video_mode::lower) + ogl.stipple_pattern(lower_pattern); + } + // Setup drawing area ogl.viewport(0, 0, background->width(), background->height()); @@ -443,6 +189,10 @@ struct image_kernel::implementation : boost::noncopyable auto f_p = item.transform.get_fill_translation(); auto f_s = item.transform.get_fill_scale(); + // Set render target + + ogl.attach(*background); + // Draw glBegin(GL_QUADS); @@ -452,13 +202,15 @@ struct image_kernel::implementation : boost::noncopyable glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, f_p[0] , (f_p[1]+f_s[1])); glVertex2d( f_p[0] *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0); glEnd(); + // Cleanup + ogl.disable(GL_SCISSOR_TEST); item.textures.clear(); ogl.yield(); // Return resources to pool as early as possible. if(!blend_modes_) - glTextureBarrierNV(); // This allows us to use framebuffer both as source and target while blending. + glTextureBarrierNV(); // This allows us to use framebuffer (background) both as source and target while blending. } }; diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index f9676e068..a144b5de9 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -68,6 +68,8 @@ struct image_mixer::implementation : boost::noncopyable std::shared_ptr local_key_buffer_; std::shared_ptr layer_key_buffer_; + + std::shared_ptr empty_buffer_; public: implementation(video_channel_context& video_channel) @@ -89,6 +91,10 @@ public: layer_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1); draw_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); local_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1); + + empty_buffer_ = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::write_only); + memset(empty_buffer_->data(), 0, empty_buffer_->size()); + channel_.ogl().gc(); } @@ -110,8 +116,7 @@ public: auto& layer = layers_.back(); - auto it = boost::range::find(layer, item); - if(it == layer.end()) + if(boost::range::find(layer, item) == layer.end()) layer.push_back(item); } @@ -138,6 +143,9 @@ public: safe_ptr render(std::deque&& layers) { + if(layers.empty()) + return make_safe(empty_buffer_); + if(channel_.get_format_desc().width != write_buffer_->width() || channel_.get_format_desc().height != write_buffer_->height()) initialize_buffers(); @@ -158,7 +166,7 @@ public: host_buffer->begin_read(write_buffer_->width(), write_buffer_->height(), format(write_buffer_->stride())); GL(glFlush()); - + return host_buffer; } @@ -199,7 +207,6 @@ public: channel_.ogl().yield(); // Try to give it some more time. } - channel_.ogl().attach(*target); kernel_.draw(channel_.ogl(), std::move(item), make_safe(target), local_key, layer_key); } diff --git a/core/mixer/image/image_shader.cpp b/core/mixer/image/image_shader.cpp new file mode 100644 index 000000000..781ea9b83 --- /dev/null +++ b/core/mixer/image/image_shader.cpp @@ -0,0 +1,286 @@ +#include "../../StdAfx.h" + +#include "image_shader.h" + +#include "../gpu/shader.h" +#include "../gpu/ogl_device.h" + +#include "blending_glsl.h" + +#include +#include + +#include + +namespace caspar { namespace core { + +std::shared_ptr g_shader; +tbb::mutex g_shader_mutex; +bool g_blend_modes = false; + +std::string get_blend_color_func() +{ + return + + get_adjustement_glsl() + + + + + get_blend_glsl() + + + + + "vec3 get_blend_color(vec3 back, vec3 fore) \n" + "{ \n" + " switch(blend_mode) \n" + " { \n" + " case 0: return BlendNormal(back, fore); \n" + " case 1: return BlendLighten(back, fore); \n" + " case 2: return BlendDarken(back, fore); \n" + " case 3: return BlendMultiply(back, fore); \n" + " case 4: return BlendAverage(back, fore); \n" + " case 5: return BlendAdd(back, fore); \n" + " case 6: return BlendSubstract(back, fore); \n" + " case 7: return BlendDifference(back, fore); \n" + " case 8: return BlendNegation(back, fore); \n" + " case 9: return BlendExclusion(back, fore); \n" + " case 10: return BlendScreen(back, fore); \n" + " case 11: return BlendOverlay(back, fore); \n" + //" case 12: return BlendSoftLight(back, fore); \n" + " case 13: return BlendHardLight(back, fore); \n" + " case 14: return BlendColorDodge(back, fore); \n" + " case 15: return BlendColorBurn(back, fore); \n" + " case 16: return BlendLinearDodge(back, fore); \n" + " case 17: return BlendLinearBurn(back, fore); \n" + " case 18: return BlendLinearLight(back, fore); \n" + " case 19: return BlendVividLight(back, fore); \n" + " case 20: return BlendPinLight(back, fore); \n" + " case 21: return BlendHardMix(back, fore); \n" + " case 22: return BlendReflect(back, fore); \n" + " case 23: return BlendGlow(back, fore); \n" + " case 24: return BlendPhoenix(back, fore); \n" + " case 25: return BlendHue(back, fore); \n" + " case 26: return BlendSaturation(back, fore); \n" + " case 27: return BlendColor(back, fore); \n" + " case 28: return BlendLuminosity(back, fore); \n" + " } \n" + " return BlendNormal(back, fore); \n" + "} \n" + " \n" + "vec4 blend(vec4 fore) \n" + "{ \n" + " vec4 back = texture2D(background, gl_TexCoord[1].st); \n" + " fore.rgb = get_blend_color(back.rgb, fore.rgb); \n" + " return vec4(mix(back.bgr, fore.rgb, fore.a), back.a + fore.a); \n" + "} \n"; +} + +std::string get_simple_blend_color_func() +{ + return + + get_adjustement_glsl() + + + + + "vec4 blend(vec4 fore) \n" + "{ \n" + " return fore; \n" + "} \n"; +} + +std::string get_vertex() +{ + return + + "void main() \n" + "{ \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + " gl_TexCoord[1] = gl_MultiTexCoord1; \n" + " gl_FrontColor = gl_Color; \n" + " gl_Position = ftransform(); \n" + "} \n"; +} + +std::string get_fragment(bool blend_modes) +{ + return + + "#version 120 \n" + "uniform sampler2D background; \n" + "uniform sampler2D plane[4]; \n" + "uniform sampler2D local_key; \n" + "uniform sampler2D layer_key; \n" + " \n" + "uniform bool is_hd; \n" + "uniform bool has_local_key; \n" + "uniform bool has_layer_key; \n" + "uniform int blend_mode; \n" + "uniform int pixel_format; \n" + " \n" + "uniform bool levels; \n" + "uniform float min_input; \n" + "uniform float max_input; \n" + "uniform float gamma; \n" + "uniform float min_output; \n" + "uniform float max_output; \n" + " \n" + "uniform bool csb; \n" + "uniform float brt; \n" + "uniform float sat; \n" + "uniform float con; \n" + " \n" + + + + + (blend_modes ? get_blend_color_func() : get_simple_blend_color_func()) + + + + + " \n" + "//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n" + "vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n" + "{ \n" + " // YUV offset \n" + " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n" + " \n" + " // RGB coefficients \n" + " const vec3 Rcoeff = vec3(1.164, 0.000, 1.596); \n" + " const vec3 Gcoeff = vec3(1.164, -0.391, -0.813); \n" + " const vec3 Bcoeff = vec3(1.164, 2.018, 0.000); \n" + " \n" + " vec3 yuv = vec3(y, cr, cb); \n" + " vec4 rgba; \n" + " \n" + " yuv += offset; \n" + " rgba.r = dot(yuv, Rcoeff); \n" + " rgba.g = dot(yuv, Gcoeff); \n" + " rgba.b = dot(yuv, Bcoeff); \n" + " rgba.a = a; \n" + " \n" + " return rgba; \n" + "} \n" + " \n" + "vec4 ycbcra_to_rgba_hd(float y, float cb, float cr, float a) \n" + "{ \n" + " // YUV offset \n" + " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n" + " \n" + " // RGB coefficients \n" + " const vec3 Rcoeff = vec3(1.164, 0.000, 1.793); \n" + " const vec3 Gcoeff = vec3(1.164, -0.213, -0.534); \n" + " const vec3 Bcoeff = vec3(1.164, 2.115, 0.000); \n" + " \n" + " vec3 yuv = vec3(y, cr, cb); \n" + " vec4 rgba; \n" + " \n" + " yuv += offset; \n" + " rgba.r = dot(yuv, Rcoeff); \n" + " rgba.g = dot(yuv, Gcoeff); \n" + " rgba.b = dot(yuv, Bcoeff); \n" + " rgba.a = a; \n" + " \n" + " return rgba; \n" + "} \n" + " \n" + "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a) \n" + "{ \n" + " if(is_hd) \n" + " return ycbcra_to_rgba_hd(y, cb, cr, a); \n" + " else \n" + " return ycbcra_to_rgba_sd(y, cb, cr, a); \n" + "} \n" + " \n" + "vec4 get_rgba_color() \n" + "{ \n" + " switch(pixel_format) \n" + " { \n" + " case 0: //gray \n" + " return vec4(texture2D(plane[0], gl_TexCoord[0].st).rrr, 1.0); \n" + " case 1: //bgra, \n" + " return texture2D(plane[0], gl_TexCoord[0].st).bgra; \n" + " case 2: //rgba, \n" + " return texture2D(plane[0], gl_TexCoord[0].st).rgba; \n" + " case 3: //argb, \n" + " return texture2D(plane[0], gl_TexCoord[0].st).argb; \n" + " case 4: //abgr, \n" + " return texture2D(plane[0], gl_TexCoord[0].st).gbar; \n" + " case 5: //ycbcr, \n" + " { \n" + " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n" + " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n" + " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n" + " return ycbcra_to_rgba(y, cb, cr, 1.0); \n" + " } \n" + " case 6: //ycbcra \n" + " { \n" + " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n" + " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n" + " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n" + " float a = texture2D(plane[3], gl_TexCoord[0].st).r; \n" + " return ycbcra_to_rgba(y, cb, cr, a); \n" + " } \n" + " case 7: //luma \n" + " { \n" + " vec3 y3 = texture2D(plane[0], gl_TexCoord[0].st).rrr; \n" + " return vec4((y3-0.065)/0.859, 1.0); \n" + " } \n" + " } \n" + " return vec4(0.0, 0.0, 0.0, 0.0); \n" + "} \n" + " \n" + "void main() \n" + "{ \n" + " vec4 color = get_rgba_color(); \n" + " if(levels) \n" + " color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n" + " if(csb) \n" + " color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con); \n" + " if(has_local_key) \n" + " color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n" + " if(has_layer_key) \n" + " color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n" + " color *= gl_Color; \n" + " color = blend(color); \n" + " gl_FragColor = color.bgra; \n" + "} \n"; +} + +safe_ptr get_image_shader(ogl_device& ogl, bool& blend_modes) +{ + tbb::mutex::scoped_lock lock(g_shader_mutex); + + if(g_shader) + { + blend_modes = g_blend_modes; + return make_safe(g_shader); + } + + try + { + g_blend_modes = glTextureBarrierNV ? env::properties().get("configuration.mixers.blend-modes", false) : false; + g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes))); + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes."; + + g_blend_modes = false; + g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes))); + } + + ogl.enable(GL_TEXTURE_2D); + + if(!g_blend_modes) + { + ogl.enable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + CASPAR_LOG(info) << L"[shader] Blend-modes are disabled."; + } + + blend_modes = g_blend_modes; + return make_safe(g_shader); +} + +}} \ No newline at end of file diff --git a/core/mixer/image/image_shader.h b/core/mixer/image/image_shader.h new file mode 100644 index 000000000..792a1cb34 --- /dev/null +++ b/core/mixer/image/image_shader.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace caspar { namespace core { + +class shader; +class ogl_device; + +struct texture_id +{ + enum type + { + plane0 = 0, + plane1, + plane2, + plane3, + local_key, + layer_key, + background, + }; +}; + +safe_ptr get_image_shader(ogl_device& ogl, bool& blend_modes); + + +}} \ No newline at end of file diff --git a/core/producer/frame/image_transform.cpp b/core/producer/frame/image_transform.cpp index 3aaee6d08..357b1524e 100644 --- a/core/producer/frame/image_transform.cpp +++ b/core/producer/frame/image_transform.cpp @@ -36,7 +36,6 @@ image_transform::image_transform() , is_key_(false) , deinterlace_(false) , blend_mode_(image_transform::blend_mode::normal) - , alpha_mode_(image_transform::alpha_mode::normal) { std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0); std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0); @@ -169,21 +168,10 @@ image_transform::blend_mode::type image_transform::get_blend_mode() const return blend_mode_; } -void image_transform::set_alpha_mode(image_transform::alpha_mode::type value) -{ - alpha_mode_ = value; -} - -image_transform::alpha_mode::type image_transform::get_alpha_mode() const -{ - return alpha_mode_; -} - image_transform& image_transform::operator*=(const image_transform &other) { opacity_ *= other.opacity_; blend_mode_ = std::max(blend_mode_, other.blend_mode_); - alpha_mode_ = std::max(alpha_mode_, other.alpha_mode_); gain_ *= other.gain_; brightness_ *= other.brightness_; contrast_ *= other.contrast_; @@ -227,7 +215,6 @@ image_transform tween(double time, const image_transform& source, const image_tr image_transform result; result.set_blend_mode (std::max(source.get_blend_mode(), dest.get_blend_mode())); - result.set_alpha_mode (std::max(source.get_alpha_mode(), dest.get_alpha_mode())); result.set_is_key (source.get_is_key() | dest.get_is_key()); result.set_deinterlace (source.get_deinterlace() | dest.get_deinterlace()); result.set_gain (do_tween(time, source.get_gain(), dest.get_gain(), duration, tweener)); @@ -320,14 +307,6 @@ image_transform::blend_mode::type get_blend_mode(const std::wstring& str) return image_transform::blend_mode::normal; } -image_transform::alpha_mode::type get_alpha_mode(const std::wstring& str) -{ - if(boost::iequals(str, L"normal")) - return image_transform::alpha_mode::normal; - - return image_transform::alpha_mode::normal; -} - bool operator<(const image_transform& lhs, const image_transform& rhs) { return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0; diff --git a/core/producer/frame/image_transform.h b/core/producer/frame/image_transform.h index 4ec5fe7a1..d6870a2a5 100644 --- a/core/producer/frame/image_transform.h +++ b/core/producer/frame/image_transform.h @@ -69,15 +69,7 @@ public: blend_mode_count }; }; - - struct alpha_mode - { - enum type - { - normal = 0, - }; - }; - + struct levels { levels() @@ -139,9 +131,6 @@ public: void set_blend_mode(blend_mode::type value); blend_mode::type get_blend_mode() const; - void set_alpha_mode(alpha_mode::type value); - alpha_mode::type get_alpha_mode() const; - private: double opacity_; double gain_; @@ -158,11 +147,9 @@ private: bool is_key_; bool deinterlace_; blend_mode::type blend_mode_; - alpha_mode::type alpha_mode_; }; image_transform::blend_mode::type get_blend_mode(const std::wstring& str); -image_transform::alpha_mode::type get_alpha_mode(const std::wstring& str); image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener); diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index 49d0b41e1..c5f206ca9 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -342,19 +342,6 @@ bool MixerCommand::DoExecute() int layer = GetLayerIndex(); GetChannel()->mixer()->apply_image_transform(GetLayerIndex(), transform); } - else if(_parameters[1] == L"ALPHA") - { - auto blend_str = _parameters.at(2); - - auto transform = [=](image_transform transform) -> image_transform - { - transform.set_alpha_mode(get_alpha_mode(blend_str)); - return transform; - }; - - int layer = GetLayerIndex(); - GetChannel()->mixer()->apply_image_transform(GetLayerIndex(), transform); - } else if(_parameters[1] == L"BRIGHTNESS") { auto value = boost::lexical_cast(_parameters.at(2));