0c6a952a90
When CL-GL interop is used, a GL context are used by two or more threads at the same time, which causes race condition. Solution: Add lock when accessing GL functions during CL-GL interop. Change-Id: I3a34da3cbdf74c401111cc4e3a04ad84cc52709e
438 строки
14 KiB
C++
438 строки
14 KiB
C++
/* Copyright (c) 2010 - 2023 Advanced Micro Devices, Inc.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE. */
|
|
|
|
#pragma once
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else //!_WIN32
|
|
#include <dlfcn.h>
|
|
#endif //!_WIN32
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glext.h>
|
|
#include "CL/cl_gl.h"
|
|
#ifndef _WIN32
|
|
#include <GL/glx.h>
|
|
#endif //!_WIN32
|
|
|
|
#include <EGL/egl.h>
|
|
#include <EGL/eglext.h>
|
|
#include <EGL/eglplatform.h>
|
|
|
|
#include "platform/context.hpp"
|
|
#include "platform/command.hpp"
|
|
|
|
namespace amd
|
|
{
|
|
|
|
//! Class GLObject keeps all the info about the GL object
|
|
//! from which the CL object is created
|
|
class GLObject : public InteropObject
|
|
{
|
|
protected:
|
|
cl_gl_object_type clGLType_; //!< CL GL object type
|
|
GLenum glTarget_;
|
|
GLuint gluiName_;
|
|
GLint gliMipLevel_;
|
|
GLenum glInternalFormat_;
|
|
GLint gliWidth_;
|
|
GLint gliHeight_;
|
|
GLint gliDepth_;
|
|
GLenum glCubemapFace_;
|
|
GLsizei glNumSamples_;
|
|
|
|
public:
|
|
//! GLObject constructor initializes member variables
|
|
GLObject(
|
|
GLenum glTarget,
|
|
GLuint gluiName,
|
|
GLint gliMipLevel,
|
|
GLenum glInternalFormat,
|
|
GLint gliWidth,
|
|
GLint gliHeight,
|
|
GLint gliDepth,
|
|
cl_gl_object_type clGLType,
|
|
GLenum glCubemapFace,
|
|
GLsizei glNumSamples
|
|
): // Initialization of member variables
|
|
clGLType_(clGLType),
|
|
glTarget_(glTarget),
|
|
gluiName_(gluiName),
|
|
gliMipLevel_(gliMipLevel),
|
|
glInternalFormat_(glInternalFormat),
|
|
gliWidth_(gliWidth),
|
|
gliHeight_(gliHeight),
|
|
gliDepth_(gliDepth),
|
|
glCubemapFace_(glCubemapFace),
|
|
glNumSamples_(glNumSamples)
|
|
{
|
|
}
|
|
|
|
virtual ~GLObject() {}
|
|
virtual GLObject* asGLObject() {return this;}
|
|
|
|
//! GLObject query functions to get GL info from member variables
|
|
GLenum getGLTarget() const {return glTarget_;}
|
|
GLuint getGLName() const {return gluiName_;}
|
|
GLint getGLMipLevel() const {return gliMipLevel_;}
|
|
GLenum getGLInternalFormat() const {return glInternalFormat_;}
|
|
GLint getGLSize() const {return gliWidth_;}
|
|
GLint getGLWidth() const {return gliWidth_;}
|
|
GLint getGLHeight() const {return gliHeight_;}
|
|
GLint getGLDepth() const {return gliDepth_;}
|
|
cl_gl_object_type getCLGLObjectType() const { return clGLType_; }
|
|
GLenum getCubemapFace() const {return glCubemapFace_;}
|
|
GLsizei getNumSamples() const { return glNumSamples_;}
|
|
};
|
|
|
|
|
|
//! Class BufferGL is drived from classes Buffer and GLObject
|
|
//! where the former keeps all data for CL object and
|
|
//! the latter keeps all data for GL object
|
|
class BufferGL : public Buffer, public GLObject
|
|
{
|
|
protected:
|
|
//! Initializes the device memory array which is nested
|
|
// after'BufferGL' object in memory layout.
|
|
virtual void initDeviceMemory();
|
|
public:
|
|
//! BufferGL constructor just calls constructors of base classes
|
|
//! to pass down the parameters
|
|
BufferGL(
|
|
Context& amdContext,
|
|
cl_mem_flags clFlags,
|
|
size_t uiSizeInBytes,
|
|
GLenum glTarget,
|
|
GLuint gluiName)
|
|
: // Call base classes constructors
|
|
Buffer(
|
|
amdContext,
|
|
clFlags,
|
|
uiSizeInBytes
|
|
),
|
|
GLObject(
|
|
glTarget,
|
|
gluiName,
|
|
0, // Mipmap level default
|
|
GL_ARRAY_BUFFER, // Just init to some value
|
|
(GLint) uiSizeInBytes,
|
|
1,
|
|
1,
|
|
CL_GL_OBJECT_BUFFER,
|
|
0,
|
|
0
|
|
)
|
|
{
|
|
setInteropObj(this);
|
|
}
|
|
virtual ~BufferGL() {}
|
|
|
|
virtual BufferGL* asBufferGL() { return this; }
|
|
};
|
|
|
|
|
|
//! Class ImageGL is derived from classes Image and GLObject
|
|
//! where the former keeps all data for CL object and
|
|
//! the latter keeps all data for GL object
|
|
class ImageGL : public Image, public GLObject
|
|
{
|
|
public:
|
|
//! ImageGL constructor just calls constructors of base classes
|
|
//! to pass down the parameters
|
|
ImageGL(
|
|
Context& amdContext,
|
|
cl_mem_object_type clType,
|
|
cl_mem_flags clFlags,
|
|
const Format& format,
|
|
size_t width,
|
|
size_t height,
|
|
size_t depth,
|
|
GLenum glTarget,
|
|
GLuint gluiName,
|
|
GLint gliMipLevel,
|
|
GLenum glInternalFormat,
|
|
cl_gl_object_type clGLType,
|
|
GLsizei numSamples,
|
|
GLenum glCubemapFace = 0)
|
|
: Image(amdContext, clType, clFlags, format, width, height, depth,
|
|
Format(format).getElementSize() * width,
|
|
Format(format).getElementSize() * width * height)
|
|
, GLObject(glTarget, gluiName, gliMipLevel, glInternalFormat,
|
|
static_cast<GLint>(width), static_cast<GLint>(height),
|
|
static_cast<GLint>(depth), clGLType, glCubemapFace,numSamples)
|
|
{
|
|
setInteropObj(this);
|
|
}
|
|
|
|
//! ImageGL constructor for mipmapped image,
|
|
//! just calls constructors of base classes to pass down the parameters
|
|
ImageGL(
|
|
Context& amdContext,
|
|
cl_mem_object_type clType,
|
|
cl_mem_flags clFlags,
|
|
const Format& format,
|
|
size_t width,
|
|
size_t height,
|
|
size_t depth,
|
|
GLenum glTarget,
|
|
GLuint gluiName,
|
|
GLint gliMipLevel,
|
|
GLenum glInternalFormat,
|
|
cl_gl_object_type clGLType,
|
|
GLsizei numSamples,
|
|
cl_int num_mip_levels,
|
|
GLenum glCubemapFace = 0)
|
|
: Image(amdContext, clType, clFlags, format, width, height, depth,
|
|
Format(format).getElementSize() * width,
|
|
Format(format).getElementSize() * width * depth, num_mip_levels)
|
|
, GLObject(glTarget, gluiName, gliMipLevel, glInternalFormat,
|
|
static_cast<GLint>(width), static_cast<GLint>(height),
|
|
static_cast<GLint>(depth), clGLType, glCubemapFace,numSamples)
|
|
{
|
|
setInteropObj(this);
|
|
}
|
|
|
|
virtual ~ImageGL() {}
|
|
|
|
protected:
|
|
//! Initializes the device memory array which is nested
|
|
// after'BufferGL' object in memory layout.
|
|
virtual void initDeviceMemory();
|
|
};
|
|
|
|
typedef EGLContext (*PFN_eglGetCurrentContext) ();
|
|
#ifdef _WIN32
|
|
#define APICALL WINAPI
|
|
#define GETPROCADDRESS GetProcAddress
|
|
#define API_GETPROCADDR "wglGetProcAddress"
|
|
#define FCN_STR_TYPE LPCSTR
|
|
typedef PROC (WINAPI* PFN_xxxGetProcAddress) (LPCSTR fcnName);
|
|
typedef HGLRC (APICALL* PFN_wglCreateContext) (HDC hdc);
|
|
typedef HGLRC (APICALL* PFN_wglGetCurrentContext) (void);
|
|
typedef HDC (APICALL* PFN_wglGetCurrentDC) (void);
|
|
typedef BOOL (APICALL* PFN_wglDeleteContext) (HGLRC hglrc);
|
|
typedef BOOL (APICALL* PFN_wglMakeCurrent) (HDC hdc, HGLRC hglrc);
|
|
typedef BOOL (APICALL* PFN_wglShareLists) (HGLRC hglrc1, HGLRC hglrc2);
|
|
#else //!_WIN32
|
|
#define APICALL // __stdcall //??? todo odintsov
|
|
#define API_GETPROCADDR "glXGetProcAddress"
|
|
#define GETPROCADDRESS dlsym
|
|
#define FCN_STR_TYPE const GLubyte*
|
|
#define WINAPI
|
|
#define PROC void*
|
|
typedef void* (*PFN_xxxGetProcAddress) (const GLubyte* procName);
|
|
// X11 typedef
|
|
typedef Display* (*PFNXOpenDisplay)(_Xconst char* display_name );
|
|
typedef int (*PFNXCloseDisplay)(Display* display );
|
|
|
|
//glx typedefs
|
|
typedef GLXDrawable (*PFNglXGetCurrentDrawable)();
|
|
typedef Display* (*PFNglXGetCurrentDisplay)();
|
|
typedef GLXContext (*PFNglXGetCurrentContext)( void );
|
|
typedef XVisualInfo* (*PFNglXChooseVisual)(Display *dpy, int screen, int *attribList);
|
|
typedef GLXContext(*PFNglXCreateContext)(Display* dpy,XVisualInfo* vis,GLXContext shareList,Bool direct);
|
|
typedef void(*PFNglXDestroyContext)(Display* dpy, GLXContext ctx);
|
|
typedef Bool(*PFNglXMakeCurrent)( Display* dpy, GLXDrawable drawable, GLXContext ctx);
|
|
typedef void* HMODULE;
|
|
#endif //!_WIN32
|
|
|
|
#define GLPREFIX(rtype, fcn, dclargs) \
|
|
typedef rtype (APICALL* PFN_##fcn) dclargs;
|
|
|
|
// Declare prototypes for GL functions
|
|
#include "gl_functions.hpp"
|
|
|
|
class GLFunctions
|
|
{
|
|
public:
|
|
//! Locks any access to the virtual GPUs
|
|
class SetIntEnv : public amd::StackObject {
|
|
public:
|
|
//! Default constructor
|
|
SetIntEnv(GLFunctions* env);
|
|
|
|
//! Destructor
|
|
~SetIntEnv();
|
|
|
|
//! Checks if the environment setup was successful
|
|
bool isValid() const { return isValid_; }
|
|
|
|
private:
|
|
GLFunctions* env_; //!< GL environment
|
|
bool isValid_; //!< If TRUE, then it's a valid setup
|
|
};
|
|
|
|
//! Locks any access to the virtual GPUs
|
|
class Lock : public amd::StackObject {
|
|
public:
|
|
//! Default constructor
|
|
Lock(GLFunctions* env);
|
|
|
|
//! Destructor
|
|
~Lock();
|
|
|
|
private:
|
|
GLFunctions* env_; //!< GL environment
|
|
};
|
|
|
|
private:
|
|
HMODULE libHandle_;
|
|
int missed_; // Indicates how many GL functions not init'ed, if any
|
|
|
|
amd::Monitor lock_;
|
|
|
|
EGLDisplay eglDisplay_;
|
|
EGLContext eglOriginalContext_;
|
|
EGLContext eglInternalContext_;
|
|
EGLContext eglTempContext_;
|
|
bool isEGL_;
|
|
PFN_eglGetCurrentContext eglGetCurrentContext_;
|
|
|
|
#ifdef _WIN32
|
|
HGLRC hOrigGLRC_;
|
|
HDC hDC_;
|
|
HGLRC hIntGLRC_; // handle for internal GLRC to access shared context
|
|
HDC tempDC_;
|
|
HGLRC tempGLRC_;
|
|
|
|
public:
|
|
PFN_wglCreateContext wglCreateContext_;
|
|
PFN_wglGetCurrentContext wglGetCurrentContext_;
|
|
PFN_wglGetCurrentDC wglGetCurrentDC_;
|
|
PFN_wglDeleteContext wglDeleteContext_;
|
|
PFN_wglMakeCurrent wglMakeCurrent_;
|
|
PFN_wglShareLists wglShareLists_;
|
|
#else
|
|
public:
|
|
Display* Dpy_;
|
|
GLXDrawable Drawable_;
|
|
GLXContext origCtx_;
|
|
Display* intDpy_;
|
|
Window intDrawable_;
|
|
GLXContext intCtx_;
|
|
Display* tempDpy_;
|
|
GLXDrawable tempDrawable_;
|
|
GLXContext tempCtx_;
|
|
|
|
//pointers to X11 functions
|
|
PFNXOpenDisplay XOpenDisplay_;
|
|
PFNXCloseDisplay XCloseDisplay_;
|
|
|
|
//pointers to GLX functions
|
|
PFNglXGetCurrentDrawable glXGetCurrentDrawable_;
|
|
PFNglXGetCurrentDisplay glXGetCurrentDisplay_;
|
|
PFNglXGetCurrentContext glXGetCurrentContext_;
|
|
PFNglXChooseVisual glXChooseVisual_;
|
|
PFNglXCreateContext glXCreateContext_;
|
|
PFNglXDestroyContext glXDestroyContext_;
|
|
PFNglXMakeCurrent glXMakeCurrent_;
|
|
#endif
|
|
public:
|
|
|
|
GLFunctions(HMODULE h, bool isEGL);
|
|
~GLFunctions();
|
|
|
|
bool update(intptr_t hglrc);
|
|
bool IsCurrentGlContext(const amd::Context::Info& info) const {
|
|
if (isEGL_) {
|
|
return ((info.hCtx_ != nullptr) && (eglGetCurrentContext_ != nullptr) &&
|
|
(info.hCtx_ == eglGetCurrentContext_()));
|
|
} else {
|
|
#ifdef _WIN32
|
|
return ((info.hCtx_ != nullptr) && (info.hCtx_ == wglGetCurrentContext_()));
|
|
#else
|
|
return ((info.hCtx_ != nullptr) && (info.hCtx_ == glXGetCurrentContext_()));
|
|
#endif // _WIN32
|
|
}
|
|
}
|
|
|
|
void WaitCurrentGlContext(const amd::Context::Info& info) const;
|
|
|
|
// Query CL-GL context association
|
|
bool isAssociated() const
|
|
{
|
|
if (isEGL_ && eglDisplay_ && eglOriginalContext_) return true;
|
|
#ifdef _WIN32
|
|
if(hDC_ && hOrigGLRC_) return true;
|
|
#else //!_WIN32
|
|
if(Dpy_ && origCtx_) return true;
|
|
#endif //!_WIN32
|
|
return false;
|
|
}
|
|
bool isEGL() const
|
|
{
|
|
return isEGL_;
|
|
}
|
|
// Accessor methods
|
|
#ifdef _WIN32
|
|
HGLRC getOrigGLRC() const {return hOrigGLRC_;}
|
|
HDC getDC() const {return hDC_;}
|
|
HGLRC getIntGLRC() const {return hIntGLRC_;}
|
|
#else //!_WIN32
|
|
Display* getDpy() const {return Dpy_;}
|
|
GLXDrawable getDrawable() const {return Drawable_;}
|
|
GLXContext getOrigCtx() const {return origCtx_;}
|
|
|
|
Display* getIntDpy() const {return intDpy_;}
|
|
GLXDrawable getIntDrawable() const {return intDrawable_;}
|
|
GLXContext getIntCtx() const {return intCtx_;}
|
|
|
|
EGLDisplay getEglDpy() const { return eglDisplay_; }
|
|
EGLContext getEglOrigCtx() const { return eglOriginalContext_; }
|
|
#endif //!_WIN32
|
|
|
|
// Initialize GL dynamic library and function pointers
|
|
bool init(intptr_t hdc, intptr_t hglrc);
|
|
|
|
// Return true if successful, false - if error occurred
|
|
bool setIntEnv();
|
|
bool restoreEnv();
|
|
|
|
amd::Monitor& getLock() { return lock_; }
|
|
|
|
PFN_xxxGetProcAddress GetProcAddress_;
|
|
|
|
#define GLPREFIX(rtype, fcn, dclargs) \
|
|
PFN_##fcn fcn##_;
|
|
// Declare pointers to GL functions
|
|
#include "gl_functions.hpp"
|
|
};
|
|
|
|
//! Functions for executing the GL related stuff
|
|
cl_mem clCreateFromGLBufferAMD(Context& amdContext, cl_mem_flags flags,
|
|
GLuint bufobj, cl_int* errcode_ret);
|
|
cl_mem clCreateFromGLTextureAMD(Context& amdContext, cl_mem_flags flags,
|
|
GLenum target, GLint miplevel, GLuint texture, int* errcode_ret);
|
|
cl_mem clCreateFromGLRenderbufferAMD(Context& amdContext, cl_mem_flags flags,
|
|
GLuint renderbuffer, int* errcode_ret);
|
|
|
|
bool
|
|
getCLFormatFromGL(
|
|
const Context& amdContext,
|
|
GLint gliInternalFormat,
|
|
cl_image_format* pclImageFormat,
|
|
int* piBytesPerPixel,
|
|
cl_mem_flags flags
|
|
);
|
|
|
|
} //namespace amd
|
|
|