Как настроить подкласс CAEAGLLayer с контекстом openGL: Текущий кадровый буфер рисования недействителен

Я пытаюсь настроить подкласс CAEAGLLayer с контекстом gl. То есть вместо создания подкласса UIView, который возвращает CAEAGLLayer, и связывания контекста gl с этим слоем из подкласса UIView, я непосредственно подклассифицирую слой и пытаюсь настроить контекст в init слоя, например, так:

- (id)init
{
    self = [super init];
    if (self) {
        self.opaque = YES;

        _glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        NSAssert([EAGLContext setCurrentContext:_glContext], @"");

        glGenRenderbuffers(1, &_colorRenderBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
        [_glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self];

        glGenFramebuffers(1, &_framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);

        /// . . .

до этого момента все кажется хорошо. Однако затем я пытаюсь создать шейдерную программу с парной вершинно-фрагментной шейдерной партией, и при связывании программа не возвращает ошибок, проверка не проходит, говоря: "Текущий кадровый буфер рисования недопустим".

Код, который связывает и проверяет шейдерную программу (после подключения шейдеров), выглядит так, на всякий случай:

- (BOOL)linkAndValidateProgram
{
    GLint status;
    glLinkProgram(_shaderProgram);

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

    glGetProgramiv(_shaderProgram, GL_LINK_STATUS, &status);
    if (!status) {
        return NO;
    }

    glValidateProgram(_shaderProgram);

#ifdef DEBUG
    glGetProgramiv(_shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
    if (infoLogLength > 0) {
        infoLog = (GLchar *)malloc(infoLogLength);
        glGetProgramInfoLog(_shaderProgram, infoLogLength, &infoLogLength, infoLog);
        NSLog(@"Program validation log:\n%s", infoLog);
        free(infoLog);
    }
#endif

    glGetProgramiv(_shaderProgram, GL_VALIDATE_STATUS, &status);
    if (!status) {
        return NO;
    }

    glUseProgram(_shaderProgram);
    return YES;
}

Мне интересно, могут ли быть какие-то дополнительные настройки в какой-то момент в течение жизненного цикла CAEAGLLayer, о которых я мог не знать и мог бы пропустить, пытаясь настроить GL в init?

2 ответа

Решение

Проблема заключалась в том, что слой не имеет размеров в этой точке в init. Что, в свою очередь, приводит к тому, что при попытке установить хранилище рендеринга для буфера слой равен 0.

ОБНОВЛЕНИЕ: В настоящее время лучше всего думать, что вместо наложения размера на init (который отлично работал в целях тестирования, но довольно хакерский), я должен просто переустанавливать буферное хранилище всякий раз, когда слой меняет размеры. Так что я переопределяю -setBounds: вот так:

- (void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self];
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &someVariableToHoldWidthIfYouNeedIt);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &someVariableToHoldHeightIfYouNeedIt);
}

Насколько я знаю, вы должны переписать метод layerClass в представлении, как это

    + (Class)layerClass
    {
       return [MYCEAGLLayer class];
    }

Также вы должны установить drawableProperties на MYCEAGLLayer.

Другие вопросы по тегам