【问题标题】:using openGL ES from C++: error 1281 on glUseProgram从 C++ 使用 openGL ES:glUseProgram 上的错误 1281
【发布时间】:2015-05-03 18:08:15
【问题描述】:

我正在尝试将一些 openGL 处理移至 C++ 类,该类包装在 Objective-C 类中以供 iOS 使用。大多数似乎都可以工作,但我没有将渲染放入帧缓冲区。当我将 每个 openGL 调用与 glGetError() 括起来时 - 在 Objective-C 包装器和 C++ 类中 - 在调用 glUseProgram 时(从 C++ 方法 renderTextures 中)出现错误 1281 (GL_INVALID_VALUE)。

(FWIW,然后在随后的两个调用中跟随 GL_INVALID_OPERATION (1282):glUniform1i 和 glUniformMatrix4fv,如果它们与着色器程序相关联,我认为这是有道理的。P.S.我在 glGetError 上使用了一个自定义包装函数,循环直到返回值为零 - 这是我得到的仅有的三个错误。)

我可以从帧缓冲区设置和检索任意值(使用 glClearColor 和 glClear 设置它们,并使用 glReadPixels 检索它们),因此帧缓冲区似乎设置正常。但是渲染(通过 glDrawElements)似乎失败了,我认为这与我在 glUseProgram 上遇到的错误有关。请注意,glUseProgram 的参数 _program 是通过对 MyClass::renderTextures 的调用从 Objective-C 包装器传入的。值是相同的(它只是一个句柄,对吗?)但在 C++ 类中调用失败。

所以... glUseProgram 失败的任何想法?是我如何设置参数_program?我正在将它从 Objective-C 传递到 C++? (关于从 C++ 内部失去对上下文的访问权?)其他任何人都可以看到的东西?

代码如下(大部分基于 Xcode 的样板)

Objective-C 包装器:

#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++(相关位):

//
//  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;   
    }

}

【问题讨论】:

  • 您可以尝试删除glDetachShader() 调用吗?看起来您在使用着色器程序之前就将其拆除。
  • 刚刚试过 - 没有区别。这是 Xcode 创建的样板文件的一部分,我的理解是 glDetachShader 只是标记要释放的对象,但直到不再需要它才会被释放stackoverflow.com/questions/9113154/…
  • 按照我阅读规范的方式,为您仍想使用的程序调用 glDetachShader() 只保证适用于当前活动的程序。
  • 在任何情况下,删除 glDetachShader 调用都不会改变结果 - 会发生同样的错误。

标签: c++ ios opengl-es


【解决方案1】:

错误 1281 已解决(openGL 新手错误)- 需要设置上下文:

(仍然没有渲染到帧缓冲区,但清除了另一个障碍。)

-(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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 2014-02-11
    相关资源
    最近更新 更多