X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fmixer%2Fgpu%2Fogl_device.cpp;h=9f83317d91f2645e33e13530e6c354d93c549ee5;hb=0324a1c7714f2f71063c274a4e03953a6145ff9e;hp=692bb3a53424c64c90050b57a7bbf8f6414cfeec;hpb=ba4563b293f7107519bf116cc28abfc9768bb49b;p=casparcg
diff --git a/core/mixer/gpu/ogl_device.cpp b/core/mixer/gpu/ogl_device.cpp
index 692bb3a53..9f83317d9 100644
--- a/core/mixer/gpu/ogl_device.cpp
+++ b/core/mixer/gpu/ogl_device.cpp
@@ -17,26 +17,50 @@
* along with CasparCG. If not, see .
*
*/
+// TODO: Smart GC
+
#include "../../stdafx.h"
#include "ogl_device.h"
-#include
+#include "shader.h"
-#include
-#include
+#include
+#include
+#include
#include
-namespace caspar { namespace mixer {
+#include
+
+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)
{
- executor_.start();
+ std::fill(binded_textures_.begin(), binded_textures_.end(), 0);
+ std::fill(viewport_.begin(), viewport_.end(), 0);
+ std::fill(scissor_.begin(), scissor_.end(), 0);
+ std::fill(blend_func_.begin(), blend_func_.end(), 0);
+
invoke([=]
{
context_.reset(new sf::Context());
context_->SetActive(true);
+
+ if (glewInit() != GLEW_OK)
+ BOOST_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));
+
+ if(!GLEW_VERSION_3_2)
+ CASPAR_LOG(warning) << "Missing OpenGL 3.2 support.";
+
+ GL(glGenFramebuffers(1, &fbo_));
+ GL(glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_));
+ GL(glReadBuffer(GL_COLOR_ATTACHMENT0_EXT));
+ GL(glDisable(GL_MULTISAMPLE_ARB));
});
}
@@ -48,55 +72,291 @@ ogl_device::~ogl_device()
pool.clear();
BOOST_FOREACH(auto& pool, host_pools_)
pool.clear();
+ glDeleteFramebuffersEXT(1, &fbo_);
});
}
+
+safe_ptr ogl_device::allocate_device_buffer(size_t width, size_t height, size_t stride)
+{
+ std::shared_ptr buffer;
+ try
+ {
+ buffer.reset(new device_buffer(width, height, stride));
+ }
+ catch(...)
+ {
+ try
+ {
+ yield();
+ gc().wait();
+
+ // Try again
+ buffer.reset(new device_buffer(width, height, stride));
+ }
+ catch(...)
+ {
+ CASPAR_LOG(error) << L"ogl: create_device_buffer failed!";
+ throw;
+ }
+ }
+ return make_safe(buffer);
+}
safe_ptr ogl_device::create_device_buffer(size_t width, size_t height, size_t stride)
{
CASPAR_VERIFY(stride > 0 && stride < 5);
CASPAR_VERIFY(width > 0 && height > 0);
- auto pool = &device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];
+ auto& pool = device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];
std::shared_ptr buffer;
- if(!pool->try_pop(buffer))
+ if(!pool->items.try_pop(buffer))
+ buffer = executor_.invoke([&]{return allocate_device_buffer(width, height, stride);}, high_priority);
+
+ //++pool->usage_count;
+
+ return safe_ptr(buffer.get(), [=](device_buffer*) mutable
+ {
+ pool->items.push(buffer);
+ });
+}
+
+safe_ptr ogl_device::allocate_host_buffer(size_t size, host_buffer::usage_t usage)
+{
+ std::shared_ptr buffer;
+
+ try
{
- executor_.invoke([&]
+ buffer.reset(new host_buffer(size, usage));
+ if(usage == host_buffer::write_only)
+ buffer->map();
+ else
+ buffer->unmap();
+ }
+ catch(...)
+ {
+ try
{
- buffer = std::make_shared(width, height, stride);
- });
+ yield();
+ gc().wait();
+
+ // Try again
+ buffer.reset(new host_buffer(size, usage));
+ if(usage == host_buffer::write_only)
+ buffer->map();
+ else
+ buffer->unmap();
+ }
+ catch(...)
+ {
+ CASPAR_LOG(error) << L"ogl: create_host_buffer failed!";
+ throw;
+ }
}
-
- return safe_ptr(buffer.get(), [=](device_buffer*){pool->push(buffer);});
+
+ return make_safe(buffer);
}
safe_ptr ogl_device::create_host_buffer(size_t size, host_buffer::usage_t usage)
{
CASPAR_VERIFY(usage == host_buffer::write_only || usage == host_buffer::read_only);
CASPAR_VERIFY(size > 0);
- auto pool = &host_pools_[usage][size];
+ auto& pool = host_pools_[usage][size];
std::shared_ptr buffer;
- if(!pool->try_pop(buffer))
+ if(!pool->items.try_pop(buffer))
+ buffer = executor_.invoke([=]{return allocate_host_buffer(size, usage);}, high_priority);
+
+ //++pool->usage_count;
+
+ return safe_ptr(buffer.get(), [=](host_buffer*) mutable
{
- executor_.invoke([&]
- {
- buffer = std::make_shared(size, usage);
+ executor_.begin_invoke([=]() mutable
+ {
if(usage == host_buffer::write_only)
buffer->map();
else
buffer->unmap();
- });
- }
- return safe_ptr(buffer.get(), [=](host_buffer*)
+ pool->items.push(buffer);
+ }, high_priority);
+ });
+}
+
+//template
+//void flush_pool(buffer_pool& pool)
+//{
+// if(pool.flush_count.fetch_and_increment() < 16)
+// return;
+//
+// if(pool.usage_count.fetch_and_store(0) < pool.items.size())
+// {
+// std::shared_ptr buffer;
+// pool.items.try_pop(buffer);
+// }
+//
+// pool.flush_count = 0;
+// pool.usage_count = 0;
+//}
+
+void ogl_device::flush()
+{
+ GL(glFlush());
+
+ //try
+ //{
+ // BOOST_FOREACH(auto& pools, device_pools_)
+ // {
+ // BOOST_FOREACH(auto& pool, pools)
+ // flush_pool(*pool.second);
+ // }
+ // BOOST_FOREACH(auto& pools, host_pools_)
+ // {
+ // BOOST_FOREACH(auto& pool, pools)
+ // flush_pool(*pool.second);
+ // }
+ //}
+ //catch(...)
+ //{
+ // CASPAR_LOG_CURRENT_EXCEPTION();
+ //}
+}
+
+void ogl_device::yield()
+{
+ executor_.yield();
+}
+
+boost::unique_future ogl_device::gc()
+{
+ return begin_invoke([=]
{
- executor_.begin_invoke([=]
+ CASPAR_LOG(info) << " ogl: Running GC.";
+
+ try
{
- if(usage == host_buffer::write_only)
- buffer->map();
- else
- buffer->unmap();
- pool->push(buffer);
- });
- });
+ BOOST_FOREACH(auto& pools, device_pools_)
+ {
+ BOOST_FOREACH(auto& pool, pools)
+ pool.second->items.clear();
+ }
+ BOOST_FOREACH(auto& pools, host_pools_)
+ {
+ BOOST_FOREACH(auto& pool, pools)
+ pool.second->items.clear();
+ }
+ }
+ catch(...)
+ {
+ CASPAR_LOG_CURRENT_EXCEPTION();
+ }
+ }, high_priority);
+}
+
+std::wstring ogl_device::get_version()
+{
+ static std::wstring ver = L"Not found";
+ try
+ {
+ ogl_device tmp;
+ ver = widen(tmp.invoke([]{return std::string(reinterpret_cast(glGetString(GL_VERSION)));})
+ + " " + tmp.invoke([]{return std::string(reinterpret_cast(glGetString(GL_VENDOR)));}));
+ }
+ catch(...){}
+
+ return ver;
+}
+
+
+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())
+ {
+ GL(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);
+ GL(glClear(GL_COLOR_BUFFER_BIT));
+}
+
+void ogl_device::use(shader& shader)
+{
+ if(active_shader_ != shader.id())
+ {
+ GL(glUseProgramObjectARB(shader.id()));
+ active_shader_ = shader.id();
+ }
}
-}}
\ No newline at end of file
+void ogl_device::blend_func(int c1, int c2, int a1, int a2)
+{
+ std::array func = {c1, c2, a1, a2};
+
+ if(blend_func_ != func)
+ {
+ blend_func_ = func;
+ GL(glBlendFuncSeparate(c1, c2, a1, a2));
+ }
+}
+
+void ogl_device::blend_func(int c1, int c2)
+{
+ blend_func(c1, c2, c1, c2);
+}
+
+}}
+