\r
namespace caspar { namespace core {\r
\r
-GLenum FORMAT[] = {0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGR, GL_BGRA};\r
-GLenum INTERNAL_FORMAT[] = {0, GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8}; \r
+static GLenum FORMAT[] = {0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGR, GL_BGRA};\r
+static GLenum INTERNAL_FORMAT[] = {0, GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8}; \r
+\r
+GLenum format(size_t stride)\r
+{\r
+ return FORMAT[stride];\r
+}\r
\r
struct device_buffer::implementation : boost::noncopyable\r
{\r
const size_t height_;\r
const size_t stride_;\r
\r
+ fence fence_;\r
+\r
public:\r
implementation(size_t width, size_t height, size_t stride) \r
: width_(width)\r
GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL));\r
source.unbind();\r
GL(glBindTexture(GL_TEXTURE_2D, 0));\r
+ fence_.set();\r
+ GL(glFlush());\r
}\r
\r
- void write(host_buffer& target)\r
- {\r
- attach(0);\r
- GL(glBindTexture(GL_TEXTURE_2D, id_));\r
- target.unmap();\r
- target.bind();\r
- GL(glReadPixels(0, 0, width_, height_, FORMAT[stride_], GL_UNSIGNED_BYTE, NULL));\r
- target.unbind();\r
- GL(glBindTexture(GL_TEXTURE_2D, 0));\r
- target.fence();\r
- }\r
-\r
void attach(int index)\r
{\r
GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, id_, 0));\r
attach(0);\r
GL(glClear(GL_COLOR_BUFFER_BIT));\r
}\r
+\r
+ bool ready() const\r
+ {\r
+ return fence_.ready();\r
+ }\r
};\r
\r
device_buffer::device_buffer(size_t width, size_t height, size_t stride) : impl_(new implementation(width, height, stride)){}\r
void device_buffer::bind(int index){impl_->bind(index);}\r
void device_buffer::unbind(){impl_->unbind();}\r
void device_buffer::read(host_buffer& source){impl_->read(source);}\r
-void device_buffer::write(host_buffer& target){impl_->write(target);}\r
void device_buffer::clear(){impl_->clear();}\r
+bool device_buffer::ready() const{return impl_->ready();}\r
+\r
\r
}}
\ No newline at end of file
\r
#include <memory>\r
\r
-namespace caspar { namespace core {\r
+#include "GL/glew.h"\r
\r
+namespace caspar { namespace core {\r
+ \r
class host_buffer;\r
\r
class device_buffer : boost::noncopyable\r
void clear();\r
\r
void attach(int index = 0);\r
+\r
void read(host_buffer& source);\r
- void write(host_buffer& target);\r
- \r
+ bool ready() const;\r
private:\r
friend class ogl_device;\r
device_buffer(size_t width, size_t height, size_t stride);\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
};\r
+ \r
+GLenum format(size_t stride);\r
\r
}}
\ No newline at end of file
\r
bool ready() const\r
{\r
+ if(!sync_)\r
+ return true;\r
+\r
GLsizei length = 0;\r
int values[] = {0};\r
\r
GL(glGetSynciv(sync_, GL_SYNC_STATUS, 1, &length, values));\r
\r
- return sync_ ? values[0] == GL_SIGNALED : true;\r
+ return values[0] == GL_SIGNALED;\r
}\r
\r
void wait(ogl_device& ogl)\r
}\r
\r
if(delay > 0)\r
- CASPAR_LOG(warning) << L"[ogl_device] Performance warning. GPU was not ready during requested host read-back. Delayed by atleast: " << delay << L" ms.";\r
+ CASPAR_LOG(warning) << L"[fence] Performance warning. GPU was not ready during requested host read-back. Delayed by atleast: " << delay << L" ms.";\r
}\r
};\r
\r
if(GLEW_ARB_sync)\r
impl_.reset(new implementation());\r
else\r
- CASPAR_LOG(warning) << "GL_SYNC not supported, running without fences. This might cause performance degradation when running multiple channels.";\r
+ CASPAR_LOG(warning) << "[fence] GL_SYNC not supported, running without fences. This might cause performance degradation when running multiple channels and short buffer depth.";\r
\r
}\r
\r
#include "host_buffer.h"\r
\r
#include "fence.h"\r
+#include "device_buffer.h"\r
#include "ogl_device.h"\r
\r
#include <common/gl/gl_check.h>\r
void* data_;\r
GLenum usage_;\r
GLenum target_;\r
- core::fence fence_;\r
+ fence fence_;\r
\r
public:\r
implementation(size_t size, usage_t usage) \r
BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target_ OpenGL Pixel Buffer Object."));\r
}\r
\r
- void map2(ogl_device& ogl)\r
+ void wait(ogl_device& ogl)\r
{\r
fence_.wait(ogl);\r
- ogl.invoke(std::bind(&implementation::map, this), high_priority);\r
}\r
\r
void unmap()\r
GL(glBindBuffer(target_, 0));\r
}\r
\r
- void fence()\r
+ void read(device_buffer& source)\r
{\r
+ source.attach(0);\r
+ source.bind();\r
+ unmap();\r
+ bind();\r
+ GL(glReadPixels(0, 0, source.width(), source.height(), format(source.stride()), GL_UNSIGNED_BYTE, NULL));\r
+ unbind();\r
+ source.unbind();\r
fence_.set();\r
GL(glFlush());\r
}\r
+\r
+ bool ready() const\r
+ {\r
+ return fence_.ready();\r
+ }\r
};\r
\r
host_buffer::host_buffer(size_t size, usage_t usage) : impl_(new implementation(size, usage)){}\r
const void* host_buffer::data() const {return impl_->data_;}\r
void* host_buffer::data() {return impl_->data_;}\r
void host_buffer::map(){impl_->map();}\r
-void host_buffer::map(ogl_device& ogl){impl_->map2(ogl);}\r
void host_buffer::unmap(){impl_->unmap();}\r
void host_buffer::bind(){impl_->bind();}\r
void host_buffer::unbind(){impl_->unbind();}\r
-void host_buffer::fence(){impl_->fence();}\r
+void host_buffer::read(device_buffer& source){impl_->read(source);}\r
size_t host_buffer::size() const { return impl_->size_; }\r
+bool host_buffer::ready() const{return impl_->ready();}\r
+void host_buffer::wait(ogl_device& ogl){impl_->wait(ogl);}\r
\r
}}
\ No newline at end of file
namespace caspar { namespace core {\r
\r
class ogl_device;\r
+class device_buffer;\r
\r
class host_buffer : boost::noncopyable\r
{\r
void unbind();\r
\r
void map();\r
- void map(ogl_device& ogl);\r
void unmap();\r
-\r
- void fence();\r
+ \r
+ void read(device_buffer& source);\r
+ bool ready() const;\r
+ void wait(ogl_device& ogl);\r
private:\r
friend class ogl_device;\r
host_buffer(size_t size, usage_t usage);\r
\r
std::swap(draw_buffer_[0], write_buffer_);\r
\r
- // device -> host. \r
- write_buffer_->write(*read_buffer);\r
+ // device -> host. \r
+ read_buffer->read(*write_buffer_);\r
\r
return read_buffer;\r
}\r
\r
void render_item(std::array<std::shared_ptr<device_buffer>,2>& targets, render_item&& item, const std::shared_ptr<device_buffer>& local_key, const std::shared_ptr<device_buffer>& layer_key)\r
{\r
+ BOOST_FOREACH(auto& texture, item.textures)\r
+ {\r
+ if(!texture->ready())\r
+ {\r
+ CASPAR_LOG(warning) << L"[image_mixer] Performance warning. Host to device transfer not complete, GPU will be stalled";\r
+ channel_.ogl().yield(); // Try to give it some more time.\r
+ }\r
+ }\r
+\r
targets[1]->attach();\r
\r
kernel_.draw(item, make_safe(targets[0]), local_key, layer_key);\r
const boost::iterator_range<const uint8_t*> image_data()\r
{\r
if(!image_data_->data())\r
- image_data_->map(ogl_);\r
+ {\r
+ image_data_->wait(ogl_);\r
+ ogl_.invoke([=]{image_data_->map();}, high_priority);\r
+ }\r
\r
auto ptr = static_cast<const uint8_t*>(image_data_->data());\r
return boost::iterator_range<const uint8_t*>(ptr, ptr + image_data_->size());\r
return impl_ ? impl_->audio_data() : boost::iterator_range<const int16_t*>();\r
}\r
\r
-size_t read_frame::image_size() const{return impl_->image_data_->size();}\r
+size_t read_frame::image_size() const{return impl_ ? impl_->image_data_->size() : 0;}\r
\r
//#include <tbb/scalable_allocator.h>\r
//#include <tbb/parallel_for.h>\r