Possible causes for RGB/BGR channel swap in off-screen GPU rendering pipeline

GPU Rendering Pipeline Description

GPU Model: BXEP-4-32

Input Process:

  1. Memory Allocation: VI (Video Input) calls SMR allocator to obtain physical memory and writes YUV422 data into this SMR.
  2. DMA Buffer Creation: Register the SMR physical address to create a DMA buffer, then obtain a DMA file descriptor using dma_buf_export and dma_buf_fd.
  3. EGLImage Creation: Create an EGLImage using the DMA file descriptor.
  4. Texture Creation: Create an input texture based on the EGLImage (using DRM_FORMAT_UYVY format).

Output Process:

  1. Memory Allocation: Call SMR API to allocate physical memory as output buffer.
  2. DMA Buffer Registration: Register the SMR physical address to create a DMA buffer and obtain a DMA file descriptor.
  3. EGLImage Creation: Create an EGLImage using the DMA file descriptor.
  4. Texture Creation: Create a texture based on the EGLImage.
  5. FBO Creation: Create a Framebuffer Object (FBO) with the texture (using DRM_FORMAT_RGB888 format).

Rendering Process:

  1. Bind the FBO.
  2. Bind the input texture.
  3. Execute glDrawArrays for rendering.

Fragment Shader Code:

#version 320 es
#extension GL_EXT_YUV_target : enable

in highp vec2 texcoord;
out highp vec3 myFragColor;

uniform highp __samplerExternal2DY2YEXT basetexture;

void main(void)
{
    highp vec4 myFragColorYUV = texture(basetexture, texcoord);
    myFragColor = vec3(yuv_2_rgb(myFragColorYUV.xyz, itu_601));
}

Issue Encountered:
The actual output image format appears to be BGR888 instead of the expected RGB888.

Question:
Is this rendering pipeline incorrect? What could be causing the RGB/BGR channel swap in the final output?

I have verified the output format behaviors in two scenarios as follows:

1. Output Format: DRM_FORMAT_ARGB8888

Fragment Shader Code:

glsl

#version 320 es
#extension GL_EXT_YUV_target : enable

in highp vec2 texcoord;

out highp vec4 myFragColor;

uniform highp __samplerExternal2DY2YEXT basetexture;

void main(void)
{
	highp vec4 myFragColorYUV = texture(basetexture, texcoord);
	myFragColor = vec4(yuv_2_rgb(myFragColorYUV.xyz, itu_601), 1.0);
}

Observation: The actual output image format is RGBA8888 (instead of the expected ARGB8888).

2. Output Format: DRM_FORMAT_BGR888

Fragment Shader Code:

glsl

#version 320 es
#extension GL_EXT_YUV_target : enable

in highp vec2 texcoord;

out highp vec3 myFragColor;

uniform highp __samplerExternal2DY2YEXT basetexture;

void main(void)
{
	highp vec4 myFragColorYUV = texture(basetexture, texcoord);
	myFragColor = vec3(yuv_2_rgb(myFragColorYUV.xyz, itu_601));
}

Findings:

  • I had to set the EGL_DMA_BUF_PLANE0_PITCH_EXT attribute to output_image_width * 4; otherwise, the eglCreateImageKHR function would return an error (failed to create EGLImage).

  • After setting EGL_DMA_BUF_PLANE0_PITCH_EXT = width * 4, the saved image shows offset (misalignment) and horizontal stripe artifacts.

3 When the fragment shader is configured to output myFragColor = vec3(1.0, 0.0, 0.0); (intended to produce pure red), the saved image actually appears blue instead of the expected red.

Hi Jason1,

Thanks for your message, and welcome to the PowerVR Developer Forum!

I would advice comparing your code with our basic PowerVR SDK OpenGL ES example IntroducingPVRCamera, present in Native_SDK/examples/OpenGLES/05_IntroducingPVRCamera at master · powervr-graphics/Native_SDK · GitHub as there are similarities with your application.

We also have a Vulkan sample which shows how to sample different YUV textures in Native_SDK/examples/Vulkan/YCbCrTextureSampling at master · powervr-graphics/Native_SDK · GitHub in case it is of any help.

Best regards,
Alejandro