glCopyImageSubData -> Fail but no glError message...

Hello !

I’m trying to use the function glCopyImageSubData for copying a 2D texture data from a context to another.
But the code crashes into a Segmentation Fault…
I was wondering if it’s related to my driver : my GPU is a NVIDIA Corporation GK104 [GeForce GTX 670] with the 340.96 driver installed (OPENGL version 4.4.0) . I’m on Ubuntu 14.04.

Here’s my code :

#include <cstdlib>
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glext.h>
#include "SOIL/SOIL.h"

using namespace std;

GLuint tex, ctex;

int width, height;

void initTex(void){
   
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
   
    //loading
    unsigned char* image;
    image = SOIL_load_image("/home/alien/sources/of_v0.9.3_linux64_release/apps/myApps/createOpenGLContext/dist/Debug/GNU-Linux/of0", &width, &height, 0, SOIL_LOAD_RGB);
   
    if(image==0){
        cout << "Image didn't loaded" << endl;
    }

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

//Wrap Mode
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
   
    //Filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   
    cout << SOIL_last_result() << endl;
    cout << "width = "<< width << endl;
    cout << "height = "<< height << endl;
   
    glBindTexture(GL_TEXTURE_2D, 0);
   
    glDisable(GL_TEXTURE_2D);
    cout << "init Tex glError ? " << glGetError() << endl;
    SOIL_free_image_data(image);
}

void copyTex(void){
   
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &ctex);
    glBindTexture(GL_TEXTURE_2D, ctex);
   
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   
    glBindTexture(GL_TEXTURE_2D, 0);
   
    cout << "ctex id = " << ctex << endl;
   
    try{
       
        glCopyImageSubData(tex, GL_TEXTURE_2D, 0, 0, 0, 0, ctex, GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1);
        cout << "MISSION COMPLETE "<<endl;
      
    }
    catch(int e) {
       
    cout << "ERROR : " << glGetError() << " - exp " << e <<endl;
   
    }
}

void init(void){
    glClearColor(1, 1, 1, 1);
    glShadeModel(GL_FLAT);
    initTex();
    copyTex();
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    cout << "end of init : "<<glGetError() << endl;
   
}

void display(void){
   
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D, tex);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-1, 1, 0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-1, -1, 0);
    glTexCoord2f(1.0, 1.0); glVertex3f(1, -1, 0);
    glTexCoord2f(1.0, 0.0); glVertex3f(1, 1, 0);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glFlush();
   
    cout << "End of Display : glError ? " << glGetError() << endl;
}

int main(int argc, char** argv) {
   
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(256,256);
    glutCreateWindow(argv[0]);
   
    init();
    glutDisplayFunc(display);
    glutMainLoop();
   
    return 0;

Please let me know if i’m doing something wrong :)
Any tips or piece of advice is welcomed.

Cheers,

Masato

You’re using RGB input user data, but the default pixel store alignment in OpenGL is 4.
That will access data out of bounds in the initial texture upload when using widths which aren’t a multiple of four in your case.
You need to set it to 1 before initTex(), not after (see line 89).

Have a look at the common mistakes link on this site. Your case is number 3.
https://www.opengl.org/wiki/Common_Mistakes

Not sure what you mean with different contexts. Your code is copying between two different texture objects.

Other tips:

  • It’s recommended to always use an internalFormat with precision qualifier.
    In your case glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, …) instead of the legacy GL_RGB.
    Actually most hardware stores it as GL_RGBA8 internally anyway.
  • You don’t need to enable texturing when generating and initializing texture objects.
  • You probably don’t want GL_CLAMP_TO_BORDER but GL_CLAMP_TO_EDGE in your wrap modes.
    The border color is black by default. This is esp. important when using filtering on cube maps for sky boxes, etc.
    It doesn’t matter if you’re nearest filtering and not using coordinates outside the [0, 1) range.

Hi Detlef! Thanks for your reply and your tips.

However, even if I’ve taken your advice into account, it’s still running into a “segmentation fault” with glCopyImageSubData.

Especially, I’ve changed the format into GL_RGBA -GL_RGBA8 for the internal format- for all functions -i.e. glTexImage2D, SOIL_load_image (SOIL_LOAD_RGBA) and glutInitDisplayMode (GLUT_RGBA) and removed glPixelStorei since it’s the corresponding default format-.

Here’s the new code with modifications.

#include <cstdlib>
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glext.h>
#include "SOIL/SOIL.h"


using namespace std;

GLuint tex, ctex;

int width, height;


void initTex(void){
   
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
   
    //loading
    unsigned char* image;
    image = SOIL_load_image("/home/alien/sources/of_v0.9.3_linux64_release/apps/myApps/createOpenGLContext/dist/Debug/GNU-Linux/of0", &width, &height, 0, SOIL_LOAD_RGBA);
   
    if(image==0){
        cout << "Image didn't loaded" << endl;
    }
   
   
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
   
   
    //Wrap Mode
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   
    //Filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   
    cout << SOIL_last_result() << endl;
    cout << "width = "<< width << endl;
    cout << "height = "<< height << endl;
   
    glBindTexture(GL_TEXTURE_2D, 0);
   
    cout << "init Tex glError ? " << glGetError() << endl;
    SOIL_free_image_data(image);
}

void copyTex(void){
   
    glGenTextures(1, &ctex);
    glBindTexture(GL_TEXTURE_2D, ctex);
   
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   
   
    cout << "ctex id = " << ctex << endl;
   
    glBindTexture(GL_TEXTURE_2D, 0);
   
    try{
       
        glCopyImageSubData(tex, GL_TEXTURE_2D, 0, 0, 0, 0, ctex, GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1);
        cout << "MISSION COMPLETE "<<endl;
       
    }
    catch(int e) {
       
    cout << "ERROR : " << glGetError() << " - exp " << e <<endl;
   
    }
          
}

void init(void){
    glClearColor(1, 1, 1, 1);
    glShadeModel(GL_FLAT);
    //glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    initTex();
    copyTex();
    cout << "end of init : "<<glGetError() << endl;
   
}

void display(void){
   
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D, tex);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-1, 1, 0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-1, -1, 0);
    glTexCoord2f(1.0, 1.0); glVertex3f(1, -1, 0);
    glTexCoord2f(1.0, 0.0); glVertex3f(1, 1, 0);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glFlush();
   
    cout << "End of Display : glError ? " << glGetError() << endl;
}

int main(int argc, char** argv) {
   
   
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);

    glutInitWindowSize(256,256);
    glutCreateWindow(argv[0]);
   
    init();
    glutDisplayFunc(display);
    glutMainLoop();
   
    return 0;
}

This is the output I get :

Image Loaded
width = 256
height = 256
init Tex glError ? 0
ctex id = 2

RUN FINISHED: Segmentation fault: core dumped: real time 140ms; user: 50ms; system: 10ms


Not sure what you mean with different contexts. Your code is copying between two different texture objects.

I’ve failed to explain what I’m trying to do. Well, in this app it’s just loading and copying. But I would like to retrieve the copied texture data in another app. But I cannot even copy the data for now haha.
Is what I’m trying to do possible ?

Thanks again :)

Masato

Ok, I don’t see anything wrong with that code. I’ll forward it to the OpenGL driver team.

Well, in this app it’s just loading and copying. But I would like to retrieve the copied texture data in another app.
Is what I’m trying to do possible ?<<

Nope. That would mean accessing OpenGL objects across different processes. While the different apps might not even run the same OpenGL implementation, even if they’d do, they would be using different OpenGL contexts with different object name arrays, but most importantly you wouldn’t be allowed by the OS to access any other application’s address space this way for security reasons.
You would need to manually transfer the image data via some pipe interface both of your apps have been programmed to use.

Other notes:
GLUT_RGBA and GLUT_RGB are identical defines. Check the headers, both zero.
They are both used to differentiate OpenGL color RGB modes from color index modes (GLUT_INDEX).
If you want to have RGB color mode and destination alpha component you need to or GLUT_ALPHA to the flags:
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_ALPHA);

Ok, thank you for the info. Didn’t expect to encounter this kind of problem with that function.
Hope that will help for others.
Cheers.
Masato

Your program is wrong. You attempt to call glCopyImageSubData with GLEW, but you never initialize GLEW, so the function pointer is NULL.