Fixing displaying on devices which do not support sampling from HAL_PIXEL_FORMAT_BGRA_8888

```
gles-renderer: renderer_set_buffer0
ANGLE Info:Debug.cpp:490 (insertMessage): EGL ERROR: eglCreateImageKHR: Sampling from AHardwareBuffer externalFormat 0x5 is unsupported
gles-renderer: Xlorie: egl error on line 264: Invalid argument
gles-renderer: Binding AHardwareBuffer to an EGLImage failed.
```
This commit is contained in:
Twaik Yont 2023-10-06 16:05:35 +03:00
parent 4acf4b2422
commit 84901c2f1c
4 changed files with 100 additions and 31 deletions

View File

@ -103,6 +103,7 @@ typedef struct {
AHardwareBuffer* buffer; AHardwareBuffer* buffer;
Bool locked; Bool locked;
Bool legacyDrawing; Bool legacyDrawing;
uint8_t flip;
uint32_t width, height; uint32_t width, height;
} root; } root;
} lorieScreenInfo, *lorieScreenInfoPtr; } lorieScreenInfo, *lorieScreenInfoPtr;
@ -323,7 +324,9 @@ static void lorieUpdateBuffer(void) {
d0.height = pScreenPtr->height; d0.height = pScreenPtr->height;
d0.layers = 1; d0.layers = 1;
d0.usage = USAGE; d0.usage = USAGE;
d0.format = 5; // Stands to HAL_PIXEL_FORMAT_BGRA_8888 d0.format = pvfb->root.flip
? AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM
: AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM;
/* I could use this, but in this case I must swap colours in the shader. */ /* I could use this, but in this case I must swap colours in the shader. */
// desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; // desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
@ -418,11 +421,11 @@ static void lorieTimerCallback(int fd, unused int r, void *arg) {
ScreenPtr pScreen = (ScreenPtr) arg; ScreenPtr pScreen = (ScreenPtr) arg;
loriePixmapUnlock(pScreen->GetScreenPixmap(pScreen)); loriePixmapUnlock(pScreen->GetScreenPixmap(pScreen));
redrawn = renderer_redraw(); redrawn = renderer_redraw(pvfb->root.flip);
if (loriePixmapLock(pScreen->GetScreenPixmap(pScreen)) && redrawn) if (loriePixmapLock(pScreen->GetScreenPixmap(pScreen)) && redrawn)
DamageEmpty(pvfb->damage); DamageEmpty(pvfb->damage);
} else if (pvfb->cursorMoved) } else if (pvfb->cursorMoved)
renderer_redraw(); renderer_redraw(pvfb->root.flip);
pvfb->cursorMoved = FALSE; pvfb->cursorMoved = FALSE;
} }
@ -662,7 +665,7 @@ Bool lorieChangeWindow(unused ClientPtr pClient, void *closure) {
if (pvfb->root.legacyDrawing) { if (pvfb->root.legacyDrawing) {
renderer_update_root(pScreenPtr->width, pScreenPtr->height, ((PixmapPtr) pScreenPtr->devPrivate)->devPrivate.ptr); renderer_update_root(pScreenPtr->width, pScreenPtr->height, ((PixmapPtr) pScreenPtr->devPrivate)->devPrivate.ptr);
renderer_redraw(); renderer_redraw(pvfb->root.flip);
} }
return TRUE; return TRUE;
@ -714,7 +717,7 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv) {
screen_info->bitmapBitOrder = BITMAP_BIT_ORDER; screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
screen_info->numPixmapFormats = ARRAY_SIZE(depths); screen_info->numPixmapFormats = ARRAY_SIZE(depths);
renderer_init(); renderer_init(&pvfb->root.legacyDrawing, &pvfb->root.flip);
xorgGlxCreateVendor(); xorgGlxCreateVendor();
lorieInitSelectionCallback(); lorieInitSelectionCallback();

View File

@ -112,13 +112,17 @@ static const char vertex_shader[] =
" outTexCoords = texCoords;\n" " outTexCoords = texCoords;\n"
" gl_Position = position;\n" " gl_Position = position;\n"
"}\n"; "}\n";
static const char fragment_shader[] =
"precision mediump float;\n" #define FRAGMENT_SHADER(texture) \
"varying vec2 outTexCoords;\n" "precision mediump float;\n" \
"uniform sampler2D texture;\n" "varying vec2 outTexCoords;\n" \
"void main(void) {\n" "uniform sampler2D texture;\n" \
" gl_FragColor = texture2D(texture, outTexCoords);\n" "void main(void) {\n" \
"}\n"; " gl_FragColor = texture2D(texture, outTexCoords)" texture ";\n" \
"}\n"
static const char fragment_shader[] = FRAGMENT_SHADER();
static const char fragment_shader_bgra[] = FRAGMENT_SHADER(".bgra");
static EGLDisplay egl_display = EGL_NO_DISPLAY; static EGLDisplay egl_display = EGL_NO_DISPLAY;
static EGLContext ctx = EGL_NO_CONTEXT; static EGLContext ctx = EGL_NO_CONTEXT;
@ -139,8 +143,9 @@ static struct {
} cursor; } cursor;
GLuint g_texture_program = 0, gv_pos = 0, gv_coords = 0; GLuint g_texture_program = 0, gv_pos = 0, gv_coords = 0;
GLuint g_texture_program_bgra = 0, gv_pos_bgra = 0, gv_coords_bgra = 0;
int renderer_init(void) { int renderer_init(int* legacy_drawing, uint8_t* flip) {
EGLint major, minor; EGLint major, minor;
EGLint numConfigs; EGLint numConfigs;
const EGLint configAttribs[] = { const EGLint configAttribs[] = {
@ -208,6 +213,49 @@ int renderer_init(void) {
} }
eglCheckError(__LINE__); eglCheckError(__LINE__);
{
// Some devices do not support sampling from HAL_PIXEL_FORMAT_BGRA_8888, here we are checking it.
const EGLint imageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
EGLClientBuffer clientBuffer;
AHardwareBuffer *new = NULL;
int status;
AHardwareBuffer_Desc d0 = {
.width = 64,
.height = 64,
.layers = 1,
.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
.format = AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM
};
status = AHardwareBuffer_allocate(&d0, &new);
if (status != 0 || new == NULL) {
loge("Failed to allocate native buffer (%p, error %d)", new, status);
loge("Forcing legacy drawing");
*legacy_drawing = 1;
return 1;
}
clientBuffer = eglGetNativeClientBufferANDROID(new);
if (!clientBuffer) {
eglCheckError(__LINE__);
loge("Failed to obtain EGLClientBuffer from AHardwareBuffer");
loge("Forcing legacy drawing");
*legacy_drawing = 1;
return 1;
}
if (!eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttributes)) {
if (eglGetError() == EGL_BAD_PARAMETER) {
loge("Sampling from HAL_PIXEL_FORMAT_BGRA_8888 is not supported, forcing AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM");
*flip = 1;
} else {
loge("Failed to obtain EGLImageKHR from EGLClientBuffer");
loge("Forcing legacy drawing");
*legacy_drawing = 1;
}
}
}
return 1; return 1;
} }
@ -230,6 +278,7 @@ void renderer_set_buffer(AHardwareBuffer* buf) {
const EGLint imageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; const EGLint imageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
EGLClientBuffer clientBuffer; EGLClientBuffer clientBuffer;
AHardwareBuffer_Desc desc = {0}; AHardwareBuffer_Desc desc = {0};
uint8_t flip = 0;
if (eglGetCurrentContext() == EGL_NO_CONTEXT) { if (eglGetCurrentContext() == EGL_NO_CONTEXT) {
loge("There is no current context, `renderer_set_buffer` call is cancelled"); loge("There is no current context, `renderer_set_buffer` call is cancelled");
@ -258,11 +307,14 @@ void renderer_set_buffer(AHardwareBuffer* buf) {
loge("Failed to obtain EGLClientBuffer from AHardwareBuffer"); loge("Failed to obtain EGLClientBuffer from AHardwareBuffer");
} }
image = clientBuffer ? eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttributes) : NULL; image = clientBuffer ? eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttributes) : NULL;
if (image != NULL) if (image != NULL) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
else { flip = desc.format != AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM;
eglCheckError(__LINE__); } else {
loge("Binding AHardwareBuffer to an EGLImage failed."); if (clientBuffer) {
eglCheckError(__LINE__);
loge("Binding AHardwareBuffer to an EGLImage failed.");
}
display.width = 1; display.width = 1;
display.height = 1; display.height = 1;
@ -279,7 +331,7 @@ void renderer_set_buffer(AHardwareBuffer* buf) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data); checkGlError(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data); checkGlError();
} }
renderer_redraw(); renderer_redraw(flip);
log("renderer_set_buffer %p %d %d", buffer, desc.width, desc.height); log("renderer_set_buffer %p %d %d", buffer, desc.width, desc.height);
} }
@ -331,9 +383,19 @@ void renderer_set_window(EGLNativeWindowType window, AHardwareBuffer* new_buffer
return; return;
} }
g_texture_program_bgra = create_program(vertex_shader, fragment_shader_bgra);
if (!g_texture_program_bgra) {
log("Xlorie: GLESv2: Unable to create bgra shader program.\n");
eglCheckError(__LINE__);
return;
}
gv_pos = (GLuint) glGetAttribLocation(g_texture_program, "position"); checkGlError(); gv_pos = (GLuint) glGetAttribLocation(g_texture_program, "position"); checkGlError();
gv_coords = (GLuint) glGetAttribLocation(g_texture_program, "texCoords"); checkGlError(); gv_coords = (GLuint) glGetAttribLocation(g_texture_program, "texCoords"); checkGlError();
gv_pos_bgra = (GLuint) glGetAttribLocation(g_texture_program_bgra, "position"); checkGlError();
gv_coords_bgra = (GLuint) glGetAttribLocation(g_texture_program_bgra, "texCoords"); checkGlError();
glActiveTexture(GL_TEXTURE0); checkGlError(); glActiveTexture(GL_TEXTURE0); checkGlError();
glGenTextures(1, &display.id); checkGlError(); glGenTextures(1, &display.id); checkGlError();
glGenTextures(1, &cursor.id); checkGlError(); glGenTextures(1, &cursor.id); checkGlError();
@ -398,7 +460,7 @@ void renderer_set_cursor_coordinates(int x, int y) {
cursor.y = (float) y; cursor.y = (float) y;
} }
static void draw(GLuint id, float x0, float y0, float x1, float y1); static void draw(GLuint id, float x0, float y0, float x1, float y1, uint8_t flip);
static void draw_cursor(void); static void draw_cursor(void);
float ia = 0; float ia = 0;
@ -407,13 +469,13 @@ int renderer_should_redraw(void) {
return sfc != EGL_NO_SURFACE && eglGetCurrentContext() != EGL_NO_CONTEXT; return sfc != EGL_NO_SURFACE && eglGetCurrentContext() != EGL_NO_CONTEXT;
} }
int renderer_redraw(void) { int renderer_redraw(uint8_t flip) {
int err = EGL_SUCCESS; int err = EGL_SUCCESS;
if (!sfc || eglGetCurrentContext() == EGL_NO_CONTEXT) if (!sfc || eglGetCurrentContext() == EGL_NO_CONTEXT)
return FALSE; return FALSE;
draw(display.id, -1.f, -1.f, 1.f, 1.f); draw(display.id, -1.f, -1.f, 1.f, 1.f, flip);
draw_cursor(); draw_cursor();
if (eglSwapBuffers(egl_display, sfc) != EGL_TRUE) { if (eglSwapBuffers(egl_display, sfc) != EGL_TRUE) {
err = eglGetError(); err = eglGetError();
@ -496,7 +558,7 @@ static GLuint create_program(const char* p_vertex_source, const char* p_fragment
return program; return program;
} }
static void draw(GLuint id, float x0, float y0, float x1, float y1) { static void draw(GLuint id, float x0, float y0, float x1, float y1, uint8_t flip) {
float coords[20] = { float coords[20] = {
x0, -y0, 0.f, 0.f, 0.f, x0, -y0, 0.f, 0.f, 0.f,
x1, -y0, 0.f, 1.f, 0.f, x1, -y0, 0.f, 1.f, 0.f,
@ -504,14 +566,16 @@ static void draw(GLuint id, float x0, float y0, float x1, float y1) {
x1, -y1, 0.f, 1.f, 1.f, x1, -y1, 0.f, 1.f, 1.f,
}; };
GLuint p = flip ? gv_pos_bgra : gv_pos, c = flip ? gv_coords_bgra : gv_coords;
glActiveTexture(GL_TEXTURE0); checkGlError(); glActiveTexture(GL_TEXTURE0); checkGlError();
glUseProgram(g_texture_program); checkGlError(); glUseProgram(flip ? g_texture_program_bgra : g_texture_program); checkGlError();
glBindTexture(GL_TEXTURE_2D, id); checkGlError(); glBindTexture(GL_TEXTURE_2D, id); checkGlError();
glVertexAttribPointer(gv_pos, 3, GL_FLOAT, GL_FALSE, 20, coords); checkGlError(); glVertexAttribPointer(p, 3, GL_FLOAT, GL_FALSE, 20, coords); checkGlError();
glVertexAttribPointer(gv_coords, 2, GL_FLOAT, GL_FALSE, 20, &coords[3]); checkGlError(); glVertexAttribPointer(c, 2, GL_FLOAT, GL_FALSE, 20, &coords[3]); checkGlError();
glEnableVertexAttribArray(gv_pos); checkGlError(); glEnableVertexAttribArray(p); checkGlError();
glEnableVertexAttribArray(gv_coords); checkGlError(); glEnableVertexAttribArray(c); checkGlError();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGlError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGlError();
} }
@ -527,7 +591,7 @@ maybe_unused static void draw_cursor(void) {
h = 2.f * cursor.height / display.height; h = 2.f * cursor.height / display.height;
glEnable(GL_BLEND); checkGlError(); glEnable(GL_BLEND); checkGlError();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); checkGlError(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); checkGlError();
draw(cursor.id, x, y, x + w, y + h); draw(cursor.id, x, y, x + w, y + h, false);
glDisable(GL_BLEND); checkGlError(); glDisable(GL_BLEND); checkGlError();
} }

View File

@ -12,13 +12,15 @@
typedef void (*renderer_message_func_type) (int type, int verb, const char *format, ...); typedef void (*renderer_message_func_type) (int type, int verb, const char *format, ...);
maybe_unused void renderer_message_func(renderer_message_func_type function); maybe_unused void renderer_message_func(renderer_message_func_type function);
maybe_unused int renderer_init(void); maybe_unused int renderer_init(int* legacy_drawing, uint8_t* flip);
maybe_unused void renderer_set_buffer(AHardwareBuffer* buffer); maybe_unused void renderer_set_buffer(AHardwareBuffer* buffer);
maybe_unused void renderer_set_window(struct ANativeWindow* native_window, AHardwareBuffer* buffer); maybe_unused void renderer_set_window(struct ANativeWindow* native_window, AHardwareBuffer* buffer);
maybe_unused int renderer_should_redraw(void); maybe_unused int renderer_should_redraw(void);
maybe_unused int renderer_redraw(void); maybe_unused int renderer_redraw(uint8_t flip);
maybe_unused void renderer_print_fps(float millis); maybe_unused void renderer_print_fps(float millis);
maybe_unused void renderer_update_root(int w, int h, void* data); maybe_unused void renderer_update_root(int w, int h, void* data);
maybe_unused void renderer_update_cursor(int w, int h, int xhot, int yhot, void* data); maybe_unused void renderer_update_cursor(int w, int h, int xhot, int yhot, void* data);
maybe_unused void renderer_set_cursor_coordinates(int x, int y); maybe_unused void renderer_set_cursor_coordinates(int x, int y);
#define AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM 5 // Stands to HAL_PIXEL_FORMAT_BGRA_8888

View File

@ -463,7 +463,7 @@ public class MainActivity extends AppCompatActivity implements View.OnApplyWindo
return; return;
try { try {
Log.v("LorieBroadcastReceiver", "Extracting X connection socket."); Log.v("LorieBroadcastReceiver", "Extracting X connection socket.");
ParcelFileDescriptor fd = service.getXConnection(); ParcelFileDescriptor fd = service == null ? null : service.getXConnection();
if (fd != null) { if (fd != null) {
LorieView.connect(fd.detachFd()); LorieView.connect(fd.detachFd());
getLorieView().triggerCallback(); getLorieView().triggerCallback();