замена glReadPixels на EGL_KHR_image_base для более быстрого копирования пикселей

Я пытаюсь использовать EGL_KHR_image_base в собственном процессе Android, чтобы заменить glReadPixels, потому что он медленный (220 мс для 1280x800 RGBA).

Это то, что у меня есть до сих пор, но у меня он создает пустой буфер (только нули)

uint8_t *ptr;
GLuint mTexture;
status_t error;

GraphicBufferAlloc* mGraphicBufferAlloc  = new GraphicBufferAlloc();    
sp<GraphicBuffer> window = mGraphicBufferAlloc->createGraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE,&error);
EGLClientBuffer buffer = (EGLClientBuffer)window->getNativeBuffer();
EGLint eglImageAttributes[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_MATCH_FORMAT_KHR,  EGL_FORMAT_RGBA_8888_KHR, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,buffer, eglImageAttributes);

glGenTextures(1, &mTexture);    
glBindTexture(GL_TEXTURE_2D, mTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
window->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, (void**)&ptr); 
memcpy(texture, ptr, width * height * 4);
window->unlock();

Что я делаю неправильно ?


person jacob    schedule 16.01.2014    source источник
comment
Ваши ширина и высота не равны нулю?   -  person HalR    schedule 16.01.2014
comment
да, я проверил. это 1280*800   -  person jacob    schedule 16.01.2014


Ответы (2)


Вы создаете пустой буфер, а затем читаете из него содержимое. Прогулка по коду:

GraphicBufferAlloc* mGraphicBufferAlloc = new GraphicBufferAlloc();
sp<GraphicBuffer> window = mGraphicBufferAlloc->createGraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE,&error);

Это создает новый GraphicBuffer (иногда называемый «буфером gralloc») с указанными размерами и форматом пикселей. Флаги использования позволяют использовать его в качестве текстуры или считывать из программного обеспечения, что вам и нужно.

EGLClientBuffer buffer = (EGLClientBuffer)window->getNativeBuffer();
EGLint eglImageAttributes[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_MATCH_FORMAT_KHR,  EGL_FORMAT_RGBA_8888_KHR, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,buffer, eglImageAttributes);

Это берет объект ANativeWindow (который представляет собой очередь буферов под капотом) и прикрепляет к нему "дескриптор" EGLImage.

glGenTextures(1, &mTexture);    
glBindTexture(GL_TEXTURE_2D, mTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);

Это создает новый объект текстуры и прикрепляет к нему EGLImage. Итак, теперь ANativeWindow можно использовать как объект текстуры.

window->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, (void**)&ptr); 
memcpy(texture, ptr, width * height * 4);
window->unlock();

Это блокирует буфер для чтения, копирует данные из него и разблокирует его. Раз ты ничего не нарисовал, то и читать нечего.

Чтобы сделать что-то полезное, вам нужно что-то визуализировать в текстуру. Вы можете сделать это, создав FBO и присоединив к нему текстуру в качестве цветового буфера, или используя glCopyTexImage2D() для копирования пикселей из фреймбуфера в текстуру.

Я смог заставить ваш пример работать, добавив следующее перед вызовом grallocBuffer->lock():

glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
glFinish();

glFinish() необходим, чтобы убедиться, что GL закончил копирование пикселей, прежде чем мы попытаемся посмотреть на них.

Редактировать: мой коллега по офису предположил, что GL_TEXTURE_2D должно быть GL_TEXTURE_EXTERNAL_OES. Еще не пробовал.

Изменить: см. также этот вопрос.

person fadden    schedule 18.01.2014
comment
Спасибо за помощь, у вас получилось? Я все еще получаю пустой буфер (хотя теперь это занимает около 50 мс) даже после добавления: glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, ширина, высота, 0); глфиниш(); не могли бы вы взглянуть: dl.dropboxusercontent.com/u/36894441/Overlay.cpp dl.dropboxusercontent.com/u/36894441/EglWindow.cpp - person jacob; 18.01.2014
comment
Теперь я вижу, что это не совсем пустой буфер, а только начало каждого 4096000, с данными, а все остальное - нули. Вы можете опубликовать код, который вы пробовали? - person jacob; 19.01.2014
comment
Хм, я не сохранял кадр как изображение, просто проверял, не все ли там нули. В начале вашей функции добавьте glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);. Это заполнит кадр серым на 50%, гарантируя, что ни одно из значений байта не равно нулю. Что ты видишь тогда? (Пройдет пара дней, прежде чем я смогу опубликовать свой эксперимент.) - person fadden; 19.01.2014
comment
На Nexus 5, где я проводил тестирование, я получил вроде бы хорошие данные, но glCopyTexImage2D() начинает выдавать ошибки после первого кадра. На Nexus 10 все возвращается без ошибок, пока я не указываю никаких атрибутов для eglCreateImageKHR(), но буфер всегда заполняется нулями (то же самое, что вы видите). Значит, что-то не так. - person fadden; 03.02.2014
comment
@fadden Я хочу скопировать пиксель, я скопировал из PBO, когда мобильный телефон поддерживает OpenGL es 3.0, и когда они поддерживают только OpenGL es 2.0, я хочу использовать GraphicBufferAlloc в Android NDK proj. но я получил сообщение об ошибке: «GraphicBufferAlloc» не был объявлен в этой области, когда я компилирую файл cpp, я не знаю, какой файл заголовка нужно импортировать. Не могли бы вы мне помочь, плз? мои включаемые файлы выглядят следующим образом: ‹GLES2/gl2.h› #include ‹GLES2/gl2ext.h› - person dragonfly; 23.12.2015
comment
@jacob Уважаемый jacob, я пытался сделать то же самое, что и вы, но мне не удалось успешно скомпилировать исходные коды с помощью ndk. Причина должна заключаться в том, что GraphicBufferAlloc отсутствует в ndk. Но почему вы можете компилировать исходные коды? Как ты это сделал? Не могли бы вы помочь мне? - person dragonfly; 06.01.2016

GraphicBuffer является частью исходного кода Android, а не NDK. см. это для справки: https://github.com/fuyufjh/GraphicBuffer

person johnson.zhi    schedule 28.12.2016