[Mesa-dev] [PATCH 8/8] android: egl: add support for software rasterizer

Mauro Rossi issor.oruam at gmail.com
Mon May 1 15:05:07 UTC 2017


+ Karl

2017-05-01 17:02 GMT+02:00 Mauro Rossi <issor.oruam at gmail.com>:

>
>
> 2017-01-06 18:35 GMT+01:00 Wu Zhen <wuzhen at jidemail.com>:
>
>> From: WuZhen <wuzhen at jidemail.com>
>>
>> this commit enable software rendering on android with llvmpipe.
>> the system boots fine antutu 3D benchmark is passing
>>
>> this commit incorporates some further work done by:
>> Paulo Sergio Travaglia <pstglia at gmail.com>
>> Mauro Rossi <issor.oruam at gmail.com>
>>
>> Change-Id: Ibe0114333a278fd5e64632ac8c17cffde7c9b359
>> Reviewed-by: Mauro Rossi <issor.oruam at gmail.com>
>> Reviewed-by: Chih-Wei Huang <cwhuang at linux.org.tw>
>> ---
>>  src/egl/Android.mk                      |   1 +
>>  src/egl/drivers/dri2/egl_dri2.c         |   1 +
>>  src/egl/drivers/dri2/platform_android.c | 389
>> +++++++++++++++++++++++++++++++-
>>  3 files changed, 386 insertions(+), 5 deletions(-)
>>
>> diff --git a/src/egl/Android.mk b/src/egl/Android.mk
>> index bfd56a744d..d63e71da92 100644
>> --- a/src/egl/Android.mk
>> +++ b/src/egl/Android.mk
>> @@ -46,6 +46,7 @@ LOCAL_CFLAGS := \
>>  LOCAL_C_INCLUDES := \
>>         $(MESA_TOP)/src/egl/main \
>>         $(MESA_TOP)/src/egl/drivers/dri2 \
>> +       $(MESA_TOP)/src/gallium/include
>>
>>  LOCAL_STATIC_LIBRARIES := \
>>         libmesa_loader
>> diff --git a/src/egl/drivers/dri2/egl_dri2.c
>> b/src/egl/drivers/dri2/egl_dri2.c
>> index 52fbdff0b1..bdb3119496 100644
>> --- a/src/egl/drivers/dri2/egl_dri2.c
>> +++ b/src/egl/drivers/dri2/egl_dri2.c
>> @@ -402,6 +402,7 @@ static const struct dri2_extension_match
>> swrast_driver_extensions[] = {
>>
>>  static const struct dri2_extension_match swrast_core_extensions[] = {
>>     { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer)
>> },
>> +   { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
>>     { NULL, 0, 0 }
>>  };
>>
>> diff --git a/src/egl/drivers/dri2/platform_android.c
>> b/src/egl/drivers/dri2/platform_android.c
>> index 1c880f934a..61c0aa4818 100644
>> --- a/src/egl/drivers/dri2/platform_android.c
>> +++ b/src/egl/drivers/dri2/platform_android.c
>> @@ -40,6 +40,7 @@
>>  #include "loader.h"
>>  #include "egl_dri2.h"
>>  #include "egl_dri2_fallbacks.h"
>> +#include "state_tracker/drm_driver.h"
>>  #include "gralloc_drm.h"
>>
>>  #define ALIGN(val, align)      (((val) + (align) - 1) & ~((align) - 1))
>> @@ -157,6 +158,8 @@ get_native_buffer_name(struct ANativeWindowBuffer
>> *buf)
>>     return gralloc_drm_get_gem_handle(buf->handle);
>>  }
>>
>> +static const gralloc_module_t *gr_module = NULL;
>> +
>>  static EGLBoolean
>>  droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
>>  {
>> @@ -338,9 +341,14 @@ droid_create_surface(_EGLDriver *drv, _EGLDisplay
>> *disp, EGLint type,
>>     if (!config)
>>        goto cleanup_surface;
>>
>> -   dri2_surf->dri_drawable =
>> -      (*dri2_dpy->dri2->createNewDrawable)(dri2_dpy->dri_screen, config,
>> -                                           dri2_surf);
>> +   if (dri2_dpy->dri2) {
>> +      dri2_surf->dri_drawable =
>> +         dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen,
>> config, dri2_surf);
>> +   } else {
>> +      dri2_surf->dri_drawable =
>> +         dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen,
>> config, dri2_surf);
>> +   }
>> +
>>     if (dri2_surf->dri_drawable == NULL) {
>>        _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
>>        goto cleanup_surface;
>> @@ -980,6 +988,259 @@ droid_add_configs_for_visuals(_EGLDriver *drv,
>> _EGLDisplay *dpy)
>>     return (count != 0);
>>  }
>>
>> +static int swrastUpdateBuffer(struct dri2_egl_surface *dri2_surf)
>> +{
>> +   if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
>> +       if (!dri2_surf->buffer && !droid_window_dequeue_buffer(dri2_surf))
>> {
>> +          _eglLog(_EGL_WARNING, "failed to dequeue buffer for window");
>> +          return 1;
>> +       }
>> +       dri2_surf->base.Width = dri2_surf->buffer->width;
>> +       dri2_surf->base.Height = dri2_surf->buffer->height;
>> +   }
>> +   return 0;
>> +}
>> +
>> +static void
>> +swrastGetDrawableInfo(__DRIdrawable * draw,
>> +                      int *x, int *y, int *w, int *h,
>> +                      void *loaderPrivate)
>> +{
>> +   struct dri2_egl_surface *dri2_surf = loaderPrivate;
>> +
>> +   swrastUpdateBuffer(dri2_surf);
>> +
>> +   *x = 0;
>> +   *y = 0;
>> +   *w = dri2_surf->base.Width;
>> +   *h = dri2_surf->base.Height;
>> +}
>> +
>> +static void
>> +swrastPutImage2(__DRIdrawable * draw, int op,
>> +                int x, int y, int w, int h, int stride,
>> +                char *data, void *loaderPrivate)
>> +{
>> +   struct dri2_egl_surface *dri2_surf = loaderPrivate;
>> +   struct _EGLDisplay *egl_dpy = dri2_surf->base.Resource.Display;
>> +   char *dstPtr, *srcPtr;
>> +   size_t BPerPixel, dstStride, copyWidth, xOffset;
>> +
>> +   if (swrastUpdateBuffer(dri2_surf)) {
>> +      return;
>> +   }
>> +
>> +   BPerPixel = get_format_bpp(dri2_surf->buffer->format);
>> +   dstStride = BPerPixel * dri2_surf->buffer->stride;
>> +   copyWidth = BPerPixel * w;
>> +   xOffset = BPerPixel * x;
>> +
>> +   /* drivers expect we do these checks (and some rely on it) */
>> +   if (copyWidth > dstStride - xOffset)
>> +      copyWidth = dstStride - xOffset;
>> +   if (h > dri2_surf->base.Height - y)
>> +      h = dri2_surf->base.Height - y;
>> +
>> +   if (gr_module->lock(gr_module, dri2_surf->buffer->handle,
>> GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
>> +                       0, 0, dri2_surf->buffer->width,
>> dri2_surf->buffer->height, (void**)&dstPtr)) {
>> +      _eglLog(_EGL_WARNING, "can not lock window buffer");
>> +      return;
>> +   }
>> +
>> +   dstPtr += y * dstStride + xOffset;
>> +   srcPtr = data;
>> +
>> +   if (xOffset == 0 && copyWidth == stride && copyWidth == dstStride) {
>> +      memcpy(dstPtr, srcPtr, copyWidth * h);
>> +   } else {
>> +      for (; h>0; h--) {
>> +         memcpy(dstPtr, srcPtr, copyWidth);
>> +         srcPtr += stride;
>> +         dstPtr += dstStride;
>> +      }
>> +   }
>> +
>> +   if (gr_module->unlock(gr_module, dri2_surf->buffer->handle)) {
>> +      _eglLog(_EGL_WARNING, "unlock buffer failed");
>> +   }
>> +
>> +   droid_window_enqueue_buffer(egl_dpy, dri2_surf);
>> +}
>> +
>> +static void
>> +swrastPutImage(__DRIdrawable * draw, int op,
>> +              int x, int y, int w, int h,
>> +              char *data, void *loaderPrivate)
>> +{
>> +   struct dri2_egl_surface *dri2_surf = loaderPrivate;
>> +   int stride;
>> +
>> +   if (swrastUpdateBuffer(dri2_surf)) {
>> +      return;
>> +   }
>> +
>> +   stride = get_format_bpp(dri2_surf->buffer->format) * w;
>> +   swrastPutImage2(draw, op, x, y, w, h, stride, data, loaderPrivate);
>> +}
>> +
>> +static void
>> +swrastGetImage(__DRIdrawable * read,
>> +               int x, int y, int w, int h,
>> +               char *data, void *loaderPrivate)
>> +{
>> +   struct dri2_egl_surface *dri2_surf = loaderPrivate;
>> +   size_t BPerPixel, srcStride, copyWidth, xOffset;
>> +   char *dstPtr, *srcPtr;
>> +
>> +   _eglLog(_EGL_WARNING, "calling swrastGetImage with read=%p,
>> private=%p, w=%d, h=%d", read, loaderPrivate, w, h);
>> +
>> +   if (swrastUpdateBuffer(dri2_surf)) {
>> +      _eglLog(_EGL_WARNING, "swrastGetImage failed data unchanged");
>> +      return;
>> +   }
>> +
>> +   BPerPixel = get_format_bpp(dri2_surf->buffer->format);
>> +   srcStride = BPerPixel * dri2_surf->buffer->stride;
>> +   copyWidth = BPerPixel * w;
>> +   xOffset = BPerPixel * x;
>> +
>> +   if (gr_module->lock(gr_module, dri2_surf->buffer->handle,
>> GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
>> +                       0, 0, dri2_surf->buffer->width,
>> dri2_surf->buffer->height, (void**)&srcPtr)) {
>> +      _eglLog(_EGL_WARNING, "can not lock window buffer");
>> +      memset(data, 0, copyWidth * h);
>> +      return;
>> +   }
>> +
>> +   srcPtr += y * srcStride + xOffset;
>> +   dstPtr = data;
>> +
>> +   if (xOffset == 0 && copyWidth == srcStride) {
>> +      memcpy(dstPtr, srcPtr, copyWidth * h);
>> +   } else {
>> +      for (; h>0; h--) {
>> +         memcpy(dstPtr, srcPtr, copyWidth);
>> +         srcPtr += srcStride;
>> +         dstPtr += copyWidth;
>> +      }
>> +   }
>> +
>> +   if (gr_module->unlock(gr_module, dri2_surf->buffer->handle)) {
>> +      _eglLog(_EGL_WARNING, "unlock buffer failed");
>> +   }
>> +}
>> +
>> +static EGLBoolean
>> +swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface
>> *draw)
>> +{
>> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
>> +   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
>> +
>> +   dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
>> +
>> +   return EGL_TRUE;
>> +}
>> +
>> +static _EGLImage *
>> +swrast_create_image_android_native_buffer(_EGLDisplay *disp,
>> _EGLContext *ctx,
>> +                                          struct ANativeWindowBuffer
>> *buf)
>> +{
>> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
>> +   struct dri2_egl_image *dri2_img;
>> +   struct winsys_handle whandle;
>> +   EGLint format;
>> +
>> +   if (ctx != NULL) {
>> +      /* From the EGL_ANDROID_image_native_buffer spec:
>> +       *
>> +       *     * If <target> is EGL_NATIVE_BUFFER_ANDROID and <ctx> is not
>> +       *       EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated.
>> +       */
>> +      _eglError(EGL_BAD_CONTEXT, "eglCreateEGLImageKHR: for "
>> +                "EGL_NATIVE_BUFFER_ANDROID, the context must be "
>> +                "EGL_NO_CONTEXT");
>> +      return NULL;
>> +   }
>> +
>> +   if (!buf || buf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC ||
>> +       buf->common.version != sizeof(*buf)) {
>> +      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
>> +      return NULL;
>> +   }
>> +
>> +   /* see the table in droid_add_configs_for_visuals */
>> +   format = get_format(buf->format);
>> +   if (format < 0)
>> +      return NULL;
>> +
>> +   dri2_img = calloc(1, sizeof(*dri2_img));
>> +   if (!dri2_img) {
>> +      _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm");
>> +      return NULL;
>> +   }
>> +
>> +   if (!_eglInitImage(&dri2_img->base, disp)) {
>> +      free(dri2_img);
>> +      return NULL;
>> +   }
>> +
>> +   memset(&whandle, 0, sizeof(whandle));
>> +   whandle.type = DRM_API_HANDLE_TYPE_BUFFER;
>> +   whandle.external_buffer = buf;
>> +   whandle.stride = buf->stride * get_format_bpp(buf->format);
>> +
>> +   dri2_img->dri_image =
>> +         dri2_dpy->swrast->createImageFromWinsys(dri2_dpy->dri_screen,
>> +                                                 buf->width,
>> +                                                 buf->height,
>> +                                                 format,
>> +                                                 1, &whandle,
>> +                                                 dri2_img);
>> +
>> +   if (!dri2_img->dri_image) {
>> +      free(dri2_img);
>> +      _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm");
>> +      return NULL;
>> +   }
>> +
>> +   return &dri2_img->base;
>> +}
>> +
>> +static _EGLImage *
>> +swrast_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
>> +                        _EGLContext *ctx, EGLenum target,
>> +                        EGLClientBuffer buffer, const EGLint *attr_list)
>> +{
>> +   switch (target) {
>> +   case EGL_NATIVE_BUFFER_ANDROID:
>> +      return swrast_create_image_android_native_buffer(disp, ctx,
>> +            (struct ANativeWindowBuffer *) buffer);
>> +   default:
>> +      return dri2_create_image_khr(drv, disp, ctx, target, buffer,
>> attr_list);
>> +   }
>> +}
>> +
>> +static int
>> +load_gralloc(void)
>> +{
>> +   const hw_module_t *mod;
>> +   int err;
>> +
>> +   err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod);
>> +   if (!err) {
>> +      gr_module = (gralloc_module_t *) mod;
>> +   } else {
>> +      _eglLog(_EGL_WARNING, "fail to load gralloc");
>> +   }
>> +   return err;
>> +}
>> +
>> +static int
>> +is_drm_gralloc(void)
>> +{
>> +   /* need a cleaner way to distinguish drm_gralloc and gralloc.default
>> */
>> +   return !!gr_module->perform;
>> +}
>> +
>>  static int
>>  droid_open_device(struct dri2_egl_display *dri2_dpy)
>>  {
>> @@ -1064,6 +1325,15 @@ static const __DRIimageLoaderExtension
>> droid_image_loader_extension = {
>>     .flushFrontBuffer    = droid_flush_front_buffer,
>>  };
>>
>> +static const __DRIswrastLoaderExtension droid_swrast_loader_extension = {
>> +   .base = { __DRI_SWRAST_LOADER, 2 },
>> +
>> +   .getDrawableInfo     = swrastGetDrawableInfo,
>> +   .putImage            = swrastPutImage,
>> +   .getImage            = swrastGetImage,
>> +   .putImage2           = swrastPutImage2,
>> +};
>> +
>>  static const __DRIextension *droid_dri2_loader_extensions[] = {
>>     &droid_dri2_loader_extension.base,
>>     &image_lookup_extension.base,
>> @@ -1078,8 +1348,14 @@ static const __DRIextension
>> *droid_image_loader_extensions[] = {
>>     NULL,
>>  };
>>
>> -EGLBoolean
>> -dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy)
>> +static const __DRIextension *droid_swrast_loader_extensions[] = {
>> +   &droid_swrast_loader_extension.base,
>> +   &image_lookup_extension.base,
>> +   NULL,
>> +};
>> +
>> +static EGLBoolean
>> +dri2_initialize_android_drm(_EGLDriver *drv, _EGLDisplay *dpy)
>>  {
>>     struct dri2_egl_display *dri2_dpy;
>>     const char *err;
>> @@ -1163,3 +1439,106 @@ cleanup_display:
>>
>>     return _eglError(EGL_NOT_INITIALIZED, err);
>>  }
>> +
>> +/* differs with droid_display_vtbl in create_image, swap_buffers */
>> +static struct dri2_egl_display_vtbl swrast_display_vtbl = {
>> +    .authenticate = NULL,
>> +    .create_window_surface = droid_create_window_surface,
>> +    .create_pixmap_surface = dri2_fallback_create_pixmap_surface,
>> +    .create_pbuffer_surface = droid_create_pbuffer_surface,
>> +    .destroy_surface = droid_destroy_surface,
>> +    .create_image = swrast_create_image_khr,
>> +    .swap_interval = dri2_fallback_swap_interval,
>> +    .swap_buffers = swrast_swap_buffers,
>> +    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
>> +    .swap_buffers_region = dri2_fallback_swap_buffers_region,
>> +    .post_sub_buffer = dri2_fallback_post_sub_buffer,
>> +    .copy_buffers = dri2_fallback_copy_buffers,
>> +    .query_buffer_age = dri2_fallback_query_buffer_age,
>> +    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_b
>> uffer_from_image,
>> +    .get_sync_values = dri2_fallback_get_sync_values,
>> +    .get_dri_drawable = dri2_surface_get_dri_drawable,
>> +};
>> +
>> +static EGLBoolean
>> +dri2_initialize_android_swrast(_EGLDriver *drv, _EGLDisplay *dpy)
>> +{
>> +   struct dri2_egl_display *dri2_dpy;
>> +   const char *err = "";
>> +   const hw_module_t *mod;
>> +
>> +   _eglSetLogProc(droid_log);
>> +
>> +   loader_set_logger(_eglLog);
>> +
>> +   dri2_dpy = calloc(1, sizeof(*dri2_dpy));
>> +   if (!dri2_dpy)
>> +      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
>> +
>> +   dpy->DriverData = (void *) dri2_dpy;
>> +
>> +   dri2_dpy->driver_name = strdup("swrast");
>> +   if (!dri2_load_driver_swrast(dpy)) {
>> +      err = "DRISW: failed to load swrast driver";
>> +      goto cleanup_driver_name;
>> +   }
>> +
>> +   dri2_dpy->loader_extensions = droid_swrast_loader_extensions;
>> +
>> +   if (!dri2_create_screen(dpy)) {
>> +      err = "DRISW: failed to create screen";
>> +      goto cleanup_driver;
>> +   }
>> +
>> +   if (!droid_add_configs_for_visuals(drv, dpy)) {
>> +      err = "DRISW: failed to add configs";
>> +      goto cleanup_screen;
>> +   }
>> +
>> +   dpy->Extensions.ANDROID_framebuffer_target = EGL_TRUE;
>> +   dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE;
>> +   dpy->Extensions.ANDROID_recordable = EGL_TRUE;
>> +   dpy->Extensions.KHR_image_base = EGL_TRUE;
>> +
>> +   /* Fill vtbl last to prevent accidentally calling virtual function
>> during
>> +    * initialization.
>> +    */
>> +   dri2_dpy->vtbl = &swrast_display_vtbl;
>> +
>> +   return EGL_TRUE;
>> +
>> +cleanup_screen:
>> +   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
>> +cleanup_driver:
>> +   dlclose(dri2_dpy->driver);
>> +cleanup_driver_name:
>> +   free(dri2_dpy->driver_name);
>> +   free(dri2_dpy);
>> +
>> +   return _eglError(EGL_NOT_INITIALIZED, err);
>> +}
>> +
>> +EGLBoolean
>> +dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy)
>> +{
>> +   EGLBoolean initialized = EGL_TRUE;
>> +
>> +   if (load_gralloc()) {
>> +      return EGL_FALSE;
>> +   }
>> +
>> +   int droid_hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL) &&
>> is_drm_gralloc();
>> +
>> +   if (droid_hw_accel) {
>> +      if (!dri2_initialize_android_drm(drv, dpy)) {
>> +         initialized = dri2_initialize_android_swrast(drv, dpy);
>> +         if (initialized) {
>> +            _eglLog(_EGL_INFO, "Android: Fallback to software renderer");
>> +         }
>> +      }
>> +   } else {
>> +      initialized = dri2_initialize_android_swrast(drv, dpy);
>> +   }
>> +
>> +   return initialized;
>> +}
>> --
>> 2.11.0
>>
>
> Hi Emil, Tomasz, Tapani, Karl,
>
> comparing this series with other swrast implementations in CrOS,
> Android-IA,
> are there other android platform swrast implementations? [Tomasz, Tapani
> if the question does makes sense]
>
> I had checked in other platforms (drm, EGL wayland)
> but in the past I had found no changes in backbuffer
> handling/swapBuffer/PutImage2,
> do you know and could explain me the reason? [Emil if you know, but do not
> use time if it requires research]
>
> I also wanted to check if situation may have changed since January 2017,
> because of swr and other patches in gallium/swrast submitted to mesa-dev
> like [1], [2], [3], [4]
> which seem to tackle with functional needs in backbuffer/image2 and
> swapbuffer area,
> even if addressed in winsys instead of EGL platform android. [Karl a brief
> update will suffice, no hurry]
>
> Are there news or consolidated choices about the implementation approach?
> [` Emil or others]
> Thanks for sharing you thoughts
>
> Mauro
>
> [1] https://lists.freedesktop.org/archives/mesa-dev/2017-
> January/141614.html
>
> [2] https://lists.freedesktop.org/archives/mesa-dev/2017-
> January/141621.html
>
> [3] https://lists.freedesktop.org/archives/mesa-dev/2017-
> January/141616.html
>
> [4] https://lists.freedesktop.org/archives/mesa-dev/2017-
> January/141624.html
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170501/bba8a00f/attachment-0001.html>


More information about the mesa-dev mailing list