llvmpipe: Add android platform integration

Allow llvmpipe to run on Android without any drm device present.
Previously llvmpipe would only run with kms_swrast, still requiring
a drm device driver to be present for the display.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344>
This commit is contained in:
Lucas Fryzek
2024-04-23 16:06:13 -04:00
committed by Marge Bot
parent 4009709bc3
commit df96cac2cf
3 changed files with 220 additions and 47 deletions

View File

@@ -308,6 +308,7 @@ struct dri2_egl_display {
/* gralloc vendor usage bit for front rendering */
uint32_t front_rendering_usage;
bool has_native_fence_fd;
bool pure_swrast;
#endif
};

View File

@@ -337,7 +337,8 @@ droid_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
&dri2_surf->base.Height);
dri2_surf->gralloc_usage =
strcmp(dri2_dpy->driver_name, "kms_swrast") == 0
((strcmp(dri2_dpy->driver_name, "kms_swrast") == 0) ||
(strcmp(dri2_dpy->driver_name, "swrast") == 0))
? GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN
: GRALLOC_USAGE_HW_RENDER;
@@ -616,6 +617,7 @@ droid_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
static EGLBoolean
droid_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
const bool has_mutable_rb = _eglSurfaceHasMutableRenderBuffer(draw);
@@ -645,16 +647,22 @@ droid_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
dri2_flush_drawable_for_swapbuffers_flags(disp, draw,
__DRI2_NOTHROTTLE_SWAPBUFFER);
/* dri2_surf->buffer can be null even when no error has occurred. For
* example, if the user has called no GL rendering commands since the
* previous eglSwapBuffers, then the driver may have not triggered
* a callback to ANativeWindow_dequeueBuffer, in which case
* dri2_surf->buffer remains null.
*/
if (dri2_surf->buffer)
droid_window_enqueue_buffer(disp, dri2_surf);
if (dri2_dpy->pure_swrast) {
driSwapBuffers(dri2_surf->dri_drawable);
if (dri2_surf->buffer)
droid_window_enqueue_buffer(disp, dri2_surf);
} else {
/* dri2_surf->buffer can be null even when no error has occurred. For
* example, if the user has called no GL rendering commands since the
* previous eglSwapBuffers, then the driver may have not triggered
* a callback to ANativeWindow_dequeueBuffer, in which case
* dri2_surf->buffer remains null.
*/
if (dri2_surf->buffer)
droid_window_enqueue_buffer(disp, dri2_surf);
dri_invalidate_drawable(dri2_surf->dri_drawable);
dri_invalidate_drawable(dri2_surf->dri_drawable);
}
/* Update the shared buffer mode */
if (has_mutable_rb &&
@@ -944,6 +952,51 @@ droid_display_shared_buffer(__DRIdrawable *driDrawable, int fence_fd,
handle_in_fence_fd(dri2_surf, dri2_surf->dri_image_back);
}
static void
droid_swrast_get_drawable_info(__DRIdrawable *drawable,
int *x, int *y, int *width, int *height,
void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
update_buffers(dri2_surf);
*x = 0;
*y = 0;
*width = dri2_surf->base.Width;
*height = dri2_surf->base.Height;
}
static void
droid_swrast_put_image2(__DRIdrawable *draw, int op, int x, int y, int w,
int h, int stride, char *data, void *loaderPrivate)
{
return;
}
static void
droid_swrast_put_image(__DRIdrawable *draw, int op, int x, int y, int w,
int h, char *data, void *loaderPrivate)
{
return;
}
static void
droid_swrast_get_image(__DRIdrawable *read, int x, int y, int w, int h,
char *data, void *loaderPrivate)
{
return;
}
static const __DRIswrastLoaderExtension swrast_loader_extension = {
.base = {__DRI_SWRAST_LOADER, 2},
.getDrawableInfo = droid_swrast_get_drawable_info,
.putImage = droid_swrast_put_image,
.getImage = droid_swrast_get_image,
.putImage2 = droid_swrast_put_image2,
};
static const __DRImutableRenderBufferLoaderExtension
droid_mutable_render_buffer_extension = {
.base = {__DRI_MUTABLE_RENDER_BUFFER_LOADER, 1},
@@ -958,6 +1011,15 @@ static const __DRIextension *droid_image_loader_extensions[] = {
NULL,
};
static const __DRIextension *droid_swrast_image_loader_extensions[] = {
&droid_image_loader_extension.base,
&image_lookup_extension.base,
&use_invalidate.base,
&droid_mutable_render_buffer_extension.base,
&swrast_loader_extension.base,
NULL,
};
static EGLBoolean
droid_load_driver(_EGLDisplay *disp, bool swrast)
{
@@ -1137,8 +1199,30 @@ dri2_initialize_android(_EGLDisplay *disp)
goto cleanup;
}
bool force_pure_swrast = debug_get_bool_option("MESA_ANDROID_NO_KMS_SWRAST", false);
disp->DriverData = (void *)dri2_dpy;
device_opened = droid_open_device(disp, disp->Options.ForceSoftware);
if (!force_pure_swrast)
device_opened = droid_open_device(disp, disp->Options.ForceSoftware);
if ((!device_opened && disp->Options.ForceSoftware) ||
force_pure_swrast) {
dri2_dpy->driver_name = strdup("swrast");
dri2_dpy->loader_extensions = droid_swrast_image_loader_extensions;
dri2_dpy->fd_render_gpu = -1;
dri2_dpy->pure_swrast = true;
if(!dri2_load_driver(disp)) {
err = "DRI2: Failed to load swrast";
goto cleanup;
}
if (!dri2_create_screen(disp)) {
err = "DRI2: Failed to create swrast screen";
goto cleanup;
}
device_opened = EGL_TRUE;
}
if (!device_opened) {
err = "DRI2: failed to open device";
@@ -1147,7 +1231,7 @@ dri2_initialize_android(_EGLDisplay *disp)
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
if (!dri2_setup_device(disp, false)) {
if (!dri2_dpy->pure_swrast && !dri2_setup_device(disp, false)) {
err = "DRI2: failed to setup EGLDevice";
goto cleanup;
}

View File

@@ -43,6 +43,8 @@
#include "dri_helpers.h"
#include "dri_query_renderer.h"
#include "util/libsync.h"
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#endif
@@ -365,6 +367,33 @@ drisw_flush_frontbuffer(struct dri_context *ctx,
return true;
}
extern bool
dri_image_drawable_get_buffers(struct dri_drawable *drawable,
struct __DRIimageList *images,
const enum st_attachment_type *statts,
unsigned statts_count);
static void
handle_in_fence(struct dri_context *ctx, __DRIimage *img)
{
struct pipe_context *pipe = ctx->st->pipe;
struct pipe_fence_handle *fence;
int fd = img->in_fence_fd;
if (fd == -1)
return;
validate_fence_fd(fd);
img->in_fence_fd = -1;
pipe->create_fence_fd(pipe, &fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
pipe->fence_server_sync(pipe, fence);
pipe->screen->fence_reference(pipe->screen, &fence, NULL);
close(fd);
}
/**
* Allocate framebuffer attachments.
*
@@ -384,12 +413,22 @@ drisw_allocate_textures(struct dri_context *stctx,
unsigned width, height;
bool resized;
unsigned i;
const __DRIimageLoaderExtension *image = screen->image.loader;
struct __DRIimageList images;
bool imported_buffers = true;
/* Wait for glthread to finish because we can't use pipe_context from
* multiple threads.
*/
_mesa_glthread_finish(stctx->st->ctx);
/* First try to get the buffers from the loader */
if (image) {
if (!dri_image_drawable_get_buffers(drawable, &images,
statts, count))
imported_buffers = false;
}
width = drawable->w;
height = drawable->h;
@@ -413,48 +452,92 @@ drisw_allocate_textures(struct dri_context *stctx,
templ.array_size = 1;
templ.last_level = 0;
for (i = 0; i < count; i++) {
enum pipe_format format;
unsigned bind;
if (imported_buffers && image) {
if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
struct pipe_resource **buf =
&drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
struct pipe_resource *texture = images.front->texture;
/* the texture already exists or not requested */
if (drawable->textures[statts[i]])
continue;
drawable->w = texture->width0;
drawable->h = texture->height0;
dri_drawable_get_format(drawable, statts[i], &format, &bind);
pipe_resource_reference(buf, texture);
handle_in_fence(stctx, images.front);
}
/* if we don't do any present, no need for display targets */
if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !screen->swrast_no_present)
bind |= PIPE_BIND_DISPLAY_TARGET;
if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
struct pipe_resource **buf =
&drawable->textures[ST_ATTACHMENT_BACK_LEFT];
struct pipe_resource *texture = images.back->texture;
if (format == PIPE_FORMAT_NONE)
continue;
drawable->w = texture->width0;
drawable->h = texture->height0;
templ.format = format;
templ.bind = bind;
templ.nr_samples = 0;
templ.nr_storage_samples = 0;
pipe_resource_reference(buf, texture);
handle_in_fence(stctx, images.back);
}
if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
screen->base.screen->resource_create_front &&
loader->base.version >= 3) {
drawable->textures[statts[i]] =
screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
} else
drawable->textures[statts[i]] =
screen->base.screen->resource_create(screen->base.screen, &templ);
if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
struct pipe_resource **buf =
&drawable->textures[ST_ATTACHMENT_BACK_LEFT];
struct pipe_resource *texture = images.back->texture;
if (drawable->stvis.samples > 1) {
templ.bind = templ.bind &
~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET);
templ.nr_samples = drawable->stvis.samples;
templ.nr_storage_samples = drawable->stvis.samples;
drawable->msaa_textures[statts[i]] =
screen->base.screen->resource_create(screen->base.screen, &templ);
drawable->w = texture->width0;
drawable->h = texture->height0;
dri_pipe_blit(stctx->st->pipe,
drawable->msaa_textures[statts[i]],
drawable->textures[statts[i]]);
pipe_resource_reference(buf, texture);
handle_in_fence(stctx, images.back);
}
/* Note: if there is both a back and a front buffer,
* then they have the same size.
*/
templ.width0 = drawable->w;
templ.height0 = drawable->h;
} else {
for (i = 0; i < count; i++) {
enum pipe_format format;
unsigned bind;
/* the texture already exists or not requested */
if (drawable->textures[statts[i]])
continue;
dri_drawable_get_format(drawable, statts[i], &format, &bind);
/* if we don't do any present, no need for display targets */
if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !screen->swrast_no_present)
bind |= PIPE_BIND_DISPLAY_TARGET;
if (format == PIPE_FORMAT_NONE)
continue;
templ.format = format;
templ.bind = bind;
templ.nr_samples = 0;
templ.nr_storage_samples = 0;
if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
screen->base.screen->resource_create_front &&
loader->base.version >= 3) {
drawable->textures[statts[i]] =
screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
} else
drawable->textures[statts[i]] =
screen->base.screen->resource_create(screen->base.screen, &templ);
if (drawable->stvis.samples > 1) {
templ.bind = templ.bind &
~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET);
templ.nr_samples = drawable->stvis.samples;
templ.nr_storage_samples = drawable->stvis.samples;
drawable->msaa_textures[statts[i]] =
screen->base.screen->resource_create(screen->base.screen, &templ);
dri_pipe_blit(stctx->st->pipe,
drawable->msaa_textures[statts[i]],
drawable->textures[statts[i]]);
}
}
}
@@ -614,9 +697,14 @@ drisw_init_screen(struct dri_screen *screen, bool driver_name_is_inferred)
}
else
screen->extensions = drisw_screen_extensions;
#ifdef HAVE_LIBDRM
if (pscreen->resource_create_with_modifiers && (pscreen->get_param(pscreen, PIPE_CAP_DMABUF) & DRM_PRIME_CAP_EXPORT))
int dmabuf_cap = pscreen->get_param(pscreen, PIPE_CAP_DMABUF);
if (pscreen->resource_create_with_modifiers && (dmabuf_cap & DRM_PRIME_CAP_EXPORT))
screen->extensions[0] = &driVkImageExtension.base;
else if (pscreen->resource_create_with_modifiers && dmabuf_cap) {
driSWImageExtension.createImageFromDmaBufs = driVkImageExtension.createImageFromDmaBufs;
}
#endif
screen->create_drawable = drisw_create_drawable;