Merge pull request #4192 from avershov:opencl-opengl-buffer

pull/4215/head
Alexander Alekhin 9 years ago
commit c0ee03fab2
  1. 21
      modules/core/include/opencv2/core/opengl.hpp
  2. 80
      modules/core/src/opengl.cpp
  3. 113
      samples/opengl/opengl_interop.cpp

@ -537,6 +537,27 @@ CV_EXPORTS void convertToGLTexture2D(InputArray src, Texture2D& texture);
*/
CV_EXPORTS void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst);
/** @brief Maps Buffer object to process on CL side (convert to UMat).
Function creates CL buffer from GL one, and then constructs UMat that can be used
to process buffer data with OpenCV functions. Note that in current implementation
UMat constructed this way doesn't own corresponding GL buffer object, so it is
the user responsibility to close down CL/GL buffers relationships by explicitly
calling unmapGLBuffer() function.
@param buffer - source Buffer object.
@param accessFlags - data access flags (ACCESS_READ|ACCESS_WRITE).
@return Returns UMat object
*/
CV_EXPORTS UMat mapGLBuffer(const Buffer& buffer, int accessFlags = ACCESS_READ|ACCESS_WRITE);
/** @brief Unmaps Buffer object (releases UMat, previously mapped from Buffer).
Function must be called explicitly by the user for each UMat previously constructed
by the call to mapGLBuffer() function.
@param u - source UMat, created by mapGLBuffer().
*/
CV_EXPORTS void unmapGLBuffer(UMat& u);
}} // namespace cv::ogl
namespace cv { namespace cuda {

@ -1804,4 +1804,84 @@ void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst)
#endif
}
//void mapGLBuffer(const Buffer& buffer, UMat& dst, int accessFlags)
UMat mapGLBuffer(const Buffer& buffer, int accessFlags)
{
(void)buffer; (void)accessFlags;
#if !defined(HAVE_OPENGL)
NO_OPENGL_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
using namespace cv::ocl;
Context& ctx = Context::getDefault();
cl_context context = (cl_context)ctx.ptr();
cl_command_queue clQueue = (cl_command_queue)Queue::getDefault().ptr();
int clAccessFlags = 0;
switch (accessFlags & (ACCESS_READ|ACCESS_WRITE))
{
default:
case ACCESS_READ|ACCESS_WRITE:
clAccessFlags = CL_MEM_READ_WRITE;
break;
case ACCESS_READ:
clAccessFlags = CL_MEM_READ_ONLY;
break;
case ACCESS_WRITE:
clAccessFlags = CL_MEM_WRITE_ONLY;
break;
}
cl_int status = 0;
cl_mem clBuffer = clCreateFromGLBuffer(context, clAccessFlags, buffer.bufId(), &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromGLBuffer failed");
gl::Finish();
status = clEnqueueAcquireGLObjects(clQueue, 1, &clBuffer, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireGLObjects failed");
size_t step = buffer.cols() * buffer.elemSize();
int rows = buffer.rows();
int cols = buffer.cols();
int type = buffer.type();
UMat u;
convertFromBuffer(clBuffer, step, rows, cols, type, u);
return u;
#endif
}
void unmapGLBuffer(UMat& u)
{
(void)u;
#if !defined(HAVE_OPENGL)
NO_OPENGL_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
using namespace cv::ocl;
cl_command_queue clQueue = (cl_command_queue)Queue::getDefault().ptr();
cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ);
u.release();
cl_int status = clEnqueueReleaseGLObjects(clQueue, 1, &clBuffer, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseGLObjects failed");
status = clFinish(clQueue);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clBuffer);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMemObject failed");
#endif
}
}} // namespace cv::ogl

@ -1,3 +1,10 @@
/*
// Sample demonstrating interoperability of OpenCV UMat with OpenGL texture.
// At first, the data obtained from video file or camera and placed onto
// OpenGL texture, following mapping of this OpenGL texture to OpenCV UMat
// and call cv::Blur function. The result is mapped back to OpenGL texture
// and rendered through OpenGL API.
*/
#if defined(WIN32) || defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
@ -25,6 +32,16 @@
# pragma comment(lib, "glu32.lib")
#endif
/*
// Press key to
// 0 no processing
// 1 processing on CPU
// 2 processing on GPU
// 9 toggle texture/buffer
// space toggle processing on/off, preserve mode
// esc quit
*/
class GLWinApp : public WinApp
{
public:
@ -33,9 +50,12 @@ public:
{
m_shutdown = false;
m_mode = 0;
m_modeStr[0] = cv::String("No processing");
m_modeStr[1] = cv::String("Processing on CPU");
m_modeStr[2] = cv::String("Processing on GPU");
m_modeStr[0] = cv::String("Texture/No processing");
m_modeStr[1] = cv::String("Texture/Processing on CPU");
m_modeStr[2] = cv::String("Texture/Processing on GPU");
m_modeStr[3] = cv::String("Buffer/No processing");
m_modeStr[4] = cv::String("Buffer/Processing on CPU");
m_modeStr[5] = cv::String("Buffer/Processing on GPU");
m_disableProcessing = false;
m_cap = cap;
}
@ -60,7 +80,12 @@ public:
case WM_CHAR:
if (wParam >= '0' && wParam <= '2')
{
m_mode = (char)wParam - '0';
set_mode((char)wParam - '0');
return 0;
}
else if (wParam == '9')
{
toggle_buffer();
return 0;
}
else if (wParam == VK_SPACE)
@ -131,13 +156,16 @@ public:
m_disableProcessing = !m_disableProcessing;
break;
case XK_0:
m_mode = 0;
set_mode(0);
break;
case XK_1:
m_mode = 1;
set_mode(1);
break;
case XK_2:
m_mode = 2;
set_mode(2);
break;
case XK_9:
toggle_buffer();
break;
case XK_Escape:
m_end_loop = true;
@ -187,14 +215,17 @@ public:
return 0;
} // init()
int get_texture(cv::ogl::Texture2D& texture)
int get_frame(cv::ogl::Texture2D& texture, cv::ogl::Buffer& buffer)
{
if (!m_cap.read(m_frame_bgr))
return -1;
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
texture.copyFrom(m_frame_rgba);
if (use_buffer())
buffer.copyFrom(m_frame_rgba);
else
texture.copyFrom(m_frame_rgba);
return 0;
}
@ -254,14 +285,16 @@ public:
int r;
cv::ogl::Texture2D texture;
cv::ogl::Buffer buffer;
r = get_texture(texture);
r = get_frame(texture, buffer);
if (r != 0)
{
return -1;
}
switch (m_mode)
bool do_buffer = use_buffer();
switch (get_mode())
{
case 0:
// no processing
@ -272,13 +305,21 @@ public:
// process video frame on CPU
cv::Mat m(m_height, m_width, CV_8UC4);
texture.copyTo(m);
if (do_buffer)
buffer.copyTo(m);
else
texture.copyTo(m);
if (!m_disableProcessing)
{
// blur texture image with OpenCV on CPU
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
}
texture.copyFrom(m);
if (do_buffer)
buffer.copyFrom(m);
else
texture.copyFrom(m);
break;
}
@ -288,19 +329,34 @@ public:
// process video frame on GPU
cv::UMat u;
cv::ogl::convertFromGLTexture2D(texture, u);
if (do_buffer)
u = cv::ogl::mapGLBuffer(buffer);
else
cv::ogl::convertFromGLTexture2D(texture, u);
if (!m_disableProcessing)
{
// blur texture image with OpenCV on GPU with OpenCL
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
}
cv::ogl::convertToGLTexture2D(u, texture);
if (do_buffer)
cv::ogl::unmapGLBuffer(u);
else
cv::ogl::convertToGLTexture2D(u, texture);
break;
}
} // switch
if (do_buffer) // buffer -> texture
{
cv::Mat m(m_height, m_width, CV_8UC4);
buffer.copyTo(m);
texture.copyFrom(m);
}
#if defined(__linux__)
XWindowAttributes window_attributes;
XGetWindowAttributes(m_display, m_window, &window_attributes);
@ -393,10 +449,35 @@ protected:
}
#endif
// modes: 0,1,2 - use texture
// 3,4,5 - use buffer
bool use_buffer()
{
return bool(m_mode >= 3);
}
void toggle_buffer()
{
if (m_mode < 3)
m_mode += 3;
else
m_mode -= 3;
}
int get_mode()
{
return (m_mode % 3);
}
void set_mode(int mode)
{
bool do_buffer = bool(m_mode >= 3);
m_mode = (mode % 3);
if (do_buffer)
m_mode += 3;
}
private:
bool m_shutdown;
int m_mode;
cv::String m_modeStr[3];
cv::String m_modeStr[3*2];
int m_disableProcessing;
#if defined(WIN32) || defined(_WIN32)
HDC m_hDC;

Loading…
Cancel
Save