Commit 89392b2a authored by Alexey Ershov's avatar Alexey Ershov

added convertToGLBuffer() & convertFromGLBuffer() functions; added OpenGL interop sample comment

rewrite & change convertFromGLBuffer() & convertToGLBuffer() into acquireGLBuffer() & releaseGLBuffer(), respectively

opengl sample: added buffer support

tested and fixed buffer support on Windows

change glFlush() call to glFinish()

added UMat::release() call; fixed functions' names

adopted & implemented API suggestion(s) from Alexander

fixed unreachable code warning

added more info to the mapGLBuffer/unmapGLBuffer description
parent ca692b98
......@@ -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
/*
// 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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment