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:
@@ -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
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user