简体   繁体   中英

using openGL ES from C++: error 1281 on glUseProgram

I am trying to move some openGL processing to a C++ class, which is wrapped in an Objective-C class for use with iOS. Most of it seems to work, but I'm not getting the rendering into the frame buffer. When I bracket every openGL call with glGetError() - both in the Objective-C wrapper and the C++ class - I get an error 1281 (GL_INVALID_VALUE) upon calling glUseProgram (from within the C++ method renderTextures.)

(FWIW, this is then followed by GL_INVALID_OPERATION (1282) on two subsequent calls: glUniform1i and glUniformMatrix4fv, which I suppose makes sense if these are associated with the shader program. PS I used a custom wrapper function on glGetError that loops until the return value is zero - these are the only three errors I get.)

I can set and retrieve arbitrary values from the frame buffer (using glClearColor and glClear to set them, and glReadPixels to retrieve them), so the frame buffer seems to be set up OK. But the rendering (via glDrawElements) seems to fail, and I am supposing this is related to the error I get on glUseProgram. Notice that the argument _program for glUseProgram gets passed in from the Objective-C wrapper, via the call to MyClass::renderTextures. The value is the same (it's just a handle, right?) but the call fails inside the C++ class.

So... any ideas why glUseProgram fails? Is it how I set up the argument _program? That I'm passing it from Objective-C to C++? (Something about losing access to the context from inside the C++?) Something else that anyone can see?

Code follows below (much based on boilerplate from Xcode)

Objective-C wrapper:

#import “MyClass.h”

// OBJECTIVE-C WRAPPER CLASS

@interface ObjCWrapperClass () {
    MyClass *_myObject;
    GLuint _program;
    GLint _mvpUniform;
    GLint _textureUniform;
    GLKMatrix4 _modelViewProjectionMatrix;
}

@property EAGLContext *myContext;

@end


@implementation ObjCWrapperClass

-(id)init {
    if (self = [super init]) {
        self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

        _myObject = new MyClass();
        BOOL result = [self loadShaders];
    }

    return self;
}

-(void)doRender {
    // Has to be in Objective-C
    [EAGLContext setCurrentContext:self.queryContext];

    // ----  Use C++ ------------------------------
    // 1. Create frame buffer
    _myObject->createFrameBuffer();

    // 2. Get Texture List
    _myObject->createTextureList();

    // 3. Create the Texture Geometry
    _myObject->createTextureGeometry();

    // 4. Load textures
    _myObject->loadTextures();

    if ([NSThread isMainThread]) {
       [self doRenderInCPP];
    }
    else {
        dispatch_sync(dispatch_get_main_queue(), ^{
            [self doRenderInCPP];
        } );
    }

    _myObject->deleteTextures();

    // ----  END C++ ------------------------------
}


-(void)doRenderInCPP 
{
    // Render textures into framebuffer
    _myObject->renderTextures(_program, _mvpUniform, _textureUniform);
}

#pragma mark -  OpenGL ES 2 shader compilation

- (BOOL)loadShaders
{
    GLuint vertShader, fragShader;
    NSString *vertShaderPathname, *fragShaderPathname;

    // Create shader program.
    _program = glCreateProgram();

    // Create and compile vertex shader.
    vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];

    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
        NSLog(@"Failed to compile vertex shader");
        return NO;
    }

    // Create and compile fragment shader.
    fragShaderPathname = [[NSBundle mainBundle] pathForResource:@“Shader" ofType:@"fsh"];

    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }

    // Attach vertex shader to program.
    glAttachShader(_program, vertShader);

    // Attach fragment shader to program.
    glAttachShader(_program, fragShader);


    // Bind attribute locations.
    // This needs to be done prior to linking.
    glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
    glBindAttribLocation(_program, GLKVertexAttribTexCoord0, "texCoord");

    // Link program.

    if (![self linkProgram:_program]) {
        NSLog(@"Failed to link program: %d", _program);        
        if (vertShader) {
            glDeleteShader(vertShader);
            vertShader = 0;
        }
        if (fragShader) {
            glDeleteShader(fragShader);
            fragShader = 0;
        }

        if (_program) {
            glDeleteProgram(_program);
            _program = 0;
        }

        return NO;

    }

    // Get uniform locations.
    _mvpUniform = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    _textureUniform = glGetUniformLocation(_program, "tileTexture");

    // Release vertex and fragment shaders.
    if (vertShader) {
        glDetachShader(_program, vertShader);
        glDeleteShader(vertShader);
    }

    if (fragShader) {
        glDetachShader(_program, fragShader);
        glDeleteShader(fragShader);
    }

    return YES;
}


- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
    GLint status;
    const GLchar *source;
    source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];

    if (!source) {
        NSLog(@"Failed to load vertex shader");
        return NO;
    }

    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);

#if defined(DEBUG)
    GLint logLength;
    glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);

    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(*shader, logLength, &logLength, log);
        NSLog(@"Shader compile log:\n%s", log);
        free(log);
    }
#endif

    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);

    if (status == 0) {
        glDeleteShader(*shader);
        return NO;
    }

    return YES;
}


- (BOOL)linkProgram:(GLuint)prog
{
    GLint status;
    glLinkProgram(prog);    

#if defined(DEBUG)
    GLint logLength;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
#endif

    glGetProgramiv(prog, GL_LINK_STATUS, &status);

    if (status == 0) {
        return NO;
    }

    return YES;
}

@end

C++ (Relevant bits):

//
//  MyClass.cpp
//

#include “MyClass.h”

void MyClass::createFrameBuffer()
{
    glGenFramebuffers(1, &_frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);

    // Create the texture:
    glGenTextures(1, &_frameBufferTexture);
    glBindTexture(GL_TEXTURE_2D, _frameBufferTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, _drawFormatEnum, _destinationSizeWidth, _destinationSizeHeight, 0, _drawFormatEnum, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _frameBufferTexture, 0);

    GLenum error = glGetError();
    if (error != 0) {
        printf("Error Creating Depth Buffer: %i (backing size: %i %i)\n", error, _destinationSizeWidth, _destinationSizeHeight);
    }

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        printf("Failed to make complete framebuffer object %x\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
    }

    glClearColor(0.015625, 0.03125, 0.0, 1.0); // For testing - put distinctive values in to see if we find these in Framebuffer
    glClear(GL_COLOR_BUFFER_BIT);
}


void MyClass::renderTextures(GLint program,  GLint mvpUniform, GLint textureUniform)
{
    // Clear the draw buffer
    glClearColor(0.0, 0.0, 0.0625, 1.0); // TEST: clear to distinctive values
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw each segment in a different area of frame buffer
    for (int segment_index = 0; segment_index < _numSegments; segment_index++) {

        // Set draw region
        glScissor(segment_index*(_segmentWidthPixels), 0, _segmentWidthPixels, _segmentHeightPixels);
        glEnable(GL_SCISSOR_TEST);

        int segment_horz_offset = getSegmentHorzOffset(segment_index);
        int segment_vert_offset = getSegmentVertOffset(segment_index);

        FFGLKMatrix4 modelViewProjectionMatrix = createMVPmatrix(segment_horz_offset, segment_vert_offset);

        // Render the object ES2
        glUseProgram(program);    // Error after glUseProgram:, GL_INVALID_VALUE (1281)
        glUniform1i(textureUniform, 0); //GL_INVALID_OPERATION (1282)
        glUniformMatrix4fv(mvpUniform, 1, 0, modelViewProjectionMatrix.m); //GL_INVALID_OPERATION (1282)

        glEnableVertexAttribArray(FFGLKVertexAttribPosition);
        glEnableVertexAttribArray(FFGLKVertexAttribTexCoord0);

        glActiveTexture(GL_TEXTURE0);

        for (auto &texture: _textures) {
            uint8_t *data = (uint8_t *)texture.geometryData;
            glVertexAttribPointer(FFGLKVertexAttribPosition, 2, GL_FLOAT, 0, sizeof(float)*4, data);
            glVertexAttribPointer(FFGLKVertexAttribTexCoord0, 2, GL_FLOAT, 0, sizeof(float)*4, data+8);
            glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
            glDrawElements(GL_TRIANGLE_STRIP, _textureVertexIndicesCount, GL_UNSIGNED_SHORT, _textureVertexIndices);
        }
        glDisable((GL_SCISSOR_TEST));

        // Test - are correct values rendered into the frame buffer?
        uint8_t *outdata = new uint8_t[100*4];
        glReadPixels(0, 0, (GLsizei)2, (GLsizei)4, GL_RGBA, GL_UNSIGNED_BYTE, outdata);

        for (int i=0; i < 8; i++) {
        printf("render: Value: %i\n", outdata[i]);  // Prints values as specified in glClearColor above (0,0,16,255)
    }

        printf("glGetError: %d\n", glGetError() );
        delete [] outdata;   
    }

}

Error 1281 resolved (openGL newbie mistake) - needed to set context:

(Still not rendering into frame buffer, but another hurdle cleared.)

-(id)init {
    if (self = [super init]) {
        self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        [EAGLContext setCurrentContext:self.myContext];  // <-- ADDED
        _myObject = new MyClass();
        BOOL result = [self loadShaders];
    }

    return self;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM