Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qt: Fix gl-gs-frame error in debug builds #16614

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions rpcs3/rpcs3qt/gl_gs_frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,41 @@ void gl_gs_frame::reset()

draw_context_t gl_gs_frame::make_context()
{
auto context = new GLContext();
context->handle = new QOpenGLContext();
GLContext* context = nullptr;

if (m_primary_context)
// Workaround for the Qt warning: "Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."
// This is also necessery in debug builds.
Emu.BlockingCallFromMainThread([&]()
{
QOffscreenSurface* surface = nullptr;
context = new GLContext();
context->handle = new QOpenGLContext();

// Workaround for the Qt warning: "Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."
Emu.BlockingCallFromMainThread([&]()
if (m_primary_context)
{
surface = new QOffscreenSurface();
QOffscreenSurface* surface = new QOffscreenSurface();
surface->setFormat(m_format);
surface->create();
});

// Share resources with the first created context
context->handle->setShareContext(m_primary_context->handle);
context->surface = surface;
context->owner = true;
}
else
{
// This is the first created context, all others will share resources with this one
m_primary_context = context;
context->surface = this;
context->owner = false;
}
// Share resources with the first created context
context->handle->setShareContext(m_primary_context->handle);
context->surface = surface;
context->owner = true;
}
else
{
// This is the first created context, all others will share resources with this one
m_primary_context = context;
context->surface = this;
context->owner = false;
}

context->handle->setFormat(m_format);
context->handle->setFormat(m_format);

if (!context->handle->create())
{
fmt::throw_exception("Failed to create OpenGL context");
}
if (!context->handle->create())
{
fmt::throw_exception("Failed to create OpenGL context");
}
});

return context;
}
Expand All @@ -80,10 +81,16 @@ void gl_gs_frame::set_current(draw_context_t ctx)
fmt::throw_exception("Null context handle passed to set_current");
}

const auto context = static_cast<GLContext*>(ctx);

if (!context->handle->makeCurrent(context->surface))
// Calling this on the main thread is necessery in debug builds.
Emu.BlockingCallFromMainThread([&]()
{
const auto context = static_cast<GLContext*>(ctx);

if (context->handle->makeCurrent(context->surface))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. This is wrong.
GLRC makeCurrent means "make this context the current one on this thread".
We don't want it attached to main thread, we want it attached to the caller. It's how you do multithreading in OGL.

{
return;
}

if (!context->owner)
{
create();
Expand All @@ -100,14 +107,18 @@ void gl_gs_frame::set_current(draw_context_t ctx)
{
fmt::throw_exception("Could not bind OpenGL context");
}
}
});
}

void gl_gs_frame::delete_context(draw_context_t ctx)
{
const auto gl_ctx = static_cast<GLContext*>(ctx);

gl_ctx->handle->doneCurrent();
// Calling this on the main thread is necessery in debug builds.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, cannot be done from main thread. Anything with "current" is thread-local

Emu.BlockingCallFromMainThread([&]()
{
gl_ctx->handle->doneCurrent();
});

#ifdef _MSC_VER
//AMD driver crashes when executing wglDeleteContext
Expand Down