Рендеринг текстуры OpenGL как черный

Я использую инфраструктуру Siphon, чтобы попытаться отправить кадры видео с сервера в клиентское приложение.

Siphon требует, чтобы вы использовали текстуры OpenGL вместо обычных изображений.

Из-за этого я пытаюсь отобразить CGImageRef как текстуру и отправить ее для публикации.

Я создаю свой контекст CGL так:

CGLPixelFormatAttribute attribs[13] = {
    kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3
CGLLockContext(cgl_ctx);

if (_texture) {
    glDeleteTextures(1, &_texture);
}

int width = 1920;
int height = 1080;

GLubyte* imageData = malloc(width * height * 4);
CGContextRef imageContext = CGBitmapContextCreate(imageData, width, height, 8, width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, width, height), image);
CGContextRelease(imageContext);

GLuint frameBuffer;
GLenum status;

glGenFramebuffersEXT(1, &frameBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_TEXTURE_2D, imageData);

status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
    NSLog(@"OpenGL Error");
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

CGLUnlockContext(cgl_ctx);
Core, // This sets the context to 3.2 kCGLPFAColorSize, (CGLPixelFormatAttribute)24, kCGLPFAAlphaSize, (CGLPixelFormatAttribute)8, kCGLPFAAccelerated, kCGLPFADoubleBuffer, kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1, kCGLPFASamples, (CGLPixelFormatAttribute)4, (CGLPixelFormatAttribute)0 }; CGLPixelFormatObj pix; GLint npix; CGLChoosePixelFormat(attribs, &pix, &npix); CGLCreateContext(pix, 0, &_ctx);

У меня уже есть CGImageRef, который, как я знаю, может правильно отображаться как NSImage.

Я визуализирую текстуру так:

CGLLockContext(cgl_ctx);

if (_texture) {
    glDeleteTextures(1, &_texture);
}

int width = 1920;
int height = 1080;

GLubyte* imageData = malloc(width * height * 4);
CGContextRef imageContext = CGBitmapContextCreate(imageData, width, height, 8, width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, width, height), image);
CGContextRelease(imageContext);

GLuint frameBuffer;
GLenum status;

glGenFramebuffersEXT(1, &frameBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_TEXTURE_2D, imageData);

status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
    NSLog(@"OpenGL Error");
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

CGLUnlockContext(cgl_ctx);

Код рендеринга находится в другом классе, но контекст должен передаваться и остается тем же.

Я пробовал совет практически во всех других случаях этой проблемы, но безрезультатно.


person JamEngulfer    schedule 09.06.2015    source источник


Ответы (2)


Предпоследний параметр в glTexImage2D:

type
Определяет тип данных пикселя. Принимаются следующие символьные значения: GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2 и GL_UNSIGNED_INT_2_10_10_10_REV.

GL_TEXTURE_2D здесь не имеет смысла, это должен быть любой тип данных элементов imageData.

Вы также должны проверять свои ошибки OpenGL с помощью glGetError или ARB_debug_output. Вам бы сразу показали, что не так:

Source:OpenGL   Type:Error  ID:5    Severity:High   Message:GL_INVALID_ENUM in glTexImage2D(incompatible format = GL_RGBA, type = GL_TEXTURE_2D)
person orost    schedule 09.06.2015
comment
Учитывая мой imageContext, что бы вы предложили для типа? Буду ли я использовать GL_UNSIGNED_BYTE? - person JamEngulfer; 10.06.2015
comment
@ JamEngulfer221 Я не знаком с используемой вами структурой. Но данные изображения обычно представляют собой числа с плавающей запятой или беззнаковые целые числа. - person orost; 10.06.2015
comment
Глядя на код, наверняка элементы imageData будут GLubyte или байтами без знака? - person JamEngulfer; 10.06.2015
comment
@ JamEngulfer221 Если это байты без знака, то GL_UNSIGNED_BYTE — это тот тип, который вам нужен, да. - person orost; 10.06.2015
comment
Кроме того, как я могу получить отчет об ошибках, как вы написали? Кажется, я не могу найти хорошую документацию по использованию того, что вы упомянули. - person JamEngulfer; 10.06.2015
comment
@JamEngulfer221 glGetError описан здесь, и ARB_debug_output < href="https://www.opengl.org/registry/specs/ARB/debug_output.txt" rel="nofollow noreferrer">здесь. Последний является расширением, поэтому он может быть или не быть доступным в вашей системе. - person orost; 10.06.2015
comment
Я изменил код, как вы предложили, но он все равно возвращает черный экран. - person JamEngulfer; 10.06.2015
comment
Фактическая причина проблемы заключалась в том, что я передавал данные в неправильном порядке и использовал нулевой контекст. Однако этот ответ решил бы проблему, если бы я изначально все правильно настроил. - person JamEngulfer; 10.06.2015

В этом коде есть несколько проблем. Следующее имеет решающее значение для того, чтобы все заработало:

  • Как также указывалось в более раннем ответе @orost, параметр type для вызова glTexImage2D() недействителен. Должен быть:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    
  • Текстура никогда не прикрепляется как цель FBO. При настройке FBO вам необходимо:

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                           GL_TEXTURE_2D, _texture, 0);
    

Есть еще пара пунктов, которые, вероятно, не помешают вам запустить его, но я бы все равно рекомендовал их изменить:

  • Вам не нужно указывать данные для текстуры, если вы собираетесь создавать контент путем рендеринга в него. Данные, которые вы передаете glTexImage2D(), в любом случае не инициализированы, так что это не принесет большой пользы. Гораздо удобнее передать NULL в качестве аргумента data, как я уже делал в вызове, показанном выше.
  • Поскольку вы используете OpenGL 3.2, нет необходимости использовать форму EXT точек входа FBO. Это стандартная функциональность в OpenGL 3.x. Форма EXT, вероятно, будет работать до тех пор, пока вы будете использовать ее последовательно, но вы рискуете получить неприятные сюрпризы, если будете смешивать ее со стандартными точками входа.
person Reto Koradi    schedule 10.06.2015
comment
Глядя на мой код, я подумал, что imageData будет инициализирован, потому что я думал, что нарисовал изображение в контексте, который каким-то образом использует imageData. - person JamEngulfer; 10.06.2015
comment
Что касается указания данных, то эти данные ЯВЛЯЮСЬ тем, что я хочу отобразить. Если я его не включу, рендерить будет буквально нечего, потому что данные изображения больше нигде не упоминаются в коде рендеринга. - person JamEngulfer; 10.06.2015
comment
Думаю, я понимаю ваши намерения, но это не так. Когда вы передаете указатель данных в glTexImage2D(), он используется только во время вызова для заполнения текстуры данными. Указатель не связан с текстурой постоянно. Если вы визуализируете текстуру и хотите получить копию полученного изображения на процессоре, вам нужно будет прочитать его обратно с помощью glReadPixels(). - person Reto Koradi; 10.06.2015
comment
Я только что прочитал документацию для glTexImage2D() и, кажется, не согласен с вами. Там написано: If target is GL_TEXTURE_2D, ... data is read from data as a sequence of signed or unsigned bytes... - person JamEngulfer; 10.06.2015
comment
@ JamEngulfer221 Да, чем это отличается от того, что я сказал? Вызов glTexImage2D() считывает данные, которые вы передаете во время вызова. Он никак не использует его после возврата вызова. - person Reto Koradi; 10.06.2015
comment
О да, я понимаю, что вы имели в виду. Извините, я, должно быть, неправильно прочитал это. - person JamEngulfer; 10.06.2015