--- /dev/null
+#include "../../../stdafx.h"\r
+\r
+#include "shader.h"\r
+\r
+#include <common/gl/gl_check.h>\r
+\r
+#include <unordered_map>\r
+\r
+namespace caspar { namespace core {\r
+\r
+struct shader::implementation : boost::noncopyable\r
+{\r
+ GLuint program_;\r
+ std::unordered_map<std::string, GLint> locations_;\r
+public:\r
+\r
+ implementation(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)\r
+ {\r
+ GLint success;\r
+ \r
+ const char* vertex_source = vertex_source_str.c_str();\r
+ \r
+ auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);\r
+ \r
+ GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));\r
+ GL(glCompileShaderARB(vertex_shader));\r
+\r
+ GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ std::stringstream str;\r
+ str << "Failed to compile vertex shader:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
+ }\r
+ \r
+ const char* fragment_source = fragment_source_str.c_str();\r
+ \r
+ auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);\r
+ \r
+ GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));\r
+ GL(glCompileShaderARB(fragmemt_shader));\r
+\r
+ GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+ std::stringstream str;\r
+ str << "Failed to compile fragment shader:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
+ }\r
+ \r
+ program_ = glCreateProgramObjectARB();\r
+ \r
+ GL(glAttachObjectARB(program_, vertex_shader));\r
+ GL(glAttachObjectARB(program_, fragmemt_shader));\r
+\r
+ GL(glLinkProgramARB(program_));\r
+ \r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+\r
+ GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(program_, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(program_));\r
+ std::stringstream str;\r
+ str << "Failed to link shader program:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
+ }\r
+ GL(glUseProgramObjectARB(program_));\r
+ }\r
+ \r
+ ~implementation()\r
+ {\r
+ glDeleteProgram(program_);\r
+ }\r
+\r
+ GLint get_location(const char* name)\r
+ {\r
+ auto it = locations_.find(name);\r
+ if(it == locations_.end())\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
+ void set(const std::string& name, int value)\r
+ {\r
+ GL(glUniform1i(get_location(name.c_str()), value));\r
+ }\r
+ \r
+ void set(const std::string& name, float value)\r
+ {\r
+ GL(glUniform1f(get_location(name.c_str()), value));\r
+ }\r
+};\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
+\r
+}}
\ No newline at end of file
}\r
\r
virtual safe_ptr<core::basic_frame> receive()\r
- {\r
- frame_timer_.restart();\r
+ { \r
+ // "receive" is called on the same thread as the gpu mixer runs. Minimize "receive" time in order to allow gpu and cpu to run in parallel. \r
+ task_group_.wait();\r
\r
- auto result = decode_frame();\r
- \r
- graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*frame_factory_->get_video_format_desc().fps*0.5));\r
+ auto result = get_frame();\r
+\r
+ task_group_.run([=]\r
+ {\r
+ frame_timer_.restart();\r
+ decode_packets();\r
+ graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*frame_factory_->get_video_format_desc().fps*0.5));\r
+ }); \r
\r
return result;\r
}\r
return frame;\r
}\r
\r
- safe_ptr<core::basic_frame> decode_frame()\r
+ safe_ptr<core::basic_frame> get_frame()\r
{ \r
- // "receive" is called on the same thread as the gpu mixer runs. Minimize "receive" time in order to allow gpu and cpu to run in parallel. \r
- task_group_.wait();\r
- task_group_.run([=]\r
- {\r
- decode_packets();\r
- });\r
-\r
if(video_decoder_ && audio_decoder_ && !video_frames_.empty() && !audio_chunks_.empty())\r
{\r
auto audio_chunk = std::move(audio_chunks_.front().second);\r