From c7fb663cf5ac746964b8cef7ecb6fed2f2a7bf97 Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Wed, 24 Jun 2020 00:37:16 +0200 Subject: [PATCH] Implementation of Pixel Buffer Object for Media Player. --- MediaPlayer.cpp | 116 +++++++++++++++++++++++++++++++++++++++---- MediaPlayer.h | 6 +++ RenderingManager.cpp | 14 ++++++ RenderingManager.h | 1 + 4 files changed, 127 insertions(+), 10 deletions(-) diff --git a/MediaPlayer.cpp b/MediaPlayer.cpp index 209d289..9377322 100644 --- a/MediaPlayer.cpp +++ b/MediaPlayer.cpp @@ -57,6 +57,12 @@ MediaPlayer::MediaPlayer(string name) : id_(name) current_segment_ = segments_.begin(); v_frame_.buffer = nullptr; + // no PBO by default + pbo_[0] = pbo_[1] = 0; + pbo_size_ = 0; + pbo_index_ = 0; + pbo_next_index_ = 1; + textureindex_ = 0; } @@ -475,6 +481,69 @@ std::list< std::pair > MediaPlayer::getPlaySegments() const return ret; } +void MediaPlayer::init_texture() +{ + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &textureindex_); + glBindTexture(GL_TEXTURE_2D, textureindex_); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, + 0, GL_RGBA, GL_UNSIGNED_BYTE, v_frame_.data[0]); + + + if (!isimage_ && Rendering::supportsPBO()) { + + // need to fill image size + pbo_size_ = height_ * width_ * 4; + + // create 2 pixel buffer objects, + glGenBuffers(2, pbo_); + // create first PBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[0]); + // glBufferDataARB with NULL pointer reserves only memory space. + glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size_, 0, GL_STREAM_DRAW); + // fill in with reset picture + GLubyte* ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (ptr) { + // update data directly on the mapped buffer + memmove(ptr, v_frame_.data[0], pbo_size_); + // release pointer to mapping buffer + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + } + else { + // did not work, disable PBO + glDeleteBuffers(2, pbo_); + pbo_[0] = pbo_[1] = 0; + pbo_size_ = 0; + } + + // idem with second PBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[1]); + glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size_, 0, GL_STREAM_DRAW); + ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (ptr) { + memmove(ptr, v_frame_.data[0], pbo_size_); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + } + else { + // did not work, disable PBO + glDeleteBuffers(2, pbo_); + pbo_[0] = pbo_[1] = 0; + pbo_size_ = 0; + } + + // should be good to go, wrap it up + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + pbo_index_ = 0; + pbo_next_index_ = 1; + + Log::Info("Using PBO"); + } + +} + void MediaPlayer::update() { // discard @@ -495,19 +564,46 @@ void MediaPlayer::update() if (v_frame_is_full_) { // first occurence; create texture if (textureindex_==0) { - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &textureindex_); - glBindTexture(GL_TEXTURE_2D, textureindex_); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, - 0, GL_RGBA, GL_UNSIGNED_BYTE, v_frame_.data[0]); + init_texture(); } - else // bind texture + // all other times, bind and fill texture + else { glBindTexture(GL_TEXTURE_2D, textureindex_); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, + + if (pbo_size_ > 0) { + + // bind PBO to read pixels + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[pbo_index_]); + + // copy pixels from PBO to texture object + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + // bind the next PBO to write pixels + // NB : equivalent but faster (memmove instead of memcpy ?) than + // glNamedBufferSubData(pboIds[nextIndex], 0, imgsize, vp->getBuffer()) + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[pbo_next_index_]); + glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size_, 0, GL_STREAM_DRAW); + + // map the buffer object into client's memory + GLubyte* ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (ptr) { + // update data directly on the mapped buffer + memmove(ptr, v_frame_.data[0], pbo_size_); + // release pointer to mapping buffer + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + // In dual PBO mode, increment current index first then get the next index + pbo_index_ = (pbo_index_ + 1) % 2; + pbo_next_index_ = (pbo_index_ + 1) % 2; + } + else + // without PBO, use standard opengl (slower) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, v_frame_.data[0]); } diff --git a/MediaPlayer.h b/MediaPlayer.h index f98e57c..a60e9e1 100644 --- a/MediaPlayer.h +++ b/MediaPlayer.h @@ -253,6 +253,11 @@ private: std::atomic v_frame_is_full_; std::atomic need_loop_; + // for PBO + guint pbo_[2]; + guint pbo_index_, pbo_next_index_; + guint pbo_size_; + MediaSegmentSet segments_; MediaSegmentSet::iterator current_segment_; @@ -263,6 +268,7 @@ private: bool interlaced_; bool enabled_; + void init_texture(); void execute_open(); void execute_loop_command(); void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE); diff --git a/RenderingManager.cpp b/RenderingManager.cpp index 7e6c099..4890e39 100644 --- a/RenderingManager.cpp +++ b/RenderingManager.cpp @@ -691,6 +691,20 @@ void RenderingWindow::draw(FrameBuffer *fb) glfwMakeContextCurrent(master_); } + +bool Rendering::supportsPBO() +{ + static int support_extension = -1; + if (support_extension < 0) { + if (GLAD_GL_ARB_pixel_buffer_object || GLAD_GL_EXT_pixel_buffer_object) + support_extension = 1; + else + support_extension = 0; + } + + return support_extension == 1; +} + // // Discarded because not working under OSX - kept in case it would become useful // diff --git a/RenderingManager.h b/RenderingManager.h index 100ca0a..e00f1b0 100644 --- a/RenderingManager.h +++ b/RenderingManager.h @@ -130,6 +130,7 @@ public: // unproject from window coordinate glm::vec3 unProject(glm::vec2 screen_coordinate, glm::mat4 modelview = glm::mat4(1.f)); + static bool supportsPBO(); private: