android — Неожиданное расположение пиксельных данных при чтении из GraphicBuffer

В настоящее время я работаю над платформой в родной среде Android, где я использую GraphicBuffer для выделения памяти, а затем создаю EGLImage из нее. Затем это используется в качестве текстуры в OpenGL, которую я рендеринг (с простым полноэкранным четырехугольником).

Проблема заключается в том, что когда я читаю данные визуализированных пикселей из GraphicBuffer, я ожидаю, что они будут в памяти в линейном формате RGBA, но в результате получится текстура, которая содержит три параллельных меньших клона изображения и с перекрывающимися пикселями. Может быть, это описание мало что говорит, но дело в том, что фактические данные в пикселях имеют смысл, но расположение памяти кажется чем-то отличным от линейного RGBA. Я предполагаю, что это потому, что графические драйверы хранят пиксели во внутреннем формате, отличном от линейного RGBA.

Если я отрисовываю стандартную текстуру OpenGL и читаю с glReadPixels, все работает нормально, поэтому я предполагаю, что проблема заключается в моем пользовательском распределении памяти с помощью GraphicBuffer.

Если причина заключается в расположении внутренней памяти драйверов, есть ли способ принудительно настроить расположение на линейный RGBA? Я пробовал большинство флагов использования, предоставленных конструктору GraphicBuffer, но безуспешно. Если нет, есть ли способ вывести данные по-разному в шейдере, чтобы «отменить» макет памяти?

Я собираю Android 4.4.3 для Nexus 5.

//Allocate graphicbuffer
outputBuffer = new GraphicBuffer(outputFormat.width, outputFormat.height, outputFormat.bufferFormat,
GraphicBuffer::USAGE_SW_READ_OFTEN |
GraphicBuffer::USAGE_HW_RENDER |
GraphicBuffer::USAGE_HW_TEXTURE);

/* ... */

//Create EGLImage from graphicbuffer
EGLint eglImageAttributes[] = {EGL_WIDTH, outputFormat.width, EGL_HEIGHT, outputFormat.height, EGL_MATCH_FORMAT_KHR,
outputFormat.eglFormat, EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, EGL_NONE};

EGLClientBuffer nativeBuffer = outputBuffer->getNativeBuffer();

eglImage = _eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, nativeBuffer, eglImageAttributes);

/* ... */

//Create output texture
glGenTextures(1, &outputTexture);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);

/* ... */

//Create target fbo
glGenFramebuffers(1, &targetFBO);
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0);

glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* ... */
//Read from graphicbuffer
const Rect lockBoundsOutput(quadRenderer->outputFormat.width, quadRenderer->outputFormat.height);

status_t statusgb = quadRenderer->getOutputBuffer()->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &result);

2

Решение

Мне удалось найти ответ самому, и я все время был неправ. Простая причина состояла в том, что, хотя я рендерил текстуру 480×1080, выделенная память была заполнена до 640×1080, поэтому мне просто нужно было удалить заполнение после каждой строки, и выходная текстура имела смысл.

0

Другие решения