The program below is supposed to:
GLFWwindow* masterWindow
masterWindow
GLFWwindow* childWindow
, with sharing activated between this window's OpenGL context and masterWindow
's contextchildWindow
However, this does not work, i.e. instead of the texture, I get random snippets of graphics memory displayed in childWindow
. Displaying the texture does work if I make the context of childWindow
current before loading it, which is why I think that the problem is neither with my shaders nor with my texture loading routine (which I took from here, https://github.com/DavidEGrayson/ahrs-visualizer/blob/master/png_texture.cpp).
I understand that I should be able to share the texture (see answer to this SO question: OpenGL - Share existing textures with future contexts?), so what am I doing wrong? In case it matters, I use a late 2008 Macbook with a NVIDIA 9400m and Mavericks/OpenGL 3.3 installed.
#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;
}
You must be aware that OpenGL will work asynchronously. The client side commands get queued up to be later processed by the GL server/GPU. Typically, the GL will hide this fact from the user, by implicitely syncing if you access data which is not available. However, when working with multiple contexts, you must explicitely synchronize the operations manually. Calling glFinish()
will flush the command queue and wait until the commands have actually been processed.
Your case is a bit special in that typically such situations arise in multi-threaded programs, where one thread creates/updates GL objects and transfers the hande to another thread to use the object.
I'm not sure if making another context current would or should lead to implicit syncing of the old context, so my guess was that it might not (but I have not read the relevant API documentations), and adding the glFinish
might be required here (or using some other means of synchronization), too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With