X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fmixer%2Fgpu%2Fogl_device.cpp;h=d74d5fd9649b77cd534b9164ad1edc9311d8f026;hb=5391bc8ee9d44c6622a33db7efdb91f7bf99fa18;hp=692bb3a53424c64c90050b57a7bbf8f6414cfeec;hpb=0b6c8422d829280ed7edcb330fd08ce30b1467b5;p=casparcg diff --git a/core/mixer/gpu/ogl_device.cpp b/core/mixer/gpu/ogl_device.cpp index 692bb3a53..d74d5fd96 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 -ogl_device::ogl_device() : executor_(L"ogl_device") +namespace caspar { namespace core { + +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,6 +72,7 @@ ogl_device::~ogl_device() pool.clear(); BOOST_FOREACH(auto& pool, host_pools_) pool.clear(); + glDeleteFramebuffersEXT(1, &fbo_); }); } @@ -55,48 +80,272 @@ safe_ptr ogl_device::create_device_buffer(size_t width, size_t he { 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)) { executor_.invoke([&] - { - buffer = std::make_shared(width, height, stride); - }); + { + 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; + } + } + }, high_priority); } - - return safe_ptr(buffer.get(), [=](device_buffer*){pool->push(buffer);}); + + ++pool->usage_count; + + return safe_ptr(buffer.get(), [=](device_buffer*) mutable + { + pool->items.push(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)) { executor_.invoke([&] { - buffer = std::make_shared(size, usage); - if(usage == host_buffer::write_only) - buffer->map(); - else - buffer->unmap(); - }); + try + { + buffer.reset(new host_buffer(size, usage)); + if(usage == host_buffer::write_only) + buffer->map(); + else + buffer->unmap(); + } + catch(...) + { + try + { + 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; + } + } + }, high_priority); } + + ++pool->usage_count; - return safe_ptr(buffer.get(), [=](host_buffer*) + return safe_ptr(buffer.get(), [=](host_buffer*) mutable { - executor_.begin_invoke([=] - { + executor_.begin_invoke([=]() mutable + { if(usage == host_buffer::write_only) buffer->map(); else buffer->unmap(); - pool->push(buffer); - }); + + pool->items.push(buffer); + }, high_priority); }); } -}} \ No newline at end of file +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([=] + { + CASPAR_LOG(info) << " ogl: Running GC."; + + try + { + 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(); + } +} + +void ogl_device::blend_func_separate(int c1, int c2, int a1, int a2) +{ + std::array func = {c1, c2, a1, a2}; + + if(blend_func_ != func) + { + blend_func_ = func; + glBlendFuncSeparate(c1, c2, a1, a2); + } +} + +}} +