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); +} + +}} +