Почему текстура EGL RGBA32 всегда имеет 1,0-дюймовый альфа-канал?

Я создаю буфер текстур NVidia на Jetson AGX Xaview со следующим:

NvBufferCreateParams params = {
     .width = TEXTURE_WIDTH,
     .height = TEXTURE_HEIGHT,
     .payloadType = NvBufferPayload_SurfArray,
     .memsize = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4,
     .layout = NvBufferLayout_Pitch,
     .colorFormat = NvBufferColorFormat_ARGB32,
     .nvbuf_tag = NvBufferTag_NONE
};
NvBufferCreateEx(&f_texture_fd, &params));

Затем я хочу нарисовать изображение в этой области, поэтому я использую следующее, чтобы сопоставить текстуру с указателем памяти:

NvBufferMemMap(
          f_texture_fd
        , 0
        , NvBufferMem_Read_Write
        , reinterpret_cast<void **>(&f_texture));

NvBufferMemSyncForCpu(
          f_texture_fd
        , 0
        , reinterpret_cast<void **>(&f_texture));

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

Аналогичным образом я отключу текстуру следующим образом, как мы видим, у меня также есть вызов синхронизации, поэтому графический процессор видит мои изменения:

NvBufferMemSyncForDevice(f_texture_fd, 0, reinterpret_cast<void **>(&f_texture));

ckt(NvBufferMemUnMap(
          f_texture_fd
        , 0
        , reinterpret_cast<void **>(&f_texture)));
f_texture = nullptr;  // pointer was invalidated

Отмена отображения происходит только после того, как я закончу рендеринг своего изображения в буфере.

Вот пример, показывающий, как я визуализирую изображение в текстуру:

std::uint8_t * output(f_texture);
for(int idx(0); idx < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++idx, output += 4)
{
    output[0] = blue;
    output[1] = green;
    output[2] = red;
    output[3] = alpha;   // <-- whatever I put here, in the fragment shader `tex.a == 1.0`
}

Теперь я могу работать над визуализацией. Поскольку я использую EGL, сначала мне нужен вершинный шейдер:

precision mediump float;

varying vec2 interp_tc;

// the input position includes (x,y) for the vertex and (x,y) for the texture
attribute vec4 in_position;

void main()
{
    interp_tc = in_position.zw;
    gl_Position = vec4(in_position.xy, 0, 1);
}

а затем фрагмент шейдеров:

#extension GL_OES_EGL_image_external : require

precision mediump float;

varying vec2 interp_tc;
uniform samplerExternalOES tex;

void main()
{
    gl_FragColor = texture2D(tex, interp_tc);
}

А рендеринг в моей программе выглядит так:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
f_egl_image = NvEGLImageFromFd(
              f_egl_display
            , f_texture_fd);
glUseProgram(f_program);
glActiveTexture(f_texture_id);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, f_texture);
panel_context::glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, f_egl_image);
glDrawArrays(GL_TRIANGLES, 0, 6);
glUseProgram(0);

glSwapBuffers();

NvDestroyEGLImage(f_egl_display, f_egl_image);

Рендеринг отлично работает для части RGB (я получаю правильные цвета), но я ничего не вижу даже там, где альфа не равна 255 (1.0) в моей текстуре. Для проверки я даже изменил этот цикл выше, чтобы использовать rand() вот так:

    output[3] = rand();  // <- random alpha channel

Это должно дать мне флуктуирующий альфа-канал, который будет отображаться на экране как смесь фона и этого изображения. Изображение по-прежнему кажется 100% сплошным.

Кроме того, смешивание работает просто отлично, так как я могу настроить альфа-канал во фрагментном шейдере, и он работает, как и ожидалось, поэтому, например, я мог бы настроить шейдер следующим образом:

if(texture2D(tex, interp_tc).a == 1.0)
{
    gl_FragColor = vec4(1.0, 0.75, 0.0, 0.3);
}
else
{
    gl_FragColor = texture2D(tex, interp_tc);
}

и изображение оранжевое, потому что входной альфа-канал всегда равен 1,0, а FragColor установлен на довольно прозрачный оранжевый цвет. Я вижу сквозь этот оранжевый цвет, как и ожидалось (т. е. 0,3 соответствует действительности и работает так, как я ожидал).

Я также пробовал следующее:

gl_FragColor = vec4(texture2D(tex, interp_tc).r,
                    texture2D(tex, interp_tc).g,
                    texture2D(tex, interp_tc).b,
                    0.5);

и, конечно же, изображение появляется с прозрачностью 50%, поэтому я вижу фон через изображение текстуры.

Другими словами, я могу заставить RGB и альфу работать, только текстура tex, кажется, не несет альфу, которую я в нее вложил.

Чтение Фрагментный шейдер всегда использует 1.0 для альфа-канала заставляет меня думать, что каким-то образом доступ к tex эквивалентен:

vec4(r, g, b, 1.0);

Но я не использую буфер глубины или какую-то особую магию. Я явно выделяю буфер NvBufferColorFormat_ARGB32 для своей текстуры.


person Alexis Wilke    schedule 02.04.2021    source источник