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:
Gu, Wangfeng
2024-05-09 14:43:18 +08:00
committed by Victor Zhang
parent 10b3a313d2
commit 28009e625b
3 changed files with 91 additions and 67 deletions
+64 -59
View File
@@ -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());
}
}
+14 -8
View File
@@ -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