gpt4 book ai didi

c++ - 第二个线程中的 wglMakeCurrent 失败了吗?

转载 作者:行者123 更新时间:2023-11-30 02:49:01 24 4
gpt4 key购买 nike

所以我正在我的 Win32 应用程序中设置我的 OpenGL 上下文。我正在设置一个多线程环境,在一个线程中处理窗口消息,在另一个线程中调用 OpenGL 渲染。到目前为止,我的工作流程如下:

线程 A:

  • 创建窗口
  • 获取显示上下文
  • 选择像素格式
  • 创建一个临时的 OpenGL 上下文并使其成为当前上下文
  • 获取扩展函数指针
  • 将当前上下文设置为 NULL 并删除临时上下文
  • 使用 wglCreateContextAttribsARB 创建一个新的上下文
  • 启动线程 B

然后,在线程 B 中:

  • wglMakeCurrent 使用来自线程 A 的 hdc 和 hglrc

问题是,线程 B 中的 wglMakeCurrent 返回 false,getLastError 返回 170(资源正在使用中)。我读过的所有内容都暗示这意味着渲染上下文已经在线程 A 中使用,但我什至在创建线程 B 之前就在线程 A 中明确调用了“wglMakeCurrent(NULL, NULL)”。

可能出了什么问题?

附言。为了清楚起见,我并没有尝试从不同的并发线程运行 OpenGL 调用。除了在线程 B 存在之前创建渲染上下文之外,每个单独的 OpenGL 调用都将从线程 B 进行。

编辑:这是一些源代码。这是在线程 A 中初始化窗口的函数:

Window* Window::init(void)
{
/* If the singleton exists already, just return a pointer to it */
if (singleton)
return singleton;

/* Allocate the singleton and check for errors */
singleton = new Window();
if (singleton == NULL)
{
fatalerror("In Window::init():\n");
fatalmore("Memory allocation failure.\n");
fatalmore("Could not allocate singleton.\n");
_getch();
exit(1);
}

/* Register window class */
WNDCLASSEX wc;
memset(&wc, 0, sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = wndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = APP_NAME;

if (!RegisterClassEx(&wc))
{
fatalerror("In Window::init():\n");
fatalmore("Failed to register window class.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

/* Read settings */
int width = Settings::get()->screenWidth;
int height = Settings::get()->screenHeight;
DWORD exStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
DWORD style = WS_OVERLAPPEDWINDOW;

/* Are we using fullscreen mode? */
if (Settings::get()->fullscreen)
{
width = Settings::get()->fullscreenWidth;
height = Settings::get()->fullscreenHeight;

DEVMODE dm;
memset(&dm, 0, sizeof(DEVMODE));

dm.dmSize = sizeof(DEVMODE);
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
dm.dmBitsPerPel = 32;
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
warning("in Window::init():\n");
warnmore("The requested fullscreen mode is not supported.\n");
warnmore("Will continue in windowed mode.\n");

width = Settings::get()->screenWidth;
height = Settings::get()->screenHeight;
Settings::get()->fullscreen = false;
}
else
{
exStyle = WS_EX_APPWINDOW;
style = WS_POPUP;
}
}

/* Create the window */
singleton->wnd = CreateWindowEx( exStyle,
APP_NAME, APP_NAME,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | style,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL,
NULL,
GetModuleHandle(NULL),
NULL );

if (!singleton->wnd)
{
fatalerror("In Window::init():\n");
fatalmore("Could not create window.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

/* Get the DC */
singleton->dc = GetDC(singleton->wnd);
if (!singleton->dc)
{
fatalerror("In Window::init():\n");
fatalmore("Failed to get display context.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

/* Choose a pixel format */
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));

pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;

int pf = ChoosePixelFormat(singleton->dc, &pfd);
if (!pf)
{
fatalerror("In Window::init():\n");
fatalmore("Failed to choose a pixel format.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

/* Set the pixel format */
if (!SetPixelFormat(singleton->dc, pf, &pfd))
{
fatalerror("In Window::init():\n");
fatalmore("Failed to set pixel format '%i'.\n", pf);
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

/* Create our fake, temporary OpenGL context */
HGLRC temprc = wglCreateContext(singleton->dc);
if (!temprc)
{
fatalerror("In Window::init():\n");
fatalmore("Failed to create a temporary context.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}
wglMakeCurrent(singleton->dc, temprc);

/* Initialize the OpenGL extensions we need */
if (!initGLCreationExtensions())
{
fatalerror("In Window::init():\n");
fatalmore("Failed to initialize OpenGL context creation extensions.\n");
clean();
_getch();
exit(1);
}

/* Check for OpenGL version */
int majorver = 0, minorver = 0;
glGetIntegerv(GL_MAJOR_VERSION, &majorver);
glGetIntegerv(GL_MINOR_VERSION, &minorver);

if (majorver < 3 || (majorver == 3 && minorver < 1))
{
fatalerror("In Window::init():\n");
fatalmore("OpenGL version 3.1 or higher is required.\n");
clean();
_getch();
exit(1);
}


/* Define context attributes */
int contextAttribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, majorver,
WGL_CONTEXT_MINOR_VERSION_ARB, minorver,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};

/* Create the real OpenGL context */
singleton->rc = wglCreateContextAttribsARB(singleton->dc, NULL, contextAttribs);
if (!singleton->rc)
{
fatalerror("In Window::init():\n");
fatalmore("Failed to create OpenGL context.\n");
fatalmore("Error code: '%i'\n", GetLastError());
clean();
_getch();
exit(1);
}

ShowWindow(singleton->wnd, SW_SHOW);

/* Delete the fake context */
wglMakeCurrent(NULL, NULL);
wglDeleteContext(temprc);

info("Successfully created window.\n");
printf("\n");

return singleton;
}

这是在线程 B 中运行的启动函数:

bool Window::renderThreadStartupFunc(void)
{
if (!singleton)
return false;

if (!singleton->dc)
return false;


if (!wglMakeCurrent(singleton->dc, singleton->rc))
{
error("In Window::renderThreadStartupFunc():\n");
errormore("Could not make context current.\n");
errormore("Error code: '%i'\n", GetLastError());
return false;
}

if (!initGLExtensions())
{
error("In Window::renderThreadStartupFunc():\n");
errormore("Failed to initialize OpenGL extensions.\n");
return false;
}

return true;
}

下面是负责启动和关闭线程 B 的代码。它在单独的类中运行,并使用 c++11 的 std::thread 库。

Renderer* Renderer::init(void)
{
/* If the singleton exists already, just return a pointer to it */
if (singleton)
return singleton;

/* Allocate the singleton and check for errors */
singleton = new Renderer();
if (singleton == NULL)
{
fatalerror("In Renderer::init():\n");
fatalmore("Memory allocation failure.\n");
fatalmore("Could not allocate singleton.\n");
_getch();
exit(1);
}

Window::get();

singleton->running = true;

renderThread = new thread(main);
if (renderThread == NULL)
{
fatalerror("In Renderer::init():\n");
fatalmore("Memory allocation failure.\n");
fatalmore("Could not allocate rendering thread.\n");
_getch();
exit(1);
}

Message startup;
startup.type = MT_STARTUP;
singleton->queue.push(startup);

return singleton;
}

void Renderer::clean(void)
{
if (!singleton)
return;

Message shutdown;
shutdown.type = MT_SHUTDOWN;
singleton->queue.push(shutdown);

if (renderThread)
{
renderThread->join();
delete renderThread;
}
}

最佳答案

一些建议:

  • 创建适当的上下文,将临时帮助器上下文作为当前上下文(您的扩展函数指针绑定(bind)到 Windows 中的事件上下文),即不要释放作为当前上下文的帮助器上下文,也不要释放助手上下文,在创建适当的上下文之前。

  • 在启动线程 B 之前,在适当的上下文和 hdc 上调用 wglMakeCurrent(…),调用 glFinish(),然后才调用 wglMakeCurrent(NULL, NULL) 并删除临时上下文。对于一些有问题的驱动程序,这是一个肮脏的解决方法。

关于c++ - 第二个线程中的 wglMakeCurrent 失败了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21613842/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com