1 #include "../../StdAfx.h"
\r
3 #include "image_kernel.h"
\r
5 #include "image_transform.h"
\r
7 #include <common/exception/exceptions.h>
\r
8 #include <common/gl/gl_check.h>
\r
12 #include <boost/noncopyable.hpp>
\r
14 #include <unordered_map>
\r
16 namespace caspar { namespace core {
\r
18 class shader_program
\r
23 shader_program() : program_(0) {}
\r
24 shader_program(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)
\r
28 const char* vertex_source = vertex_source_str.c_str();
\r
30 auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
\r
32 GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));
\r
33 GL(glCompileShaderARB(vertex_shader));
\r
35 GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
\r
36 if (success == GL_FALSE)
\r
39 GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));
\r
40 GL(glDeleteObjectARB(vertex_shader));
\r
41 std::stringstream str;
\r
42 str << "Failed to compile vertex shader:" << std::endl << info << std::endl;
\r
43 BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));
\r
46 const char* fragment_source = fragment_source_str.c_str();
\r
48 auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
\r
50 GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));
\r
51 GL(glCompileShaderARB(fragmemt_shader));
\r
53 GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
\r
54 if (success == GL_FALSE)
\r
57 GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));
\r
58 GL(glDeleteObjectARB(fragmemt_shader));
\r
59 std::stringstream str;
\r
60 str << "Failed to compile fragment shader:" << std::endl << info << std::endl;
\r
61 BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));
\r
64 program_ = glCreateProgramObjectARB();
\r
66 GL(glAttachObjectARB(program_, vertex_shader));
\r
67 GL(glAttachObjectARB(program_, fragmemt_shader));
\r
69 GL(glLinkProgramARB(program_));
\r
71 GL(glDeleteObjectARB(vertex_shader));
\r
72 GL(glDeleteObjectARB(fragmemt_shader));
\r
74 GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));
\r
75 if (success == GL_FALSE)
\r
78 GL(glGetInfoLogARB(program_, sizeof(info), 0, info));
\r
79 GL(glDeleteObjectARB(program_));
\r
80 std::stringstream str;
\r
81 str << "Failed to link shader program:" << std::endl << info << std::endl;
\r
82 BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));
\r
84 GL(glUseProgramObjectARB(program_));
\r
85 glUniform1i(glGetUniformLocation(program_, "plane[0]"), 0);
\r
86 glUniform1i(glGetUniformLocation(program_, "plane[1]"), 1);
\r
87 glUniform1i(glGetUniformLocation(program_, "plane[2]"), 2);
\r
88 glUniform1i(glGetUniformLocation(program_, "plane[3]"), 3);
\r
91 GLint get_location(const char* name)
\r
93 GLint loc = glGetUniformLocation(program_, name);
\r
97 shader_program& operator=(shader_program&& other)
\r
99 program_ = other.program_;
\r
100 other.program_ = 0;
\r
106 glDeleteProgram(program_);
\r
111 GL(glUseProgramObjectARB(program_));
\r
115 GLubyte progressive_pattern[] = {
\r
116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
\r
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
\r
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
\r
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
\r
121 GLubyte upper_pattern[] = {
\r
122 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
\r
123 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
\r
124 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
\r
125 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};
\r
127 GLubyte lower_pattern[] = {
\r
128 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
\r
129 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
\r
130 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
\r
131 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
\r
133 struct image_kernel::implementation
\r
135 std::unordered_map<pixel_format::type, shader_program> shaders_;
\r
138 std::unordered_map<pixel_format::type, shader_program>& shaders()
\r
140 GL(glEnable(GL_POLYGON_STIPPLE));
\r
141 GL(glEnable(GL_BLEND));
\r
142 GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
\r
144 if(shaders_.empty())
\r
146 std::string common_vertex =
\r
149 " gl_TexCoord[0] = gl_MultiTexCoord0; "
\r
150 " gl_FrontColor = gl_Color; "
\r
151 " gl_Position = ftransform(); "
\r
154 std::string common_fragment =
\r
155 "uniform sampler2D plane[4]; "
\r
156 "uniform float color_gain; "
\r
158 // NOTE: YCbCr, ITU-R, http://www.intersil.com/data/an/an9717.pdf
\r
159 // TODO: Support for more yuv formats might be needed.
\r
160 "vec4 ycbcra_to_bgra(float y, float cb, float cr, float a) "
\r
164 " y = 1.164*(y-0.0625); "
\r
167 " color.r = y + 1.596 * cr; "
\r
168 " color.g = y - 0.813 * cr - 0.337633 * cb; "
\r
169 " color.b = y + 2.017 * cb; "
\r
176 shaders_[pixel_format::abgr] = shader_program(common_vertex, common_fragment +
\r
180 " vec4 abgr = texture2D(plane[0], gl_TexCoord[0].st); "
\r
181 " gl_FragColor = abgr.argb * color_gain; "
\r
184 shaders_[pixel_format::argb]= shader_program(common_vertex, common_fragment +
\r
188 " vec4 argb = texture2D(plane[0], gl_TexCoord[0].st); "
\r
189 " gl_FragColor = argb.grab * gl_Color * color_gain; "
\r
192 shaders_[pixel_format::bgra]= shader_program(common_vertex, common_fragment +
\r
196 " vec4 bgra = texture2D(plane[0], gl_TexCoord[0].st); "
\r
197 " gl_FragColor = bgra.rgba * gl_Color * color_gain; "
\r
200 shaders_[pixel_format::rgba] = shader_program(common_vertex, common_fragment +
\r
204 " vec4 rgba = texture2D(plane[0], gl_TexCoord[0].st); "
\r
205 " gl_FragColor = rgba.bgra * gl_Color * color_gain; "
\r
208 shaders_[pixel_format::ycbcr] = shader_program(common_vertex, common_fragment +
\r
212 " float y = texture2D(plane[0], gl_TexCoord[0].st).r;"
\r
213 " float cb = texture2D(plane[1], gl_TexCoord[0].st).r;"
\r
214 " float cr = texture2D(plane[2], gl_TexCoord[0].st).r;"
\r
215 " float a = 1.0; "
\r
216 " gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color * color_gain;"
\r
219 shaders_[pixel_format::ycbcra] = shader_program(common_vertex, common_fragment +
\r
223 " float y = texture2D(plane[0], gl_TexCoord[0].st).r;"
\r
224 " float cb = texture2D(plane[1], gl_TexCoord[0].st).r;"
\r
225 " float cr = texture2D(plane[2], gl_TexCoord[0].st).r;"
\r
226 " float a = texture2D(plane[3], gl_TexCoord[0].st).r;"
\r
227 " gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color * color_gain;"
\r
234 image_kernel::image_kernel() : impl_(new implementation()){}
\r
236 void image_kernel::apply(pixel_format::type pix_fmt, const image_transform& transform)
\r
238 impl_->shaders()[pix_fmt].use();
\r
240 GL(glUniform1f(impl_->shaders()[pix_fmt].get_location("color_gain"), static_cast<GLfloat>(transform.get_gain())));
\r
242 if(transform.get_mode() == video_mode::upper)
\r
243 glPolygonStipple(upper_pattern);
\r
244 else if(transform.get_mode() == video_mode::lower)
\r
245 glPolygonStipple(lower_pattern);
\r
247 glPolygonStipple(progressive_pattern);
\r