\r
#include "device_buffer.h"\r
\r
-#include "host_buffer.h"\r
#include "fence.h"\r
\r
#include <common/exception/exceptions.h>\r
GL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT[stride_], width_, height_, 0, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL));\r
GL(glBindTexture(GL_TEXTURE_2D, 0));\r
CASPAR_LOG(debug) << "[device_buffer] allocated size:" << width*height*stride; \r
- clear();\r
} \r
\r
~implementation()\r
GL(glBindTexture(GL_TEXTURE_2D, 0));\r
}\r
\r
- void begin_read(host_buffer& source)\r
+ void begin_read()\r
{\r
bind();\r
- source.unmap();\r
- source.bind();\r
GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL));\r
- source.unbind();\r
unbind();\r
fence_.set();\r
- //GL(glFlush());\r
}\r
\r
- void attach(int index)\r
- {\r
- GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, id_, 0));\r
- }\r
-\r
- void clear()\r
- {\r
- attach(0);\r
- GL(glClear(GL_COLOR_BUFFER_BIT));\r
- }\r
-\r
bool ready() const\r
{\r
return fence_.ready();\r
size_t device_buffer::stride() const { return impl_->stride_; }\r
size_t device_buffer::width() const { return impl_->width_; }\r
size_t device_buffer::height() const { return impl_->height_; }\r
-void device_buffer::attach(int index){impl_->attach(index);}\r
void device_buffer::bind(){impl_->bind();}\r
void device_buffer::bind(int index){impl_->bind(index);}\r
void device_buffer::unbind(){impl_->unbind();}\r
-void device_buffer::begin_read(host_buffer& source){impl_->begin_read(source);}\r
-void device_buffer::clear(){impl_->clear();}\r
+void device_buffer::begin_read(){impl_->begin_read();}\r
bool device_buffer::ready() const{return impl_->ready();}\r
+int device_buffer::id() const{ return impl_->id_;}\r
\r
\r
}}
\ No newline at end of file
\r
namespace caspar { namespace core {\r
\r
-class host_buffer;\r
-\r
class device_buffer : boost::noncopyable\r
{\r
public:\r
void bind();\r
void bind(int index);\r
void unbind();\r
-\r
- void clear();\r
-\r
- void attach(int index = 0);\r
-\r
- void begin_read(host_buffer& source);\r
+ \r
+ void begin_read();\r
bool ready() const;\r
private:\r
friend class ogl_device;\r
device_buffer(size_t width, size_t height, size_t stride);\r
\r
+ int id() const;\r
+\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
};\r
GL(glBindBuffer(target_, 0));\r
}\r
\r
- void begin_read(device_buffer& source)\r
+ void begin_read(size_t width, size_t height, GLuint format)\r
{\r
- source.attach(0);\r
- source.bind();\r
unmap();\r
bind();\r
- GL(glReadPixels(0, 0, source.width(), source.height(), format(source.stride()), GL_UNSIGNED_BYTE, NULL));\r
+ GL(glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, NULL));\r
unbind();\r
- source.unbind();\r
fence_.set();\r
- //GL(glFlush());\r
}\r
\r
bool ready() const\r
void host_buffer::unmap(){impl_->unmap();}\r
void host_buffer::bind(){impl_->bind();}\r
void host_buffer::unbind(){impl_->unbind();}\r
-void host_buffer::begin_read(device_buffer& source){impl_->begin_read(source);}\r
+void host_buffer::begin_read(size_t width, size_t height, GLuint format){impl_->begin_read(width, height, format);}\r
size_t host_buffer::size() const { return impl_->size_; }\r
bool host_buffer::ready() const{return impl_->ready();}\r
void host_buffer::wait(ogl_device& ogl){impl_->wait(ogl);}\r
namespace caspar { namespace core {\r
\r
class ogl_device;\r
-class device_buffer;\r
\r
class host_buffer : boost::noncopyable\r
{\r
void map();\r
void unmap();\r
\r
- void begin_read(device_buffer& source);\r
+ void begin_read(size_t width, size_t height, unsigned int format);\r
bool ready() const;\r
void wait(ogl_device& ogl);\r
private:\r
\r
#include "ogl_device.h"\r
\r
+#include "shader.h"\r
+\r
#include <common/exception/exceptions.h>\r
#include <common/utility/assert.h>\r
#include <common/gl/gl_check.h>\r
\r
namespace caspar { namespace core {\r
\r
-ogl_device::ogl_device() : executor_(L"ogl_device")\r
+ogl_device::ogl_device() \r
+ : executor_(L"ogl_device")\r
+ , pattern_(nullptr)\r
+ , attached_texture_(0)\r
+ , active_shader_(0)\r
{\r
+ std::fill(binded_textures_.begin(), binded_textures_.end(), 0);\r
+ std::fill(viewport_.begin(), viewport_.end(), 0);\r
+ std::fill(scissor_.begin(), scissor_.end(), 0);\r
+ \r
invoke([=]\r
{\r
context_.reset(new sf::Context());\r
return ver;\r
}\r
\r
-}}
\ No newline at end of file
+\r
+void ogl_device::enable(GLenum cap)\r
+{\r
+ auto& val = caps_[cap];\r
+ if(!val)\r
+ {\r
+ glEnable(cap);\r
+ val = true;\r
+ }\r
+}\r
+\r
+void ogl_device::disable(GLenum cap)\r
+{\r
+ auto& val = caps_[cap];\r
+ if(val)\r
+ {\r
+ glDisable(cap);\r
+ val = false;\r
+ }\r
+}\r
+\r
+void ogl_device::viewport(size_t x, size_t y, size_t width, size_t height)\r
+{\r
+ if(x != viewport_[0] || y != viewport_[1] || width != viewport_[2] || height != viewport_[3])\r
+ { \r
+ glViewport(x, y, width, height);\r
+ viewport_[0] = x;\r
+ viewport_[1] = y;\r
+ viewport_[2] = width;\r
+ viewport_[3] = height;\r
+ }\r
+}\r
+\r
+void ogl_device::scissor(size_t x, size_t y, size_t width, size_t height)\r
+{\r
+ if(x != scissor_[0] || y != scissor_[1] || width != scissor_[2] || height != scissor_[3])\r
+ { \r
+ glScissor(x, y, width, height);\r
+ scissor_[0] = x;\r
+ scissor_[1] = y;\r
+ scissor_[2] = width;\r
+ scissor_[3] = height;\r
+ }\r
+}\r
+\r
+void ogl_device::stipple_pattern(const GLubyte* pattern)\r
+{\r
+ if(pattern_ != pattern)\r
+ { \r
+ glPolygonStipple(pattern);\r
+ pattern_ = pattern;\r
+ }\r
+}\r
+\r
+void ogl_device::attach(device_buffer& texture)\r
+{ \r
+ if(attached_texture_ != texture.id())\r
+ {\r
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, texture.id(), 0);\r
+ attached_texture_ = texture.id();\r
+ }\r
+}\r
+\r
+void ogl_device::clear(device_buffer& texture)\r
+{ \r
+ attach(texture);\r
+ glClear(GL_COLOR_BUFFER_BIT);\r
+}\r
+\r
+void ogl_device::use(shader& shader)\r
+{\r
+ if(active_shader_ != shader.id())\r
+ { \r
+ glUseProgramObjectARB(shader.id()); \r
+ active_shader_ = shader.id();\r
+ }\r
+}\r
+\r
+}}\r
+\r
#include <boost/thread/future.hpp>\r
\r
#include <array>\r
+#include <unordered_map>\r
+\r
+#include <gl/glew.h>\r
\r
#include "../../dependencies\SFML-1.6\include\SFML/Window/Context.hpp"\r
\r
namespace caspar { namespace core {\r
\r
+class shader;\r
+\r
class ogl_device : boost::noncopyable\r
{ \r
+ std::unordered_map<GLenum, bool> caps_;\r
+ std::array<size_t, 4> viewport_;\r
+ std::array<size_t, 4> scissor_;\r
+ const GLubyte* pattern_;\r
+ GLint attached_texture_;\r
+ GLint active_shader_;\r
+ std::array<GLint, 16> binded_textures_;\r
+\r
std::unique_ptr<sf::Context> context_;\r
\r
std::array<tbb::concurrent_unordered_map<size_t, safe_ptr<tbb::concurrent_bounded_queue<std::shared_ptr<device_buffer>>>>, 4> device_pools_;\r
public: \r
ogl_device();\r
~ogl_device();\r
+\r
+ // Not thread-safe, must be called inside of context\r
+ void enable(GLenum cap);\r
+ void disable(GLenum cap);\r
+ void viewport(size_t x, size_t y, size_t width, size_t height);\r
+ void scissor(size_t x, size_t y, size_t width, size_t height);\r
+ void stipple_pattern(const GLubyte* pattern);\r
+\r
+ void attach(device_buffer& texture);\r
+ void clear(device_buffer& texture);\r
+\r
+ void begin_read(host_buffer& dest, device_buffer& source);\r
+ void begin_read(device_buffer& dest, host_buffer& source);\r
\r
+ void use(shader& shader);\r
+\r
+ // thread-afe\r
template<typename Func>\r
auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
{ \r
it = locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first;\r
return it->second;\r
}\r
-\r
- void use()\r
- { \r
- GL(glUseProgramObjectARB(program_)); \r
- }\r
-\r
+ \r
void set(const std::string& name, int value)\r
{\r
GL(glUniform1i(get_location(name.c_str()), value));\r
\r
\r
shader::shader(const std::string& vertex_source_str, const std::string& fragment_source_str) : impl_(new implementation(vertex_source_str, fragment_source_str)){}\r
-void shader::use(){impl_->use();}\r
void shader::set(const std::string& name, int value){impl_->set(name, value);}\r
void shader::set(const std::string& name, float value){impl_->set(name, value);}\r
void shader::set(const std::string& name, double value){impl_->set(name, value);}\r
+int shader::id() const{return impl_->program_;}\r
\r
}}
\ No newline at end of file
{\r
public:\r
shader(const std::string& vertex_source_str, const std::string& fragment_source_str);\r
- void use();\r
void set(const std::string& name, int value);\r
void set(const std::string& name, float value);\r
void set(const std::string& name, double value);\r
private:\r
+ friend class ogl_device;\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
+\r
+ int id() const;\r
};\r
\r
}}
\ No newline at end of file
#pragma once\r
\r
+static std::string get_adjustement_glsl()\r
+{\r
+ return \r
+ "\n /* "\r
+ "\n ** Contrast, saturation, brightness "\r
+ "\n ** Code of this function is from TGM's shader pack "\r
+ "\n ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057 "\r
+ "\n */ "\r
+ "\n "\r
+ "\n vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con) "\r
+ "\n { "\r
+ "\n const float AvgLumR = 0.5; "\r
+ "\n const float AvgLumG = 0.5; "\r
+ "\n const float AvgLumB = 0.5; "\r
+ "\n "\r
+ "\n const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721); "\r
+ "\n "\r
+ "\n vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB); "\r
+ "\n vec3 brtColor = color * brt; "\r
+ "\n vec3 intensity = vec3(dot(brtColor, LumCoeff)); "\r
+ "\n vec3 satColor = mix(intensity, brtColor, sat); "\r
+ "\n vec3 conColor = mix(AvgLumin, satColor, con); "\r
+ "\n return conColor; "\r
+ "\n } "\r
+ "\n "\r
+ "\n /* "\r
+ "\n ** Gamma correction "\r
+ "\n ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/ "\r
+ "\n */ "\r
+ "\n "\r
+ "\n#define GammaCorrection(color, gamma) pow(color, vec3(1.0 / gamma)) \n "\r
+ "\n "\r
+ "\n /* "\r
+ "\n ** Levels control (input (+gamma), output) "\r
+ "\n ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/ "\r
+ "\n */ "\r
+ "\n "\r
+ "\n#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0)) \n "\r
+ "\n#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma) \n " \r
+ "\n#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(vec3(minOutput), vec3(maxOutput), color) \n "\r
+ "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput) \n "\r
+ ;\r
+}\r
+\r
static std::string get_blend_glsl()\r
{\r
static std::string glsl = \r
"\n return rgb; "\r
"\n } "\r
"\n "\r
- "\n "\r
- "\n /* "\r
- "\n ** Contrast, saturation, brightness "\r
- "\n ** Code of this function is from TGM's shader pack "\r
- "\n ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057 "\r
- "\n */ "\r
- "\n "\r
- "\n vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con) "\r
- "\n { "\r
- "\n const float AvgLumR = 0.5; "\r
- "\n const float AvgLumG = 0.5; "\r
- "\n const float AvgLumB = 0.5; "\r
- "\n "\r
- "\n const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721); "\r
- "\n "\r
- "\n vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB); "\r
- "\n vec3 brtColor = color * brt; "\r
- "\n vec3 intensity = vec3(dot(brtColor, LumCoeff)); "\r
- "\n vec3 satColor = mix(intensity, brtColor, sat); "\r
- "\n vec3 conColor = mix(AvgLumin, satColor, con); "\r
- "\n return conColor; "\r
- "\n } "\r
+ "\n "\r
"\n "\r
"\n "\r
"\n /* "\r
"\n vec3 baseHSL = RGBToHSL(base); "\r
"\n return HSLToRGB(vec3(baseHSL.r, baseHSL.g, RGBToHSL(blend).b)); "\r
"\n } "\r
- "\n "\r
- "\n "\r
- "\n /* "\r
- "\n ** Gamma correction "\r
- "\n ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/ "\r
- "\n */ "\r
- "\n "\r
- "\n#define GammaCorrection(color, gamma) pow(color, vec3(1.0 / gamma)) \n "\r
- "\n "\r
- "\n /* "\r
- "\n ** Levels control (input (+gamma), output) "\r
- "\n ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/ "\r
- "\n */ "\r
- "\n "\r
- "\n#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0)) \n "\r
- "\n#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma) \n "\r
- "\n#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(vec3(minOutput), vec3(maxOutput), color) \n "\r
- "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput) \n "\r
+ "\n "\r
;\r
\r
return glsl;\r
#include "blending_glsl.h"\r
#include "../gpu/shader.h"\r
#include "../gpu/device_buffer.h"\r
+#include "../gpu/ogl_device.h"\r
\r
#include <common/exception/exceptions.h>\r
#include <common/gl/gl_check.h>\r
+#include <common/env.h>\r
\r
#include <core/video_format.h>\r
#include <core/producer/frame/pixel_format.h>\r
\r
#include <boost/noncopyable.hpp>\r
\r
+#include <tbb/mutex.h>\r
+\r
#include <unordered_map>\r
\r
namespace caspar { namespace core {\r
struct image_kernel::implementation : boost::noncopyable\r
{ \r
std::unique_ptr<shader> shader_;\r
- \r
- core::video_mode::type last_mode_;\r
- size_t last_width_;\r
- size_t last_height_;\r
- \r
- //std::string get_blend_color_func()\r
- //{\r
- // return \r
- // \r
- // get_blend_glsl()\r
- // \r
- // +\r
- // \r
- // "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
- // "{ \n"\r
- // " switch(blend_mode) \n"\r
- // " { \n"\r
- // " case 0: return BlendNormal(back, fore); \n"\r
- // " case 1: return BlendLighten(back, fore); \n"\r
- // " case 2: return BlendDarken(back, fore); \n"\r
- // " case 3: return BlendMultiply(back, fore); \n"\r
- // " case 4: return BlendAverage(back, fore); \n"\r
- // " case 5: return BlendAdd(back, fore); \n"\r
- // " case 6: return BlendSubstract(back, fore); \n"\r
- // " case 7: return BlendDifference(back, fore); \n"\r
- // " case 8: return BlendNegation(back, fore); \n"\r
- // " case 9: return BlendExclusion(back, fore); \n"\r
- // " case 10: return BlendScreen(back, fore); \n"\r
- // " case 11: return BlendOverlay(back, fore); \n"\r
- // //" case 12: return BlendSoftLight(back, fore); \n"\r
- // " case 13: return BlendHardLight(back, fore); \n"\r
- // " case 14: return BlendColorDodge(back, fore); \n"\r
- // " case 15: return BlendColorBurn(back, fore); \n"\r
- // " case 16: return BlendLinearDodge(back, fore); \n"\r
- // " case 17: return BlendLinearBurn(back, fore); \n"\r
- // " case 18: return BlendLinearLight(back, fore); \n"\r
- // " case 19: return BlendVividLight(back, fore); \n"\r
- // " case 20: return BlendPinLight(back, fore); \n"\r
- // " case 21: return BlendHardMix(back, fore); \n"\r
- // " case 22: return BlendReflect(back, fore); \n"\r
- // " case 23: return BlendGlow(back, fore); \n"\r
- // " case 24: return BlendPhoenix(back, fore); \n"\r
- // " case 25: return BlendHue(back, fore); \n"\r
- // " case 26: return BlendSaturation(back, fore); \n"\r
- // " case 27: return BlendColor(back, fore); \n"\r
- // " case 28: return BlendLuminosity(back, fore); \n"\r
- // " } \n"\r
- // " return BlendNormal(back, fore); \n"\r
- // "} \n"\r
- // " \n" \r
- // "vec4 blend_color(vec4 fore) \n"\r
- // "{ \n"\r
- // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
- // " fore.rgb = get_blend_color(back.bgr, fore.rgb); \n"\r
- // " \n"\r
- // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
- // "} \n";\r
- //}\r
- // \r
- //std::string get_simple_blend_color_func()\r
- //{\r
- // return \r
-\r
- // "vec4 blend_color(vec4 fore) \n"\r
- // "{ \n"\r
- // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
- // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
- // "} \n";\r
- //}\r
+ bool blend_modes_;\r
+ \r
+ implementation() : blend_modes_(true)\r
+ {\r
+ }\r
+\r
+ std::string get_blend_color_func()\r
+ {\r
+ return \r
+ \r
+ get_adjustement_glsl()\r
+ \r
+ +\r
+\r
+ get_blend_glsl()\r
+ \r
+ +\r
+ \r
+ "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
+ "{ \n"\r
+ " switch(blend_mode) \n"\r
+ " { \n"\r
+ " case 0: return BlendNormal(back, fore); \n"\r
+ " case 1: return BlendLighten(back, fore); \n"\r
+ " case 2: return BlendDarken(back, fore); \n"\r
+ " case 3: return BlendMultiply(back, fore); \n"\r
+ " case 4: return BlendAverage(back, fore); \n"\r
+ " case 5: return BlendAdd(back, fore); \n"\r
+ " case 6: return BlendSubstract(back, fore); \n"\r
+ " case 7: return BlendDifference(back, fore); \n"\r
+ " case 8: return BlendNegation(back, fore); \n"\r
+ " case 9: return BlendExclusion(back, fore); \n"\r
+ " case 10: return BlendScreen(back, fore); \n"\r
+ " case 11: return BlendOverlay(back, fore); \n"\r
+ //" case 12: return BlendSoftLight(back, fore); \n"\r
+ " case 13: return BlendHardLight(back, fore); \n"\r
+ " case 14: return BlendColorDodge(back, fore); \n"\r
+ " case 15: return BlendColorBurn(back, fore); \n"\r
+ " case 16: return BlendLinearDodge(back, fore); \n"\r
+ " case 17: return BlendLinearBurn(back, fore); \n"\r
+ " case 18: return BlendLinearLight(back, fore); \n"\r
+ " case 19: return BlendVividLight(back, fore); \n"\r
+ " case 20: return BlendPinLight(back, fore); \n"\r
+ " case 21: return BlendHardMix(back, fore); \n"\r
+ " case 22: return BlendReflect(back, fore); \n"\r
+ " case 23: return BlendGlow(back, fore); \n"\r
+ " case 24: return BlendPhoenix(back, fore); \n"\r
+ " case 25: return BlendHue(back, fore); \n"\r
+ " case 26: return BlendSaturation(back, fore); \n"\r
+ " case 27: return BlendColor(back, fore); \n"\r
+ " case 28: return BlendLuminosity(back, fore); \n"\r
+ " } \n"\r
+ " return BlendNormal(back, fore); \n"\r
+ "} \n"\r
+ " \n" \r
+ "vec4 blend(vec4 fore) \n"\r
+ "{ \n"\r
+ " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
+ " fore.rgb = get_blend_color(back.rgb, fore.rgb); \n"\r
+ " return vec4(mix(back.bgr, fore.rgb, fore.a), back.a + fore.a); \n"\r
+ "} \n";\r
+ }\r
+ \r
+ std::string get_simple_blend_color_func()\r
+ {\r
+ return \r
+ \r
+ get_adjustement_glsl()\r
+ \r
+ +\r
+\r
+ "vec4 blend(vec4 fore) \n"\r
+ "{ \n"\r
+ " return fore; \n"\r
+ "} \n";\r
+ }\r
\r
std::string get_vertex()\r
{\r
"} \n";\r
}\r
\r
- std::string get_fragment(bool compability_mode)\r
+ std::string get_fragment()\r
{\r
return\r
\r
"#version 120 \n"\r
- //"uniform sampler2D background; \n"\r
+ "uniform sampler2D background; \n"\r
"uniform sampler2D plane[4]; \n"\r
"uniform sampler2D local_key; \n"\r
"uniform sampler2D layer_key; \n"\r
"uniform bool is_hd; \n"\r
"uniform bool has_local_key; \n"\r
"uniform bool has_layer_key; \n"\r
- //"uniform int blend_mode; \n"\r
- //"uniform int alpha_mode; \n"\r
+ "uniform int blend_mode; \n"\r
+ "uniform int alpha_mode; \n"\r
"uniform int pixel_format; \n"\r
" \n"\r
"uniform bool levels; \n"\r
\r
+\r
\r
- get_blend_glsl()\r
+ (blend_modes_ ? get_blend_color_func() : get_simple_blend_color_func())\r
\r
+\r
-\r
+ \r
+ " \n"\r
"//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n"\r
"vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n"\r
"{ \n"\r
" color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n"\r
" if(has_layer_key) \n"\r
" color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n"\r
- " gl_FragColor = color.bgra * gl_Color; \n"\r
+ " color *= gl_Color; \n"\r
+ " color = blend(color); \n"\r
+ " gl_FragColor = color.bgra; \n"\r
"} \n";\r
}\r
\r
+ void init_shader(ogl_device& ogl)\r
+ {\r
+ try\r
+ { \r
+ blend_modes_ = glTextureBarrierNV ? env::properties().get("configuration.mixers.blend-modes", false) : false;\r
+ shader_.reset(new shader(get_vertex(), get_fragment()));\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
+ \r
+ blend_modes_ = false;\r
+ shader_.reset(new shader(get_vertex(), get_fragment()));\r
+ }\r
+ \r
+ ogl.enable(GL_TEXTURE_2D);\r
\r
- implementation() \r
- : last_mode_(core::video_mode::progressive)\r
- , last_width_(0)\r
- , last_height_(0)\r
- { \r
+ if(!blend_modes_)\r
+ {\r
+ ogl.enable(GL_BLEND);\r
+ GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE));\r
+ CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";\r
+ }\r
}\r
-\r
- \r
- void draw(const render_item& item,\r
+ \r
+ void draw(ogl_device& ogl,\r
+ render_item&& item,\r
const safe_ptr<device_buffer>& background,\r
const std::shared_ptr<device_buffer>& local_key, \r
const std::shared_ptr<device_buffer>& layer_key)\r
return;\r
\r
if(!shader_)\r
- {\r
- try\r
- {\r
- shader_.reset(new shader(get_vertex(), get_fragment(false)));\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
- shader_.reset(new shader(get_vertex(), get_fragment(true)));\r
- }\r
+ init_shader(ogl);\r
\r
- GL(glEnable(GL_TEXTURE_2D));\r
- GL(glEnable(GL_BLEND));\r
- GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE));\r
- }\r
-\r
- if(last_mode_ != item.mode)\r
+ if(item.mode == core::video_mode::progressive) \r
+ ogl.disable(GL_POLYGON_STIPPLE); \r
+ else \r
{\r
- last_mode_ = item.mode;\r
- \r
- if(item.mode == core::video_mode::progressive) \r
- GL(glDisable(GL_POLYGON_STIPPLE)); \r
- else \r
- {\r
- GL(glEnable(GL_POLYGON_STIPPLE)); \r
-\r
- if(item.mode == core::video_mode::upper)\r
- glPolygonStipple(upper_pattern);\r
- else if(item.mode == core::video_mode::lower)\r
- glPolygonStipple(lower_pattern);\r
- }\r
- }\r
+ ogl.enable(GL_POLYGON_STIPPLE);\r
\r
- if(last_width_ != background->width() || last_height_ != background->height())\r
- {\r
- last_width_ = background->width();\r
- last_height_ = background->height();\r
- GL(glViewport(0, 0, background->width(), background->height()));\r
+ if(item.mode == core::video_mode::upper)\r
+ ogl.stipple_pattern(upper_pattern);\r
+ else if(item.mode == core::video_mode::lower)\r
+ ogl.stipple_pattern(lower_pattern);\r
}\r
\r
// Bind textures\r
\r
if(layer_key)\r
layer_key->bind(5);\r
-\r
- //background->bind(6);\r
-\r
+ \r
// Setup shader\r
\r
- shader_->use(); \r
+ ogl.use(*shader_);\r
\r
shader_->set("plane[0]", 0);\r
shader_->set("plane[1]", 1);\r
shader_->set("plane[3]", 3);\r
shader_->set("local_key", 4);\r
shader_->set("layer_key", 5);\r
- //shader_->set("background", 6);\r
shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0);\r
shader_->set("has_local_key", local_key ? 1 : 0);\r
shader_->set("has_layer_key", layer_key ? 1 : 0);\r
- //shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode());\r
- //shader_->set("alpha_mode", item.transform.get_alpha_mode());\r
shader_->set("pixel_format", item.pix_desc.pix_fmt); \r
+ \r
+ // Setup blend_func\r
+ \r
+ if(blend_modes_)\r
+ {\r
+ background->bind(6);\r
+\r
+ shader_->set("background", 6);\r
+ shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode());\r
+ shader_->set("alpha_mode", item.transform.get_alpha_mode());\r
+ }\r
\r
auto levels = item.transform.get_levels();\r
\r
shader_->set("csb", false); \r
\r
// Setup drawing area\r
+ \r
+ ogl.viewport(0, 0, background->width(), background->height());\r
\r
GL(glColor4d(item.transform.get_gain(), item.transform.get_gain(), item.transform.get_gain(), item.transform.get_opacity()));\r
\r
double w = static_cast<double>(background->width());\r
double h = static_cast<double>(background->height());\r
\r
- GL(glEnable(GL_SCISSOR_TEST));\r
- GL(glScissor(static_cast<size_t>(m_p[0]*w), static_cast<size_t>(m_p[1]*h), static_cast<size_t>(m_s[0]*w), static_cast<size_t>(m_s[1]*h)));\r
+ ogl.enable(GL_SCISSOR_TEST);\r
+ ogl.scissor(static_cast<size_t>(m_p[0]*w), static_cast<size_t>(m_p[1]*h), static_cast<size_t>(m_s[0]*w), static_cast<size_t>(m_s[1]*h));\r
}\r
\r
auto f_p = item.transform.get_fill_translation();\r
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);\r
glEnd();\r
\r
- if(scissor)\r
- GL(glDisable(GL_SCISSOR_TEST)); \r
+ ogl.disable(GL_SCISSOR_TEST); \r
+ \r
+ item.textures.clear();\r
+ ogl.yield(); // Return resources to pool as early as possible.\r
+\r
+ if(!blend_modes_)\r
+ glTextureBarrierNV(); // This allows us to use framebuffer both as source and target while blending.\r
}\r
};\r
\r
image_kernel::image_kernel() : impl_(new implementation()){}\r
-void image_kernel::draw(const render_item& item, const safe_ptr<device_buffer>& background, const std::shared_ptr<device_buffer>& local_key, const std::shared_ptr<device_buffer>& layer_key)\r
+void image_kernel::draw(ogl_device& ogl, render_item&& item, const safe_ptr<device_buffer>& background, const std::shared_ptr<device_buffer>& local_key, const std::shared_ptr<device_buffer>& layer_key)\r
{\r
- impl_->draw(item, background, local_key, layer_key);\r
+ impl_->draw(ogl, std::move(item), background, local_key, layer_key);\r
}\r
\r
bool operator==(const render_item& lhs, const render_item& rhs)\r
namespace caspar { namespace core {\r
\r
class device_buffer;\r
+class ogl_device;\r
\r
struct render_item\r
{\r
{\r
public:\r
image_kernel();\r
- void draw(const render_item& item, const safe_ptr<device_buffer>& background, const std::shared_ptr<device_buffer>& local_key = nullptr, const std::shared_ptr<device_buffer>& layer_key = nullptr);\r
+ void draw(ogl_device& ogl, render_item&& item, const safe_ptr<device_buffer>& background, const std::shared_ptr<device_buffer>& local_key = nullptr, const std::shared_ptr<device_buffer>& layer_key = nullptr);\r
private:\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
\r
struct image_mixer::implementation : boost::noncopyable\r
{ \r
- typedef std::deque<render_item> layer;\r
+ typedef std::deque<render_item> layer;\r
\r
- video_channel_context& channel_;\r
+ video_channel_context& channel_;\r
\r
- std::vector<image_transform> transform_stack_;\r
- std::vector<video_mode::type> mode_stack_;\r
+ std::vector<image_transform> transform_stack_;\r
+ std::vector<video_mode::type> mode_stack_;\r
\r
- std::deque<std::deque<render_item>> layers_; // layer/stream/items\r
+ std::deque<std::deque<render_item>> layers_; // layer/stream/items\r
\r
- image_kernel kernel_;\r
+ image_kernel kernel_;\r
\r
- std::array<std::shared_ptr<device_buffer>,2> draw_buffer_;\r
- std::shared_ptr<device_buffer> write_buffer_;\r
+ std::shared_ptr<device_buffer> draw_buffer_;\r
+ std::shared_ptr<device_buffer> write_buffer_;\r
\r
- std::array<std::shared_ptr<device_buffer>,2> local_key_buffer_;\r
- std::shared_ptr<device_buffer> layer_key_buffer_;\r
+ std::shared_ptr<device_buffer> local_key_buffer_;\r
+ std::shared_ptr<device_buffer> layer_key_buffer_;\r
\r
public:\r
implementation(video_channel_context& video_channel) \r
{\r
write_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
layer_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
- draw_buffer_[0] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
- //draw_buffer_[1] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
- local_key_buffer_[0] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
- //local_key_buffer_[1] = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
+ draw_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
+ local_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
channel_.ogl().gc();\r
}\r
\r
if(channel_.get_format_desc().width != write_buffer_->width() || channel_.get_format_desc().height != write_buffer_->height())\r
initialize_buffers();\r
\r
- layer_key_buffer_->clear();\r
- draw_buffer_[0]->clear();\r
- //draw_buffer_[1]->clear();\r
- local_key_buffer_[0]->clear();\r
- //local_key_buffer_[1]->clear();\r
-\r
+ channel_.ogl().clear(*layer_key_buffer_);\r
+ channel_.ogl().clear(*local_key_buffer_);\r
+ channel_.ogl().clear(*draw_buffer_);\r
+ \r
bool layer_key = false;\r
-\r
+ \r
BOOST_FOREACH(auto& layer, layers)\r
draw(std::move(layer), layer_key);\r
\r
- std::swap(draw_buffer_[0], write_buffer_);\r
+ std::swap(draw_buffer_, write_buffer_);\r
\r
auto host_buffer = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only);\r
- host_buffer->begin_read(*write_buffer_);\r
+ \r
+ channel_.ogl().attach(*write_buffer_);\r
+ host_buffer->begin_read(write_buffer_->width(), write_buffer_->height(), format(write_buffer_->stride()));\r
\r
GL(glFlush());\r
\r
void draw(layer&& layer, bool& layer_key)\r
{ \r
bool local_key = false;\r
-\r
- local_key_buffer_[0]->clear();\r
+ \r
+ channel_.ogl().clear(*local_key_buffer_);\r
\r
BOOST_FOREACH(auto& item, layer)\r
draw(std::move(item), local_key, layer_key);\r
\r
layer_key = local_key;\r
\r
- std::swap(local_key_buffer_[0], layer_key_buffer_);\r
+ std::swap(local_key_buffer_, layer_key_buffer_);\r
}\r
\r
void draw(render_item&& item, bool& local_key, bool& layer_key)\r
}\r
else\r
{\r
- draw(draw_buffer_, std::move(item), local_key ? local_key_buffer_[0] : nullptr, layer_key ? layer_key_buffer_ : nullptr); \r
- local_key_buffer_[0]->clear();\r
+ draw(draw_buffer_, std::move(item), local_key ? local_key_buffer_ : nullptr, layer_key ? layer_key_buffer_ : nullptr); \r
+ channel_.ogl().clear(*local_key_buffer_);\r
local_key = false;\r
}\r
- channel_.ogl().yield(); // Return resources to pool as early as possible.\r
}\r
\r
- void draw(std::array<std::shared_ptr<device_buffer>,2>& targets, render_item&& item, const std::shared_ptr<device_buffer>& local_key, const std::shared_ptr<device_buffer>& layer_key)\r
+ void draw(std::shared_ptr<device_buffer>& target, render_item&& item, const std::shared_ptr<device_buffer>& local_key, const std::shared_ptr<device_buffer>& layer_key)\r
{\r
if(!std::all_of(item.textures.begin(), item.textures.end(), std::mem_fn(&device_buffer::ready)))\r
{\r
channel_.ogl().yield(); // Try to give it some more time.\r
} \r
\r
- targets[0]->attach();\r
- kernel_.draw(item, make_safe(targets[0]), local_key, layer_key);\r
-\r
- //targets[1]->attach();\r
- \r
- //kernel_.draw(item, make_safe(targets[0]), local_key, layer_key);\r
- \r
- //targets[0]->bind();\r
-\r
- //glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, targets[0]->width(), targets[0]->height());\r
- \r
- //std::swap(targets[0], targets[1]);\r
+ channel_.ogl().attach(*target);\r
+ kernel_.draw(channel_.ogl(), std::move(item), make_safe(target), local_key, layer_key);\r
}\r
\r
safe_ptr<write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
\r
ogl_->begin_invoke([=]\r
{ \r
- texture->begin_read(*buffer);\r
+ buffer->unmap();\r
+ buffer->bind();\r
+ texture->begin_read();\r
+ buffer->unbind();\r
}, high_priority);\r
}\r
\r
{\r
diag_->add_guide("produce-time", 0.5f); \r
diag_->set_color("produce-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
- diag_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 1.0f));\r
- diag_->set_color("output-time", diagnostics::color(1.0f, 1.0f, 0.0f));\r
diag_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f)); \r
+ diag_->set_color("output-time", diagnostics::color(1.0f, 0.5f, 0.0f));\r
+ diag_->set_color("mix-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
\r
CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
context_.execution().begin_invoke([this]{tick();});\r
CASPAR_LOG(error) << context_.print() << L" Unexpected exception. Clearing stage and freeing memory";\r
stage_->clear();\r
context_.ogl().gc().wait();\r
+ mixer_ = make_safe<caspar::core::mixer>(context_);\r
}\r
\r
context_.execution().begin_invoke([this]{tick();});\r