OpenGL在另一个线程中绘图

2024-03-14

我为 Windows 创建了一个简单的 OpenGL 应用程序。它创建一个窗口,然后使用 OpenGL 命令在其上绘制一个三角形。这按预期工作。

后来我想将我的绘图代码封装到一个DLL中,以便可以在C# WinForms应用程序中使用它来绘制WinForm。 为此,我将绘图代码移至单独的类和线程中。我的想法是,我可以将我的类“附加”到任何现有窗口,并让我的线程绘制到它。

可悲的是事情似乎并没有那么简单。一旦我将窗口创建和绘制内容分离到不同的线程中,屏幕就会保持全黑。绘图调用似乎不再起作用了。

有没有办法让我的绘图完全独立于窗口创建和主 UI 线程?

编辑:这是一些代码:-)

这是我的renderer(从 UI 线程调用时有效,从后台线程调用时无效):

// Constructor
Renderer::Renderer(HWND hwnd, size_t windowWidth, size_t windowHeight)
  :
  mContext(hwnd)
{
  mWindowWidth = windowWidth;
  mWindowHeight = windowHeight;
  mHdc = GetDC(hwnd);

  // From now on everything is similar to initializing a context on any other hdc
  PIXELFORMATDESCRIPTOR pfd;
  ZeroMemory(&pfd, sizeof(pfd));
  pfd.nSize = sizeof(pfd);
  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;
  int iFormat = ChoosePixelFormat(mHdc, &pfd);
  SetPixelFormat(mHdc, iFormat, &pfd);

  mHrc = wglCreateContext(mHdc);
  wglMakeCurrent(mHdc, mHrc);


  // Set up OpenGL
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_LIGHTING);
  glDisable(GL_TEXTURE_2D);
  glLoadIdentity();
  glViewport(0, 0, windowWidth, windowHeight);
  glOrtho(0, windowWidth, windowHeight, 0, -1, 1);
}


// Draws the scene
void Renderer::Draw()
{
  wglMakeCurrent(mHdc, mHrc);

  glClear(GL_COLOR_BUFFER_BIT);
  glColor4f(1, 0, 1, 1);

  glBegin(GL_QUADS);
  glColor3f(1.0, 1.0, 1.0);
  glVertex3f(0.0f, float(mWindowHeight/2), 0.0f);
  glVertex3f(float(mWindowWidth/2), float(mWindowHeight/2), 0.0f);
  glVertex3f(float(mWindowWidth/2), 0.0f, 0.0f);
  glVertex3f(0.0f, 0.0f, 0.0f);
  glEnd();

  glFlush();
  SwapBuffers(mHdc);
}

这就是我从后台线程:

// Constructor
BackgroundRenderer::BackgroundRenderer(HWND hwnd, uint32_t windowWidth, uint32_t windowHeight)
  :
  mCancelThread(false)
{
  // Initialize OpenGL
  mRenderer = std::make_shared<Renderer>(hwnd, windowWidth, windowHeight);

  // Start rendering thread
  mRenderingThread = std::thread(&BackgroundRenderer::BackgroundLoop, this);
}


// Destructor
BackgroundRenderer::~BackgroundRenderer()
{
  // Stop rendering thread
  mCancelThread = true;
  mRenderingThread.join();
}


// The background rendering loop
void BackgroundRenderer::BackgroundLoop()
{
  while (!mCancelThread)
  {
    // Draw stuff
    mRenderer->Draw();
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
  }
}

这是我的main将它们粘合在一起:

// Message loop
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
  case WM_CLOSE:
    PostQuitMessage(0);
    return 0;
  }

  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


// Window creation
HWND CreateApplicationWindow(char* title, int x, int y, int width, int height, int nCmdShow)
{
  HWND        hWnd;
  WNDCLASS    wc;
  static HINSTANCE hInstance = 0;

  if (!hInstance)
  {
    hInstance = GetModuleHandle(NULL);
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = (WNDPROC)WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "OpenGL";

    RegisterClass(&wc);
  }

  hWnd = CreateWindowA("OpenGL", title, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, x, y, width, height, NULL, NULL, hInstance, NULL);
  ShowWindow(hWnd, nCmdShow);

  return hWnd;
}


// Main entry point of application
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow)
{
  HWND hWnd = CreateApplicationWindow("Test", 0, 0, 640, 480, nCmdShow);

  // This renders from another thread (not working)
  auto  backgroundRenderer = std::make_shared<BackgroundRenderer>(hWnd, 640, 480);

  // This would render in the UI thread (works)
  //auto renderer = std::make_shared<Renderer>(hWnd, 640, 480);

  MSG msg;
  while (GetMessage(&msg, hWnd, 0, 0))
  {
    // This would render in the UI thread (works)
    //renderer->Draw();

    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  DestroyWindow(hWnd);
  return msg.wParam;
}

两个基本规则是:

  • 任何给定的 OpenGL 渲染上下文一次只能在一个线程上处于活动状态。
  • 并且任何线程一次只能使一个 OpenGL 上下文当前处于活动状态。

然而,特定的 OpenGL 上下文和特定的窗口之间没有严格的关联(用于在多个窗口中使用单个 OpenGL 上下文的 Win32 测试程序 https://github.com/datenwolf/wglarb/blob/master/test/shared.c),或特定线程。您始终可以将 OpenGL 上下文从一个线程迁移到另一个线程。

两种常用的方法是:

  • 在线程 A 中创建一个窗口,将窗口句柄传递给线程 B,然后创建 OpenGL 上下文。

or

  • 在线程 A 中创建窗口和 OpenGL 上下文,使上下文在 A 中处于非活动状态,将句柄传递给线程 B 并使它们在线程 B 中处于活动状态。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL在另一个线程中绘图 的相关文章

  • 将图像文件从网址复制到本地文件夹?

    我有该图像的网址 例如 http testsite com web abc jpg http testsite com web abc jpg 我想将该 URL 复制到 c images 中的本地文件夹中 而且当我将该文件复制到文件夹中时
  • 如何使用 MVVM 更新 WPF 中编辑的数据? [复制]

    这个问题在这里已经有答案了 我正在为聊天应用程序构建 UI 设计 在尝试更新所选联系人的消息时遇到问题 选择现有联系人 选择编辑选项 然后编辑其属性 例如用户名和图像 后 唯一进行的更改是联系人的用户名和图像 我仍然想更改 MessageM
  • 在Application_AquireRequestState事件中用POST数据重写Url

    我有一个在其中注册路线的代码Application AcquireRequestState应用程序的事件 注册路由后 我会在 Http 运行时缓存中设置一个标志 这样我就不会再次执行路由注册代码 在此事件中注册路线有特定原因Applicat
  • 访问“if”语句之外的变量

    我怎样才能使insuranceCost以外可用if陈述 if this comboBox5 Text Third Party Fire and Theft double insuranceCost 1 在 if 语句之外定义它 double
  • 无法从 Web api POST 读取正文数据

    我正在尝试从新的 Asp Net Web Api 中的请求中提取一些数据 我有一个像这样的处理程序设置 public class MyTestHandler DelegatingHandler protected override Syst
  • 导出类时编译器错误

    我正在使用 Visual Studio 2013 但遇到了一个奇怪的问题 当我导出一个类时 它会抛出 尝试引用已删除的函数 错误 但是 当该类未导出时 它的行为会正确 让我举个例子 class Foo note the export cla
  • Qt 计算和比较密码哈希

    目前正在 Qt 中为测验程序构建面向 Web 的身份验证服务 据我了解 在数据库中存储用户密码时 必须对其进行隐藏 以防落入坏人之手 流行的方法似乎是添加的过程Salt https en wikipedia org wiki Salt cr
  • 矩阵向量变换

    我正在编写一个代码来制作软件蒙皮器 骨骼 皮肤动画 并且我正处于 优化 阶段 蒙皮器工作得很好 并且在 Core 上 1 09 毫秒内对 4900 个三角形网格与 22 个骨骼进行蒙皮Duo 2 Ghz 笔记本 我需要知道的是 1 有人可以
  • 序列化和反序列化 Visual Studio 解决方案文件 - 或以编程方式编辑?

    我想以编程方式添加和删除项目 解决方案文件夹和其他项目 例如解决方案的资源文件 但我不确定最好的方法是什么 对于那些不知道的人 高度简化 解决方案文件 sln 通常如下所示 Microsoft Visual Studio Solution
  • xamarin intellisense 无法在 Windows 10 上的 Visual Studio 2015 中工作

    我一直在尝试在 Windows 10 平台上将 Xamarin 与 Visual Studio 2015 一起使用 我无法对 XML 使用 Intellisense 这非常令人沮丧 有什么解决办法吗 您需要将 android 布局文件的 x
  • Visual Studio - 在哪里定义自定义路径宏?

    我刚刚打开了其他人的 Visual Studio 项目 在他们的构建属性中 他们有一些用于包含和 lib 目录的自定义路径宏 宏名称是这样的 MY WHATEVER INCLUDE DIR 我可以手动将每个宏替换为真实路径 但最好只使用宏
  • 在简单注入器中注册具有多个构造函数和字符串依赖项的类型

    我正在尝试弄清楚如何使用 Simple Injector 我在项目中使用了它 注册简单服务及其组件没有任何问题 但是 当组件具有两个以上实现接口的构造函数时 我想使用依赖注入器 public DAL IDAL private Logger
  • dropdownlist DataTextField 由属性组成?

    有没有一种方法可以通过 C 使 asp net 中的下拉列表的 datatextfield 属性由对象的多个属性组成 public class MyObject public int Id get set public string Nam
  • 在VisualStudio DTE中,如何获取ActiveDocument的内容?

    我正在 VisualStudio 中编写脚本 并尝试获取当前 ActiveDocument 的内容 这是我当前的解决方案 var visualStudio new API VisualStudio 2010 var vsDTE visual
  • 错误左值需要作为赋值C++的左操作数

    整个程序基本上只允许用户移动光标 如果用户位于给定的坐标范围 2 2 内 则允许用户键入输入 我刚刚提供了一些我认为足以解决问题的代码 我不知道是什么导致了这个问题 你能解释一下为什么会发生吗 void goToXY int int 创建一
  • 正确使用“extern”关键字

    有一些来源 书籍 在线材料 解释了extern如下 extern int i declaration has extern int i 1 definition specified by the absence of extern 并且有支
  • 从 C 线程调用 Python 代码

    我对从 C 或 C 线程调用 Python 代码时如何确保线程安全感到非常困惑 The Python 文档 http docs python org c api init html non python created threads似乎是
  • 从有符号字符转换为无符号字符然后再转换回来?

    我正在使用 JNI 并有一个 jbyte 类型的数组 其中 jbyte 表示为有符号字符 即范围从 128 到 127 jbyte 表示图像像素 对于图像处理 我们通常希望像素分量的范围为0到255 因此 我想将jbyte值转换为0到255
  • C# 粘贴到文本框时检查剪贴板中的字符

    有没有一些方法可以在粘贴到文本框 C 之前仅检查剪贴板中的字符 Ctrl V 和右键单击 gt 粘贴 但不使用 MaskedTextbox 在文本框文本更改中添加规则以仅接受数字 例如 private string value privat
  • Android进程调度

    我试图更好地理解 以便在创建 Android 应用程序 服务时确定潜在的互操作性问题对可靠性的影响 我想弄清楚进程优先级是如何确定的 服务和活动之间优先级的差异以及调度程序是否以不同方式对待它们的优先级 基本上 我试图深入了解某个活动或服务

随机推荐

  • 我怎样才能让这个希伯来语字符串替换起作用?

    我想用希伯来语字符串替换这个占位符 但不幸的是字符串替换不起作用 看起来在希伯来语字符串中根本找不到占位符字符串 Test public void Fancy placeholder should be replaced const str
  • Spring Boot 中的全局方法安全性

    我在尝试在 Spring Boot 应用程序中启用全局方法安全性时遇到一些问题 或多或少我有这样的配置 ComponentScan Configuration EnableAutoConfiguration EnableConfigurat
  • 生成格雷码。

    我尝试在中生成格雷码Python 这段代码工作正常 问题是我正在初始化基本情况 n 1 0 1 在里面main函数并将其传递给gray code函数来计算其余部分 我想生成函数本身内部的所有格雷码 包括基本情况 我怎么做 def gray
  • 为什么 SIGHUP 在 Alpine Docker 容器中的 busybox sh 上不起作用?

    Sending SIGHUP with kill HUP
  • 如何使用 URL Swift 3 下载图像? [复制]

    这个问题在这里已经有答案了 我是一名新手开发人员 我正在尝试从 URL 下载并显示图像 并将其显示在 UIImage 视图中 我已经使用以前提出的问题和网络中的信息尝试了多种方法 但它不断出现多个错误 有一个很好的例子说明了如何做到这一点L
  • Java,向日期添加分钟,奇怪的异常

    Windows 和 Ubuntu Linux 上的 Java 版本 1 5 0 06 每当我向日期 2008 10 05 00 00 00 添加分钟时 似乎错误地添加了一个额外的小时 即 在午夜 2008 10 05 00 00 00 上添
  • 使用系统命令从Windows下的C程序内部更改目录

    我遇到一个问题 我必须从 C 程序内部运行命令提示符命令 这是我所做的 include
  • java.util.UUID 线程安全吗?

    我问这个问题是因为以下观察 在高度多线程环境中的线程转储中获取此堆栈跟踪 http 80 200 daemon prio 10 tid 0x00002aaab4981000 nid 0x7520 waiting for monitor en
  • 从头开始创建 XS 模块的现代方法是什么?

    我需要为 Perl 编写一个 XS 模块 据我了解 h2xs 现在几乎已被弃用 现在启动 XS 模块的首选方法是什么 我查看了 Module Starter 但它只处理纯 Perl 模块 不 h2xs 并未被弃用 如果您创建许多纯 Perl
  • 使用拉动刷新滚动列表视图时出现问题

    我开发了一个具有一个列表视图的应用程序 我使用拉动刷新来刷新列表数据 同时下拉 所以我在我的代码中完美地实现了 但是当我向上滚动列表向下滚动时 但当我向下滚动它时 我遇到一个问题不滚动完成 因为它考虑拉动刷新和刷新数据 但我想在显示列表索引
  • Entity Framework Core:Update() 方法在依赖实体上插入而不是更新

    看起来 EF Core 正在执行 INSERT 而不是 UPDATE 因此 MySQL 会抱怨重复键 但是 我在 DbSet 上使用 Update 方法 并且实体确实设置了主键 这会导致 MySql 中出现 DUPLICATE ENTRY
  • Angular 2 ngStyle 和背景图像[重复]

    这个问题在这里已经有答案了 我对 Angular 2 ngStyle 指令遇到了很大的麻烦 我无法从 Base64 编码文件设置背景图像 现在在 template html 中我有这个 div class projects item wra
  • Angular 2 动画/过渡仅适用于 chrome?

    正如标题所示 我一直在使用 Angular2 构建一个 Web 应用程序 并决定测试跨浏览器 结果发现漂亮的动画只能在 Chrome 中运行 这是我的一个组件的样子 如果这可能会有所不同 Component selector contact
  • 如何在 Plone 中定义默认视图

    我已经有一个用于 Plone 站点 主页 的默认视图的页面模板 如何定义文件夹的默认视图 此默认视图应使用页面模板 尝试这个 导航到所需的文件夹 在网址末尾添加 manage propertiesForm in the resulting
  • Python scikit-learn KMeans 在计算轮廓分数时被杀死 (9)

    我目前正在研究一个图像数据集 250 000 张图像 因此与特征向量一样多 每个图像都由 132 个特征组成 并尝试使用 sklearn 提供的 KMeans 函数 我在 Mac OS X 10 10 Python 2 7 和 sklear
  • 在 MATLAB 中绘图时循环颜色

    当我使用以下方法在同一个图上绘制多条曲线时hold on 每条曲线默认为相同的颜色 蓝色 我希望它们有不同的颜色 我见过的一种解决方案是制作颜色矢量 例如c k g r 并循环它 但我不喜欢这个解决方案 如果我的绘图数量大于颜色向量的长度
  • PHP 设置 MySQL 套接字位置

    我以前遇到过这样的问题 我的 C 应用程序在 tmp mysql sock 中寻找套接字 但我的套接字位置已设置为 var run mysqld sock 我现在更改了 my cnf 中的设置 始终将套接字放入 tmp 现在 当我尝试使用
  • 使用 GDI+ 创建的图像未显示在 VB6 LeadTools 中

    我们有使用 VB6 构建的遗留应用程序 这些应用程序正在使用引导工具 一切都很顺利 我们有另一个 NET 进程来优化图像 并做一些水印 并将其保存为 tiff 格式 这是 NET 代码的一瞥 using var bitmap new Bit
  • 使用 Android TabLayout 时单击选项卡不会切换当前选项卡

    我应该自己设置 onClicks 吗 如果是的话 我应该在哪里设置
  • OpenGL在另一个线程中绘图

    我为 Windows 创建了一个简单的 OpenGL 应用程序 它创建一个窗口 然后使用 OpenGL 命令在其上绘制一个三角形 这按预期工作 后来我想将我的绘图代码封装到一个DLL中 以便可以在C WinForms应用程序中使用它来绘制W