使用 GLFW3 在 OpenGL 上下文之间共享纹理不起作用

Posted

技术标签:

【中文标题】使用 GLFW3 在 OpenGL 上下文之间共享纹理不起作用【英文标题】:Sharing textures between OpenGL contexts with GLFW3 is not working 【发布时间】:2014-04-25 18:54:05 【问题描述】:

下面的程序应该是:

    创建一个不可见的GLFWwindow* masterWindow 从文件加载纹理,而活动的 OpenGL 上下文是与 masterWindow 关联的上下文 创建一个GLFWwindow* childWindow,并在此窗口的 OpenGL 上下文和masterWindow 的上下文之间激活共享 在childWindow 中显示带有纹理的全窗口四边形

但是,这不起作用,即我在childWindow 中显示随机图形内存的sn-ps,而不是纹理。如果我在加载之前将childWindow 的上下文设为当前,则显示纹理确实有效,这就是为什么我认为问题既不在于我的着色器,也不在于我的纹理加载例程(我从这里获取,https://github.com/DavidEGrayson/ahrs-visualizer/blob/master/png_texture.cpp)。 我知道我应该能够分享纹理(请参阅这个 SO 问题的答案:OpenGL - Share existing textures with future contexts?),那么我做错了什么?以防万一,我使用的是 2008 年末的 Macbook,装有 NVIDIA 9400m 并安装了 Mavericks/OpenGL 3.3。

#include <iostream>
#define GLEW_STATIC
#include <glew.h>
#include <glfw3.h>

const char* vShader =
  "#version 150 core\n"
  "in vec2 vertex;"
  "in vec2 vertexUV;"
  "out vec2 UV;"
  "void main() gl_Position = vec4(vertex,0,1);UV=vertexUV;";
const char* fShader =
 "#version 150 core\n"
 "uniform sampler2D sampler;"
 "in vec2 UV;"
 "out vec4 color;"
 "void main() color = texture(sampler, UV);";

GLuint png_texture_load(const char * file_name, unsigned int * width=NULL, unsigned int * height=NULL);
GLuint make_program(const char* vShader, const char* fShader);

GLFWwindow* masterWindow(NULL);

void create_window_with_texture(GLuint texture)

  GLFWwindow* childWindow(glfwCreateWindow(256,256, "", NULL, masterWindow));
  glfwMakeContextCurrent(childWindow);

  // texture appears if loaded from here
  // texture=png_texture_load("rose.png");                                                                                                               

  GLfloat vertices[]=-1,-1,1,-1,-1,1,1,1, // window corners in clip space                                                                               
                  0,0,1,0,0,1,1,1;    // corners in uv-space                                                                                        
  GLubyte indices[]=0,2,1,3;             // points for a two triangle strip                                                                            

  GLuint vArray,vBuffer,iBuffer;
  glGenVertexArrays(1,&vArray);glBindVertexArray(vArray);
  glGenBuffers(1,&vBuffer);glBindBuffer(GL_ARRAY_BUFFER,vBuffer);
  glGenBuffers(1,&iBuffer);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,iBuffer);
  glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_DYNAMIC_DRAW);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_DYNAMIC_DRAW);

  GLuint program(make_program(vShader,fShader));
  glUseProgram(program);
  glUniform1i(glGetUniformLocation(program,"sampler"),0);
  GLuint vertexPtr(GLuint(glGetAttribLocation(program,"vertex")));
  glEnableVertexAttribArray(vertexPtr);
  GLuint vertexUVPtr(GLuint(glGetAttribLocation(program, "vertexUV")));
  glEnableVertexAttribArray(vertexUVPtr);
  glVertexAttribPointer(vertexPtr, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0 );
  glVertexAttribPointer(vertexUVPtr, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)32);

  glActiveTexture(GL_TEXTURE0);
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_BLEND);

  glBindTexture(GL_TEXTURE_2D,texture);
  glDrawElements(GL_TRIANGLE_STRIP,4, GL_UNSIGNED_BYTE, (GLvoid*)0);

  glfwSwapBuffers(childWindow);


int main()

  if (!glfwInit())
    return -1;
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,2);
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
  glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
  masterWindow=glfwCreateWindow(10,10, "", NULL,NULL);
  glfwWindowHint(GLFW_VISIBLE,GL_TRUE);
  glfwWindowHint(GLFW_SAMPLES, 4);
  glfwMakeContextCurrent(masterWindow);
  glewExperimental = GL_TRUE;
  GLenum err = glewInit();
  if(GLEW_OK!=err)
    return -1;
  glGetError(); // catch benign glewInit() invalid enum error                                                                                            

  GLuint texture(0);
  texture=png_texture_load("rose.png");

  create_window_with_texture(texture);

  std::cin.get();

  return 0;

【问题讨论】:

加载纹理后直接加glFinish()是否有效? 天哪,确实如此!非常感谢!想让它成为一个答案以便我接受吗? 【参考方案1】:

您必须知道 OpenGL 将异步工作。客户端命令排队等待稍后由 GL 服务器/GPU 处理。通常,如果您访问不可用的数据,GL 会通过隐式同步来向用户隐藏这一事实。但是,在使用多个上下文时,您必须手动显式同步操作。调用glFinish() 将刷新命令队列并等待命令实际被处理。 您的情况有点特殊,这种情况通常出现在多线程程序中,其中一个线程创建/更新 GL 对象并将手柄转移到另一个线程以使用该对象。

我不确定使另一个上下文成为当前上下文是否会或应该导致旧上下文的隐式同步,所以我的猜测是它可能不会(但我没有阅读相关的 API 文档),并添加了 @987654322 @ 这里可能也需要(或使用其他同步方式)。

【讨论】:

以上是关于使用 GLFW3 在 OpenGL 上下文之间共享纹理不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 OS X 上的 OpenGL 上下文之间共享数据(不同的版本/配置文件)

是否可以在 Qt 的***窗口之间使用相同的 OpenGL 上下文?

如何在 imgui 窗口中使用 opengl glfw3 渲染?

如果 OpenGL 3+ 请求,glfw3 不绘图?

错误:在 Linux 上使用 OpenGL 编译 C++ 程序时出现“GL/glfw3.h:没有这样的文件或目录”

使用 glfw3 glew 和 opengl 在 Visual Studio 社区中获取访问冲突异常