From: Ronag Date: Sun, 14 Aug 2011 13:44:59 +0000 (+0000) Subject: 2.0. - blend_modes are re-enabled. X-Git-Tag: 2.0.1~172 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=517174ad8f15d5b6f71cdf8bc04a158cbe4bd278;p=casparcg 2.0. - blend_modes are re-enabled. - comapbility mode is re-enabled. - Mayor optimization to blend modes using texture barrier. - blend modes are disabled by default. - Misc gpu related optimizations. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1168 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/core/mixer/gpu/device_buffer.cpp b/core/mixer/gpu/device_buffer.cpp index a03c11677..67ca643dc 100644 --- a/core/mixer/gpu/device_buffer.cpp +++ b/core/mixer/gpu/device_buffer.cpp @@ -21,7 +21,6 @@ #include "device_buffer.h" -#include "host_buffer.h" #include "fence.h" #include @@ -64,7 +63,6 @@ public: GL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT[stride_], width_, height_, 0, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL)); GL(glBindTexture(GL_TEXTURE_2D, 0)); CASPAR_LOG(debug) << "[device_buffer] allocated size:" << width*height*stride; - clear(); } ~implementation() @@ -95,29 +93,14 @@ public: GL(glBindTexture(GL_TEXTURE_2D, 0)); } - void begin_read(host_buffer& source) + void begin_read() { bind(); - source.unmap(); - source.bind(); GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL)); - source.unbind(); unbind(); fence_.set(); - //GL(glFlush()); } - void attach(int index) - { - GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, id_, 0)); - } - - void clear() - { - attach(0); - GL(glClear(GL_COLOR_BUFFER_BIT)); - } - bool ready() const { return fence_.ready(); @@ -128,13 +111,12 @@ device_buffer::device_buffer(size_t width, size_t height, size_t stride) : impl_ size_t device_buffer::stride() const { return impl_->stride_; } size_t device_buffer::width() const { return impl_->width_; } size_t device_buffer::height() const { return impl_->height_; } -void device_buffer::attach(int index){impl_->attach(index);} void device_buffer::bind(){impl_->bind();} void device_buffer::bind(int index){impl_->bind(index);} void device_buffer::unbind(){impl_->unbind();} -void device_buffer::begin_read(host_buffer& source){impl_->begin_read(source);} -void device_buffer::clear(){impl_->clear();} +void device_buffer::begin_read(){impl_->begin_read();} bool device_buffer::ready() const{return impl_->ready();} +int device_buffer::id() const{ return impl_->id_;} }} \ No newline at end of file diff --git a/core/mixer/gpu/device_buffer.h b/core/mixer/gpu/device_buffer.h index 1f1df5200..0959c0374 100644 --- a/core/mixer/gpu/device_buffer.h +++ b/core/mixer/gpu/device_buffer.h @@ -27,8 +27,6 @@ namespace caspar { namespace core { -class host_buffer; - class device_buffer : boost::noncopyable { public: @@ -40,17 +38,15 @@ public: void bind(); void bind(int index); void unbind(); - - void clear(); - - void attach(int index = 0); - - void begin_read(host_buffer& source); + + void begin_read(); bool ready() const; private: friend class ogl_device; device_buffer(size_t width, size_t height, size_t stride); + int id() const; + struct implementation; safe_ptr impl_; }; diff --git a/core/mixer/gpu/host_buffer.cpp b/core/mixer/gpu/host_buffer.cpp index 72c2aa947..e1695f07f 100644 --- a/core/mixer/gpu/host_buffer.cpp +++ b/core/mixer/gpu/host_buffer.cpp @@ -114,17 +114,13 @@ public: GL(glBindBuffer(target_, 0)); } - void begin_read(device_buffer& source) + void begin_read(size_t width, size_t height, GLuint format) { - source.attach(0); - source.bind(); unmap(); bind(); - GL(glReadPixels(0, 0, source.width(), source.height(), format(source.stride()), GL_UNSIGNED_BYTE, NULL)); + GL(glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, NULL)); unbind(); - source.unbind(); fence_.set(); - //GL(glFlush()); } bool ready() const @@ -140,7 +136,7 @@ void host_buffer::map(){impl_->map();} void host_buffer::unmap(){impl_->unmap();} void host_buffer::bind(){impl_->bind();} void host_buffer::unbind(){impl_->unbind();} -void host_buffer::begin_read(device_buffer& source){impl_->begin_read(source);} +void host_buffer::begin_read(size_t width, size_t height, GLuint format){impl_->begin_read(width, height, format);} size_t host_buffer::size() const { return impl_->size_; } bool host_buffer::ready() const{return impl_->ready();} void host_buffer::wait(ogl_device& ogl){impl_->wait(ogl);} diff --git a/core/mixer/gpu/host_buffer.h b/core/mixer/gpu/host_buffer.h index 66bfb2de6..4566e2c38 100644 --- a/core/mixer/gpu/host_buffer.h +++ b/core/mixer/gpu/host_buffer.h @@ -26,7 +26,6 @@ namespace caspar { namespace core { class ogl_device; -class device_buffer; class host_buffer : boost::noncopyable { @@ -47,7 +46,7 @@ public: void map(); void unmap(); - void begin_read(device_buffer& source); + void begin_read(size_t width, size_t height, unsigned int format); bool ready() const; void wait(ogl_device& ogl); private: diff --git a/core/mixer/gpu/ogl_device.cpp b/core/mixer/gpu/ogl_device.cpp index 95beaa70e..1f2698d53 100644 --- a/core/mixer/gpu/ogl_device.cpp +++ b/core/mixer/gpu/ogl_device.cpp @@ -21,6 +21,8 @@ #include "ogl_device.h" +#include "shader.h" + #include #include #include @@ -31,8 +33,16 @@ namespace caspar { namespace core { -ogl_device::ogl_device() : executor_(L"ogl_device") +ogl_device::ogl_device() + : executor_(L"ogl_device") + , pattern_(nullptr) + , attached_texture_(0) + , active_shader_(0) { + std::fill(binded_textures_.begin(), binded_textures_.end(), 0); + std::fill(viewport_.begin(), viewport_.end(), 0); + std::fill(scissor_.begin(), scissor_.end(), 0); + invoke([=] { context_.reset(new sf::Context()); @@ -204,4 +214,83 @@ std::wstring ogl_device::get_version() return ver; } -}} \ No newline at end of file + +void ogl_device::enable(GLenum cap) +{ + auto& val = caps_[cap]; + if(!val) + { + glEnable(cap); + val = true; + } +} + +void ogl_device::disable(GLenum cap) +{ + auto& val = caps_[cap]; + if(val) + { + glDisable(cap); + val = false; + } +} + +void ogl_device::viewport(size_t x, size_t y, size_t width, size_t height) +{ + if(x != viewport_[0] || y != viewport_[1] || width != viewport_[2] || height != viewport_[3]) + { + glViewport(x, y, width, height); + viewport_[0] = x; + viewport_[1] = y; + viewport_[2] = width; + viewport_[3] = height; + } +} + +void ogl_device::scissor(size_t x, size_t y, size_t width, size_t height) +{ + if(x != scissor_[0] || y != scissor_[1] || width != scissor_[2] || height != scissor_[3]) + { + glScissor(x, y, width, height); + scissor_[0] = x; + scissor_[1] = y; + scissor_[2] = width; + scissor_[3] = height; + } +} + +void ogl_device::stipple_pattern(const GLubyte* pattern) +{ + if(pattern_ != pattern) + { + glPolygonStipple(pattern); + pattern_ = pattern; + } +} + +void ogl_device::attach(device_buffer& texture) +{ + if(attached_texture_ != texture.id()) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, texture.id(), 0); + attached_texture_ = texture.id(); + } +} + +void ogl_device::clear(device_buffer& texture) +{ + attach(texture); + glClear(GL_COLOR_BUFFER_BIT); +} + +void ogl_device::use(shader& shader) +{ + if(active_shader_ != shader.id()) + { + glUseProgramObjectARB(shader.id()); + active_shader_ = shader.id(); + } +} + +}} + diff --git a/core/mixer/gpu/ogl_device.h b/core/mixer/gpu/ogl_device.h index 5d6e55a6d..efb188a43 100644 --- a/core/mixer/gpu/ogl_device.h +++ b/core/mixer/gpu/ogl_device.h @@ -32,13 +32,26 @@ #include #include +#include + +#include #include "../../dependencies\SFML-1.6\include\SFML/Window/Context.hpp" namespace caspar { namespace core { +class shader; + class ogl_device : boost::noncopyable { + std::unordered_map caps_; + std::array viewport_; + std::array scissor_; + const GLubyte* pattern_; + GLint attached_texture_; + GLint active_shader_; + std::array binded_textures_; + std::unique_ptr context_; std::array>>>, 4> device_pools_; @@ -51,7 +64,23 @@ class ogl_device : boost::noncopyable public: ogl_device(); ~ogl_device(); + + // Not thread-safe, must be called inside of context + void enable(GLenum cap); + void disable(GLenum cap); + void viewport(size_t x, size_t y, size_t width, size_t height); + void scissor(size_t x, size_t y, size_t width, size_t height); + void stipple_pattern(const GLubyte* pattern); + + void attach(device_buffer& texture); + void clear(device_buffer& texture); + + void begin_read(host_buffer& dest, device_buffer& source); + void begin_read(device_buffer& dest, host_buffer& source); + void use(shader& shader); + + // thread-afe template auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future // noexcept { diff --git a/core/mixer/gpu/shader.cpp b/core/mixer/gpu/shader.cpp index b15942a59..03f34dc23 100644 --- a/core/mixer/gpu/shader.cpp +++ b/core/mixer/gpu/shader.cpp @@ -91,12 +91,7 @@ public: it = locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first; return it->second; } - - void use() - { - GL(glUseProgramObjectARB(program_)); - } - + void set(const std::string& name, int value) { GL(glUniform1i(get_location(name.c_str()), value)); @@ -115,9 +110,9 @@ 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::use(){impl_->use();} 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);} +int shader::id() const{return impl_->program_;} }} \ No newline at end of file diff --git a/core/mixer/gpu/shader.h b/core/mixer/gpu/shader.h index caea024b9..0595edbcc 100644 --- a/core/mixer/gpu/shader.h +++ b/core/mixer/gpu/shader.h @@ -12,13 +12,15 @@ class shader : boost::noncopyable { public: shader(const std::string& vertex_source_str, const std::string& fragment_source_str); - void use(); void set(const std::string& name, int value); void set(const std::string& name, float value); void set(const std::string& name, double value); private: + friend class ogl_device; struct implementation; safe_ptr impl_; + + int id() const; }; }} \ No newline at end of file diff --git a/core/mixer/image/blending_glsl.h b/core/mixer/image/blending_glsl.h index 485693fff..86b4b9613 100644 --- a/core/mixer/image/blending_glsl.h +++ b/core/mixer/image/blending_glsl.h @@ -1,5 +1,49 @@ #pragma once +static std::string get_adjustement_glsl() +{ + return + "\n /* " + "\n ** Contrast, saturation, brightness " + "\n ** Code of this function is from TGM's shader pack " + "\n ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057 " + "\n */ " + "\n " + "\n vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con) " + "\n { " + "\n const float AvgLumR = 0.5; " + "\n const float AvgLumG = 0.5; " + "\n const float AvgLumB = 0.5; " + "\n " + "\n const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721); " + "\n " + "\n vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB); " + "\n vec3 brtColor = color * brt; " + "\n vec3 intensity = vec3(dot(brtColor, LumCoeff)); " + "\n vec3 satColor = mix(intensity, brtColor, sat); " + "\n vec3 conColor = mix(AvgLumin, satColor, con); " + "\n return conColor; " + "\n } " + "\n " + "\n /* " + "\n ** Gamma correction " + "\n ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/ " + "\n */ " + "\n " + "\n#define GammaCorrection(color, gamma) pow(color, vec3(1.0 / gamma)) \n " + "\n " + "\n /* " + "\n ** Levels control (input (+gamma), output) " + "\n ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/ " + "\n */ " + "\n " + "\n#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0)) \n " + "\n#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma) \n " + "\n#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(vec3(minOutput), vec3(maxOutput), color) \n " + "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput) \n " + ; +} + static std::string get_blend_glsl() { static std::string glsl = @@ -114,28 +158,7 @@ static std::string get_blend_glsl() "\n return rgb; " "\n } " "\n " - "\n " - "\n /* " - "\n ** Contrast, saturation, brightness " - "\n ** Code of this function is from TGM's shader pack " - "\n ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057 " - "\n */ " - "\n " - "\n vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con) " - "\n { " - "\n const float AvgLumR = 0.5; " - "\n const float AvgLumG = 0.5; " - "\n const float AvgLumB = 0.5; " - "\n " - "\n const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721); " - "\n " - "\n vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB); " - "\n vec3 brtColor = color * brt; " - "\n vec3 intensity = vec3(dot(brtColor, LumCoeff)); " - "\n vec3 satColor = mix(intensity, brtColor, sat); " - "\n vec3 conColor = mix(AvgLumin, satColor, con); " - "\n return conColor; " - "\n } " + "\n " "\n " "\n " "\n /* " @@ -219,24 +242,7 @@ static std::string get_blend_glsl() "\n vec3 baseHSL = RGBToHSL(base); " "\n return HSLToRGB(vec3(baseHSL.r, baseHSL.g, RGBToHSL(blend).b)); " "\n } " - "\n " - "\n " - "\n /* " - "\n ** Gamma correction " - "\n ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/ " - "\n */ " - "\n " - "\n#define GammaCorrection(color, gamma) pow(color, vec3(1.0 / gamma)) \n " - "\n " - "\n /* " - "\n ** Levels control (input (+gamma), output) " - "\n ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/ " - "\n */ " - "\n " - "\n#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0)) \n " - "\n#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma) \n " - "\n#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(vec3(minOutput), vec3(maxOutput), color) \n " - "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput) \n " + "\n " ; return glsl; diff --git a/core/mixer/image/image_kernel.cpp b/core/mixer/image/image_kernel.cpp index bc23ad20f..2777bb3c4 100644 --- a/core/mixer/image/image_kernel.cpp +++ b/core/mixer/image/image_kernel.cpp @@ -24,9 +24,11 @@ #include "blending_glsl.h" #include "../gpu/shader.h" #include "../gpu/device_buffer.h" +#include "../gpu/ogl_device.h" #include #include +#include #include #include @@ -36,6 +38,8 @@ #include +#include + #include namespace caspar { namespace core { @@ -55,75 +59,82 @@ GLubyte lower_pattern[] = { struct image_kernel::implementation : boost::noncopyable { std::unique_ptr shader_; - - core::video_mode::type last_mode_; - size_t last_width_; - size_t last_height_; - - //std::string get_blend_color_func() - //{ - // return - // - // 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_color(vec4 fore) \n" - // "{ \n" - // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n" - // " fore.rgb = get_blend_color(back.bgr, fore.rgb); \n" - // " \n" - // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n" - // "} \n"; - //} - // - //std::string get_simple_blend_color_func() - //{ - // return - - // "vec4 blend_color(vec4 fore) \n" - // "{ \n" - // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n" - // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n" - // "} \n"; - //} + 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() { @@ -138,12 +149,12 @@ struct image_kernel::implementation : boost::noncopyable "} \n"; } - std::string get_fragment(bool compability_mode) + std::string get_fragment() { return "#version 120 \n" - //"uniform sampler2D background; \n" + "uniform sampler2D background; \n" "uniform sampler2D plane[4]; \n" "uniform sampler2D local_key; \n" "uniform sampler2D layer_key; \n" @@ -151,8 +162,8 @@ struct image_kernel::implementation : boost::noncopyable "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 blend_mode; \n" + "uniform int alpha_mode; \n" "uniform int pixel_format; \n" " \n" "uniform bool levels; \n" @@ -170,10 +181,11 @@ struct image_kernel::implementation : boost::noncopyable + - get_blend_glsl() + (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" @@ -276,20 +288,40 @@ struct image_kernel::implementation : boost::noncopyable " 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" - " gl_FragColor = color.bgra * gl_Color; \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); - implementation() - : last_mode_(core::video_mode::progressive) - , last_width_(0) - , last_height_(0) - { + 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(const render_item& item, + + void draw(ogl_device& ogl, + render_item&& item, const safe_ptr& background, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) @@ -305,45 +337,18 @@ struct image_kernel::implementation : boost::noncopyable return; if(!shader_) - { - try - { - shader_.reset(new shader(get_vertex(), get_fragment(false))); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes."; - shader_.reset(new shader(get_vertex(), get_fragment(true))); - } + init_shader(ogl); - GL(glEnable(GL_TEXTURE_2D)); - GL(glEnable(GL_BLEND)); - GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE)); - } - - if(last_mode_ != item.mode) + if(item.mode == core::video_mode::progressive) + ogl.disable(GL_POLYGON_STIPPLE); + else { - last_mode_ = item.mode; - - if(item.mode == core::video_mode::progressive) - GL(glDisable(GL_POLYGON_STIPPLE)); - else - { - GL(glEnable(GL_POLYGON_STIPPLE)); - - if(item.mode == core::video_mode::upper) - glPolygonStipple(upper_pattern); - else if(item.mode == core::video_mode::lower) - glPolygonStipple(lower_pattern); - } - } + ogl.enable(GL_POLYGON_STIPPLE); - if(last_width_ != background->width() || last_height_ != background->height()) - { - last_width_ = background->width(); - last_height_ = background->height(); - GL(glViewport(0, 0, background->width(), background->height())); + 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 @@ -356,12 +361,10 @@ struct image_kernel::implementation : boost::noncopyable if(layer_key) layer_key->bind(5); - - //background->bind(6); - + // Setup shader - shader_->use(); + ogl.use(*shader_); shader_->set("plane[0]", 0); shader_->set("plane[1]", 1); @@ -369,13 +372,21 @@ struct image_kernel::implementation : boost::noncopyable shader_->set("plane[3]", 3); shader_->set("local_key", 4); shader_->set("layer_key", 5); - //shader_->set("background", 6); 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("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("pixel_format", item.pix_desc.pix_fmt); + + // Setup blend_func + + if(blend_modes_) + { + 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()); + } auto levels = item.transform.get_levels(); @@ -409,6 +420,8 @@ struct image_kernel::implementation : boost::noncopyable shader_->set("csb", false); // Setup drawing area + + ogl.viewport(0, 0, background->width(), background->height()); GL(glColor4d(item.transform.get_gain(), item.transform.get_gain(), item.transform.get_gain(), item.transform.get_opacity())); @@ -423,8 +436,8 @@ struct image_kernel::implementation : boost::noncopyable double w = static_cast(background->width()); double h = static_cast(background->height()); - GL(glEnable(GL_SCISSOR_TEST)); - GL(glScissor(static_cast(m_p[0]*w), static_cast(m_p[1]*h), static_cast(m_s[0]*w), static_cast(m_s[1]*h))); + ogl.enable(GL_SCISSOR_TEST); + ogl.scissor(static_cast(m_p[0]*w), static_cast(m_p[1]*h), static_cast(m_s[0]*w), static_cast(m_s[1]*h)); } auto f_p = item.transform.get_fill_translation(); @@ -439,15 +452,20 @@ 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(); - if(scissor) - GL(glDisable(GL_SCISSOR_TEST)); + 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. } }; image_kernel::image_kernel() : impl_(new implementation()){} -void image_kernel::draw(const render_item& item, const safe_ptr& background, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) +void image_kernel::draw(ogl_device& ogl, render_item&& item, const safe_ptr& background, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) { - impl_->draw(item, background, local_key, layer_key); + impl_->draw(ogl, std::move(item), background, local_key, layer_key); } bool operator==(const render_item& lhs, const render_item& rhs) diff --git a/core/mixer/image/image_kernel.h b/core/mixer/image/image_kernel.h index a612fc01b..07078e870 100644 --- a/core/mixer/image/image_kernel.h +++ b/core/mixer/image/image_kernel.h @@ -29,6 +29,7 @@ namespace caspar { namespace core { class device_buffer; +class ogl_device; struct render_item { @@ -58,7 +59,7 @@ class image_kernel : boost::noncopyable { public: image_kernel(); - void draw(const render_item& item, const safe_ptr& background, const std::shared_ptr& local_key = nullptr, const std::shared_ptr& layer_key = nullptr); + void draw(ogl_device& ogl, render_item&& item, const safe_ptr& background, const std::shared_ptr& local_key = nullptr, const std::shared_ptr& layer_key = nullptr); private: struct implementation; safe_ptr impl_; diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index 326128672..f9676e068 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -52,22 +52,22 @@ namespace caspar { namespace core { struct image_mixer::implementation : boost::noncopyable { - typedef std::deque layer; + typedef std::deque layer; - video_channel_context& channel_; + video_channel_context& channel_; - std::vector transform_stack_; - std::vector mode_stack_; + std::vector transform_stack_; + std::vector mode_stack_; - std::deque> layers_; // layer/stream/items + std::deque> layers_; // layer/stream/items - image_kernel kernel_; + image_kernel kernel_; - std::array,2> draw_buffer_; - std::shared_ptr write_buffer_; + std::shared_ptr draw_buffer_; + std::shared_ptr write_buffer_; - std::array,2> local_key_buffer_; - std::shared_ptr layer_key_buffer_; + std::shared_ptr local_key_buffer_; + std::shared_ptr layer_key_buffer_; public: implementation(video_channel_context& video_channel) @@ -87,10 +87,8 @@ public: { write_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); layer_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1); - draw_buffer_[0] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); - //draw_buffer_[1] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); - local_key_buffer_[0] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1); - //local_key_buffer_[1] = 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); channel_.ogl().gc(); } @@ -143,21 +141,21 @@ public: if(channel_.get_format_desc().width != write_buffer_->width() || channel_.get_format_desc().height != write_buffer_->height()) initialize_buffers(); - layer_key_buffer_->clear(); - draw_buffer_[0]->clear(); - //draw_buffer_[1]->clear(); - local_key_buffer_[0]->clear(); - //local_key_buffer_[1]->clear(); - + channel_.ogl().clear(*layer_key_buffer_); + channel_.ogl().clear(*local_key_buffer_); + channel_.ogl().clear(*draw_buffer_); + bool layer_key = false; - + BOOST_FOREACH(auto& layer, layers) draw(std::move(layer), layer_key); - std::swap(draw_buffer_[0], write_buffer_); + std::swap(draw_buffer_, write_buffer_); auto host_buffer = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only); - host_buffer->begin_read(*write_buffer_); + + channel_.ogl().attach(*write_buffer_); + host_buffer->begin_read(write_buffer_->width(), write_buffer_->height(), format(write_buffer_->stride())); GL(glFlush()); @@ -167,15 +165,15 @@ public: void draw(layer&& layer, bool& layer_key) { bool local_key = false; - - local_key_buffer_[0]->clear(); + + channel_.ogl().clear(*local_key_buffer_); BOOST_FOREACH(auto& item, layer) draw(std::move(item), local_key, layer_key); layer_key = local_key; - std::swap(local_key_buffer_[0], layer_key_buffer_); + std::swap(local_key_buffer_, layer_key_buffer_); } void draw(render_item&& item, bool& local_key, bool& layer_key) @@ -187,14 +185,13 @@ public: } else { - draw(draw_buffer_, std::move(item), local_key ? local_key_buffer_[0] : nullptr, layer_key ? layer_key_buffer_ : nullptr); - local_key_buffer_[0]->clear(); + draw(draw_buffer_, std::move(item), local_key ? local_key_buffer_ : nullptr, layer_key ? layer_key_buffer_ : nullptr); + channel_.ogl().clear(*local_key_buffer_); local_key = false; } - channel_.ogl().yield(); // Return resources to pool as early as possible. } - void draw(std::array,2>& targets, render_item&& item, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) + void draw(std::shared_ptr& target, render_item&& item, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) { if(!std::all_of(item.textures.begin(), item.textures.end(), std::mem_fn(&device_buffer::ready))) { @@ -202,18 +199,8 @@ public: channel_.ogl().yield(); // Try to give it some more time. } - targets[0]->attach(); - kernel_.draw(item, make_safe(targets[0]), local_key, layer_key); - - //targets[1]->attach(); - - //kernel_.draw(item, make_safe(targets[0]), local_key, layer_key); - - //targets[0]->bind(); - - //glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, targets[0]->width(), targets[0]->height()); - - //std::swap(targets[0], targets[1]); + channel_.ogl().attach(*target); + kernel_.draw(channel_.ogl(), std::move(item), make_safe(target), local_key, layer_key); } safe_ptr create_frame(const void* tag, const core::pixel_format_desc& desc) diff --git a/core/mixer/write_frame.cpp b/core/mixer/write_frame.cpp index 0a63d8fd9..1bb3a8a5d 100644 --- a/core/mixer/write_frame.cpp +++ b/core/mixer/write_frame.cpp @@ -109,7 +109,10 @@ struct write_frame::implementation ogl_->begin_invoke([=] { - texture->begin_read(*buffer); + buffer->unmap(); + buffer->bind(); + texture->begin_read(); + buffer->unbind(); }, high_priority); } diff --git a/core/video_channel.cpp b/core/video_channel.cpp index 45d3b9158..23c1f16e4 100644 --- a/core/video_channel.cpp +++ b/core/video_channel.cpp @@ -63,9 +63,9 @@ public: { diag_->add_guide("produce-time", 0.5f); diag_->set_color("produce-time", diagnostics::color(1.0f, 0.0f, 0.0f)); - diag_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 1.0f)); - diag_->set_color("output-time", diagnostics::color(1.0f, 1.0f, 0.0f)); diag_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f)); + diag_->set_color("output-time", diagnostics::color(1.0f, 0.5f, 0.0f)); + diag_->set_color("mix-time", diagnostics::color(0.0f, 1.0f, 0.0f)); CASPAR_LOG(info) << print() << " Successfully Initialized."; context_.execution().begin_invoke([this]{tick();}); @@ -118,6 +118,7 @@ public: CASPAR_LOG(error) << context_.print() << L" Unexpected exception. Clearing stage and freeing memory"; stage_->clear(); context_.ogl().gc().wait(); + mixer_ = make_safe(context_); } context_.execution().begin_invoke([this]{tick();});