SWDEV-460019 - [OGLP][Nv2x] DaVinci Resolve Studio: Crash observed when editing in color tab
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
[ROCm/clr commit: 0c6a952a90]
This commit is contained in:
committed by
Victor Zhang
parent
10b3a313d2
commit
28009e625b
@@ -765,7 +765,13 @@ RUNTIME_ENTRY_RET(cl_event, clCreateEventFromGLsyncKHR,
|
||||
LogWarning("Memory allocation of clglEvent object failed");
|
||||
return nullptr;
|
||||
}
|
||||
clglEvent->context().glenv()->glFlush_();
|
||||
|
||||
// Add this scope to bound the scoped lock
|
||||
{
|
||||
amd::GLFunctions::Lock lock(clglEvent->context().glenv());
|
||||
clglEvent->context().glenv()->glFlush_();
|
||||
} // Release scoped lock
|
||||
|
||||
// initially set the status of fence as queued
|
||||
clglEvent->setStatus(CL_SUBMITTED);
|
||||
// store GLsync id of the fence in event in order to associate them together
|
||||
@@ -1108,23 +1114,22 @@ cl_mem clCreateFromGLBufferAMD(Context& amdContext, cl_mem_flags flags, GLuint b
|
||||
|
||||
// Mapping will be done at acquire time (sync point)
|
||||
|
||||
// Now create BufferGL object
|
||||
pBufferGL = new (amdContext) BufferGL(amdContext, flags, gliSize, 0, bufobj);
|
||||
|
||||
if (!pBufferGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("cannot create object of class BufferGL");
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
if (!pBufferGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pBufferGL->release();
|
||||
return (cl_mem)0;
|
||||
}
|
||||
} // Release scoped lock
|
||||
|
||||
// Now create BufferGL object
|
||||
pBufferGL = new (amdContext) BufferGL(amdContext, flags, gliSize, 0, bufobj);
|
||||
|
||||
if (!pBufferGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("cannot create object of class BufferGL");
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
if (!pBufferGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pBufferGL->release();
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
*not_null(errcode_ret) = CL_SUCCESS;
|
||||
|
||||
// Create interop object
|
||||
@@ -1430,34 +1435,34 @@ cl_mem clCreateFromGLTextureAMD(Context& amdContext, cl_mem_flags clFlags, GLenu
|
||||
|
||||
// PBO and mapping will be done at "acquire" time (sync point)
|
||||
|
||||
target = (glTarget == GL_TEXTURE_CUBE_MAP) ? target : 0;
|
||||
|
||||
if (wholeMipmap) {
|
||||
pImageGL = new (amdContext)
|
||||
ImageGL(amdContext, clType, clFlags, clImageFormat, static_cast<size_t>(gliTexWidth),
|
||||
static_cast<size_t>(gliTexHeight), static_cast<size_t>(gliTexDepth), glTarget,
|
||||
texture, miplevel, glInternalFormat, clGLType, numSamples, gliTexMaxLevel, target);
|
||||
} else {
|
||||
pImageGL = new (amdContext)
|
||||
ImageGL(amdContext, clType, clFlags, clImageFormat, static_cast<size_t>(gliTexWidth),
|
||||
static_cast<size_t>(gliTexHeight), static_cast<size_t>(gliTexDepth), glTarget,
|
||||
texture, miplevel, glInternalFormat, clGLType, numSamples, target);
|
||||
}
|
||||
|
||||
if (!pImageGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("Cannot create class ImageGL - out of memory?");
|
||||
return static_cast<cl_mem>(0);
|
||||
}
|
||||
|
||||
if (!pImageGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pImageGL->release();
|
||||
return static_cast<cl_mem>(0);
|
||||
}
|
||||
|
||||
} // Release scoped lock
|
||||
|
||||
target = (glTarget == GL_TEXTURE_CUBE_MAP) ? target : 0;
|
||||
|
||||
if (wholeMipmap) {
|
||||
pImageGL = new (amdContext)
|
||||
ImageGL(amdContext, clType, clFlags, clImageFormat, static_cast<size_t>(gliTexWidth),
|
||||
static_cast<size_t>(gliTexHeight), static_cast<size_t>(gliTexDepth), glTarget,
|
||||
texture, miplevel, glInternalFormat, clGLType, numSamples, gliTexMaxLevel, target);
|
||||
} else {
|
||||
pImageGL = new (amdContext)
|
||||
ImageGL(amdContext, clType, clFlags, clImageFormat, static_cast<size_t>(gliTexWidth),
|
||||
static_cast<size_t>(gliTexHeight), static_cast<size_t>(gliTexDepth), glTarget,
|
||||
texture, miplevel, glInternalFormat, clGLType, numSamples, target);
|
||||
}
|
||||
|
||||
if (!pImageGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("Cannot create class ImageGL - out of memory?");
|
||||
return static_cast<cl_mem>(0);
|
||||
}
|
||||
|
||||
if (!pImageGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pImageGL->release();
|
||||
return static_cast<cl_mem>(0);
|
||||
}
|
||||
|
||||
*not_null(errcode_ret) = CL_SUCCESS;
|
||||
return as_cl<Memory>(pImageGL);
|
||||
}
|
||||
@@ -1553,25 +1558,24 @@ cl_mem clCreateFromGLRenderbufferAMD(Context& amdContext, cl_mem_flags clFlags,
|
||||
|
||||
// PBO and mapping will be done at "acquire" time (sync point)
|
||||
|
||||
pImageGL =
|
||||
new (amdContext) ImageGL(amdContext, CL_MEM_OBJECT_IMAGE2D, clFlags, clImageFormat,
|
||||
(size_t)gliRbWidth, (size_t)gliRbHeight, 1, glTarget, renderbuffer,
|
||||
0, glInternalFormat, CL_GL_OBJECT_RENDERBUFFER, 0);
|
||||
|
||||
if (!pImageGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("Cannot create class ImageGL from renderbuffer - out of memory?");
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
if (!pImageGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pImageGL->release();
|
||||
return (cl_mem)0;
|
||||
}
|
||||
} // Release scoped lock
|
||||
|
||||
pImageGL =
|
||||
new (amdContext) ImageGL(amdContext, CL_MEM_OBJECT_IMAGE2D, clFlags, clImageFormat,
|
||||
(size_t)gliRbWidth, (size_t)gliRbHeight, 1, glTarget, renderbuffer,
|
||||
0, glInternalFormat, CL_GL_OBJECT_RENDERBUFFER, 0);
|
||||
|
||||
if (!pImageGL) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
LogWarning("Cannot create class ImageGL from renderbuffer - out of memory?");
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
if (!pImageGL->create()) {
|
||||
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
|
||||
pImageGL->release();
|
||||
return (cl_mem)0;
|
||||
}
|
||||
|
||||
*not_null(errcode_ret) = CL_SUCCESS;
|
||||
return as_cl<Memory>(pImageGL);
|
||||
}
|
||||
@@ -1627,6 +1631,7 @@ cl_int clEnqueueAcquireExtObjectsAMD(cl_command_queue command_queue, cl_uint num
|
||||
// that any such pending OpenGL operations are complete for an OpenGL context bound
|
||||
// to the same thread as the OpenCL context.
|
||||
if (hostQueue.device().settings().checkExtension(ClKhrGlEvent)) {
|
||||
GLFunctions::Lock lock(gl_functions);
|
||||
gl_functions->WaitCurrentGlContext(hostQueue.context().info());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ bool amd::ClGlEvent::waitForFence() {
|
||||
HGLRC tempGLRC_ = context().glenv()->wglGetCurrentContext_();
|
||||
// Set DC and GLRC
|
||||
if (tempDC_ && tempGLRC_) {
|
||||
amd::GLFunctions::Lock lock(context().glenv());
|
||||
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
static_cast<GLuint64>(-1));
|
||||
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
|
||||
@@ -74,14 +75,12 @@ bool amd::ClGlEvent::waitForFence() {
|
||||
return false;
|
||||
|
||||
// Make the newly created GL context current to this thread
|
||||
context().glenv()->setIntEnv();
|
||||
amd::GLFunctions::SetIntEnv ie(context().glenv());
|
||||
|
||||
// If fence has not yet executed, wait till it finishes
|
||||
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
static_cast<GLuint64>(-1));
|
||||
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
|
||||
// Since we're done making GL calls, restore whatever context was previously current to this
|
||||
// thread
|
||||
context().glenv()->restoreEnv();
|
||||
}
|
||||
#else // Lnx
|
||||
Display* tempDpy_ = context().glenv()->glXGetCurrentDisplay_();
|
||||
@@ -89,6 +88,7 @@ bool amd::ClGlEvent::waitForFence() {
|
||||
GLXContext tempCtx_ = context().glenv()->glXGetCurrentContext_();
|
||||
// Set internal Display and GLXContext
|
||||
if (tempDpy_ && tempCtx_) {
|
||||
amd::GLFunctions::Lock lock(context().glenv());
|
||||
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
static_cast<GLuint64>(-1));
|
||||
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
|
||||
@@ -98,14 +98,12 @@ bool amd::ClGlEvent::waitForFence() {
|
||||
return false;
|
||||
|
||||
// Make the newly created GL context current to this thread
|
||||
context().glenv()->setIntEnv();
|
||||
amd::GLFunctions::SetIntEnv ie(context().glenv());
|
||||
|
||||
// If fence has not yet executed, wait till it finishes
|
||||
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
static_cast<GLuint64>(-1));
|
||||
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
|
||||
// Since we're done making GL calls, restore whatever context was previously current to this
|
||||
// thread
|
||||
context().glenv()->restoreEnv();
|
||||
}
|
||||
#endif
|
||||
// If we reach this point, fence should have completed
|
||||
@@ -151,6 +149,14 @@ amd::GLFunctions::SetIntEnv::~SetIntEnv() {
|
||||
env_->getLock().unlock();
|
||||
}
|
||||
|
||||
amd::GLFunctions::Lock::Lock(GLFunctions* env) : env_(env) {
|
||||
env_->getLock().lock();
|
||||
}
|
||||
|
||||
amd::GLFunctions::Lock::~Lock() {
|
||||
env_->getLock().unlock();
|
||||
}
|
||||
|
||||
amd::GLFunctions::GLFunctions(HMODULE h, bool isEGL)
|
||||
: libHandle_(h),
|
||||
missed_(0),
|
||||
|
||||
@@ -280,6 +280,19 @@ public:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user