Android / Etnaviv / i.MX6 update
Martin Fuzzey
martin.fuzzey at flowbird.group
Tue Jul 31 09:02:13 UTC 2018
On 27/07/18 16:02, Shawn Guo wrote:
> Hi Martin,
>
> I'm very interested in running i.MX6 Etnaviv with Android. Can you
> please share what you have done for getting it up running? Thanks.
>
> Shawn
Hi Shawn,
sure, here is my complete stack for reference:
======================================
Kernel 4.14
======================================
With this hack:
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-26 15:37:28 +0200
Make imx-drm export a render node so that mesa can use it to allocate dumb memory rather than requiring the master node.
The problem with using the master node is that, on android 8.1, drm_hwcomposer
is a seperate process and must be the master node (to use the KMS API),
since only a single process may be master surfaceflinger cannot be master too.
With this change surfaceflinger can use just a rendernode.
Note that we also have to modify the permissions table to allow render nodes
to use the dumb allocation functions. This is a hack and unlikely to be accepted
upstream but it's better than the huge security hole of allowing everything we were
using before.
Need to discuss an upstream acceptable way for this...
---
drivers/gpu/drm/drm_ioctl.c | 6 +++---
drivers/gpu/drm/imx/imx-drm-core.c | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index a9ae6dd..31c4c86 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -639,9 +639,9 @@ int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index f91cb72..0c34306 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -177,7 +177,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
static struct drm_driver imx_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
- DRIVER_ATOMIC,
+ DRIVER_ATOMIC | DRIVER_RENDER,
.lastclose = imx_drm_driver_lastclose,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
=====================================
Mesa 8.1.1
=====================================
with these cherry picked from master (master will probably work too but haven't tried yet)
commit 3f7bca44d9a9f07eaafc5de850ec65bdd00707b9
Author: Rob Herring <robh at kernel.org>
Date: Thu Apr 26 16:02:01 2018 +0200
egl/android: #ifdef out flink name support
Author: Robert Foss <robert.foss at collabora.com>
Date: Wed Apr 18 17:27:40 2018 +0200
egl/android: Add DRM node probing and filtering
And these two by me:
Make eglCreateImageKHR import modifiers.
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-24 11:44:09 +0200
This is required for, amoung other things, Android screenshots to work.
See mailing list discussion:
https://lists.freedesktop.org/archives/mesa-dev/2018-July/200654.html
---
src/egl/Android.mk | 3 ++-
src/egl/drivers/dri2/platform_android.c | 27 +++++++++++++++++++++++++--
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/egl/Android.mk b/src/egl/Android.mk
index 8412aeb..707ff9a 100644
--- a/src/egl/Android.mk
+++ b/src/egl/Android.mk
@@ -45,7 +45,8 @@ LOCAL_CFLAGS := \
LOCAL_C_INCLUDES := \
$(MESA_TOP)/src/egl/main \
- $(MESA_TOP)/src/egl/drivers/dri2
+ $(MESA_TOP)/src/egl/drivers/dri2 \
+ $(TOP)/external/libdrm/android
LOCAL_STATIC_LIBRARIES := \
libmesa_util \
diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
index a8dc5c8..d8e3494 100644
--- a/src/egl/drivers/dri2/platform_android.c
+++ b/src/egl/drivers/dri2/platform_android.c
@@ -43,6 +43,8 @@
#include "gralloc_drm.h"
#endif /* HAVE_DRM_GRALLOC */
+#include <gralloc_handle.h>
+
#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
struct droid_yuv_format {
@@ -801,6 +803,9 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
struct ANativeWindowBuffer *buf, int fd)
{
unsigned int pitch;
+ struct gralloc_gbm_handle_t *grh;
+ uint64_t modifier = 0;
+ bool have_modifier = false;
if (is_yuv(buf->format)) {
_EGLImage *image;
@@ -824,22 +829,40 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
}
pitch = buf->stride * get_format_bpp(buf->format);
+
if (pitch == 0) {
_eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
return NULL;
}
- const EGLint attr_list[] = {
+ grh = (struct gralloc_gbm_handle_t *)buf->handle;
+ if (grh->magic == GRALLOC_HANDLE_MAGIC) {
+ modifier = grh->modifier;
+ have_modifier = true;
+ }
+
+ EGLint attr_list[] = {
EGL_WIDTH, buf->width,
EGL_HEIGHT, buf->height,
EGL_LINUX_DRM_FOURCC_EXT, fourcc,
EGL_DMA_BUF_PLANE0_FD_EXT, fd,
EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, modifier & 0xffffffff,
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, modifier >> 32,
EGL_NONE, 0
};
- return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list);
+ if (!have_modifier) {
+ for (int i=0; i < ARRAY_SIZE(attr_list); i+=2) {
+ if (attr_list[i] == EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT) {
+ attr_list[i] = EGL_NONE;
+ break;
+ }
+ }
+ }
+
+ return dri2_create_image_dma_buf(disp, ctx, NULL, (const EGLint *)attr_list);
}
#ifdef HAVE_DRM_GRALLOC
(I'll submit the one above properly now that Tomasz has said he has no objection in principle)
Force the stride of transfer buffers to be the same as the master resource.
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-25 11:41:57 +0200
This is required on Android since the buffer stride is obtained from the gralloc
alloc operation, rather than the map (lock) operation.
This is an Android specificity so the approach used here, which forces it for
all use cases (and hence wastes memory on non Android), will not be acceptable
upstream.
But, when mesa supports explicit user_stride we may be able to reuse some of this
code (see patchwork below).
Without this patch a segfault occurs in inputflinger if a mouse is attached while
attempting to draw the mousepointer by software rendering.
See
https://lists.freedesktop.org/archives/etnaviv/2018-July/001886.html
https://patchwork.freedesktop.org/series/42303/
---
src/gallium/drivers/etnaviv/etnaviv_resource.c | 35 ++++++++++++++++++++++--
src/gallium/drivers/etnaviv/etnaviv_resource.h | 3 +-
src/gallium/drivers/etnaviv/etnaviv_texture.c | 2 +
src/gallium/drivers/etnaviv/etnaviv_transfer.c | 3 +-
4 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
index c600eff..4fd42f8 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_resource.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
@@ -176,10 +176,32 @@ setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
return size;
}
+static int etna_adjust_user_stride(
+ const struct pipe_resource *prsc, unsigned user_stride,
+ unsigned msaa_xscale, unsigned *paddingX)
+{
+ unsigned new_paddingX = *paddingX;
+ unsigned stride;
+
+ for (stride = 0; stride < user_stride; new_paddingX *= 2) {
+ unsigned padded_width = align(prsc->width0 * msaa_xscale, new_paddingX);
+ stride = util_format_get_stride(prsc->format, padded_width);
+ }
+
+ if (stride != user_stride)
+ return -EINVAL;
+
+ if (new_paddingX != *paddingX)
+ *paddingX = new_paddingX;
+
+ return 0;
+}
+
/* Create a new resource object, using the given template info */
struct pipe_resource *
etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
- uint64_t modifier, const struct pipe_resource *templat)
+ uint64_t modifier, const struct pipe_resource *templat,
+ unsigned user_stride)
{
struct etna_screen *screen = etna_screen(pscreen);
struct etna_resource *rsc;
@@ -233,6 +255,13 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
if (!screen->specs.use_blt && templat->target != PIPE_BUFFER)
etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
+ if (user_stride) {
+ if (etna_adjust_user_stride(templat, user_stride, msaa_xscale, &paddingX)) {
+ BUG("Unable to honour user_stride %u", user_stride);
+ return NULL;
+ }
+ }
+
if (templat->bind & PIPE_BIND_SCANOUT) {
struct pipe_resource scanout_templat = *templat;
struct renderonly_scanout *scanout;
@@ -357,7 +386,7 @@ etna_resource_create(struct pipe_screen *pscreen,
layout = ETNA_LAYOUT_LINEAR;
/* modifier is only used for scanout surfaces, so safe to use LINEAR here */
- return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat);
+ return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat, 0);
}
enum modifier_priority {
@@ -438,7 +467,7 @@ etna_resource_create_modifiers(struct pipe_screen *pscreen,
tmpl.bind |= PIPE_BIND_SCANOUT;
return etna_resource_alloc(pscreen, modifier_to_layout(modifier),
- modifier, &tmpl);
+ modifier, &tmpl, 0);
}
static void
diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h
index 11ccf8f..3cece4e 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_resource.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h
@@ -155,7 +155,8 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
struct pipe_resource *
etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
- uint64_t modifier, const struct pipe_resource *templat);
+ uint64_t modifier, const struct pipe_resource *templat,
+ unsigned user_stride);
void
etna_resource_screen_init(struct pipe_screen *pscreen);
diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c
index 72ef00b..799908d 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_texture.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c
@@ -203,7 +203,7 @@ etna_texture_handle_incompatible(struct pipe_context *pctx, struct pipe_resource
PIPE_BIND_BLENDABLE);
res->texture =
etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED,
- DRM_FORMAT_MOD_LINEAR, &templat);
+ DRM_FORMAT_MOD_LINEAR, &templat, 0);
}
if (!res->texture) {
diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
index 30ae3bf..6d2e654 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
@@ -208,7 +208,8 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
templ.bind = PIPE_BIND_RENDER_TARGET;
trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR,
- DRM_FORMAT_MOD_LINEAR, &templ);
+ DRM_FORMAT_MOD_LINEAR, &templ,
+ rsc->levels[level].stride);
if (!trans->rsc) {
slab_free(&ctx->transfer_pool, trans);
return NULL;
=================
drm_hwcompooser
=================
Unmodified (78c9f6c26210423926ea027edfab0b9504c2d7ff)
=========================
libdrm 2.4.92
=========================
A build fix patch for android 8.1
Android 8 wants to build libdrm twice, for vendor and system.
From: Martin Fuzzey <mfuzzey at parkeon.com>
Date: 2018-07-25 12:19:12 +0200
---
Android.mk | 47 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/Android.mk b/Android.mk
index 1b77c53..9e2b949 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,6 +21,10 @@
# IN THE SOFTWARE.
#
+# Two identical libs are defined here.
+# libdrm: for vendors. installed to /vendor/lib. libdrm_<vendor> uses this.
+# libdrm_platform: for platform modules (such as libminui). installed to /system/lib
+
LIBDRM_COMMON_MK := $(call my-dir)/Android.common.mk
LOCAL_PATH := $(call my-dir)
@@ -57,8 +61,47 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH)/include/drm \
$(LOCAL_PATH)/android
-LOCAL_SHARED_LIBRARIES := \
- libcutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include/drm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)
+
+
+
+
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_{,H,INCLUDE_H,INCLUDE_ANDROID_H,INCLUDE_VMWGFX_H}_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+#static library for the device (recovery)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdrm_platform
+
+LOCAL_SRC_FILES := $(LIBDRM_FILES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include/drm \
+ $(LOCAL_PATH)/android
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include/drm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+# Shared library for the device
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdrm_platform
+
+LOCAL_SRC_FILES := $(LIBDRM_FILES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include/drm \
+ $(LOCAL_PATH)/android
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include/drm
=====================================
GBM GRALLOC (handle rework v2 branch)
=====================================
with these two additional patches:
Sometimes, such as when taking screenshots, android tries to lock a zero sized region.
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-25 12:12:13 +0200
Map the full buffer in this case
---
gralloc_gbm.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gralloc_gbm.cpp b/gralloc_gbm.cpp
index cd37f4d..17434ca 100644
--- a/gralloc_gbm.cpp
+++ b/gralloc_gbm.cpp
@@ -397,7 +397,6 @@ int gralloc_gbm_bo_lock(buffer_handle_t handle,
struct gralloc_handle_t *gbm_handle = gralloc_handle(handle);
struct gbm_bo *bo = gralloc_gbm_bo_from_handle(handle);
struct bo_data_t *bo_data;
-
if (!bo)
return -EINVAL;
@@ -427,6 +426,12 @@ int gralloc_gbm_bo_lock(buffer_handle_t handle,
usage |= bo_data->locked_for;
+ if (w == 0)
+ w = gbm_handle->width;
+
+ if (h == 0)
+ h = gbm_handle->height;
+
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK |
GRALLOC_USAGE_SW_READ_MASK)) {
/* the driver is supposed to wait for the bo */
Buffers used for software rendering should not be marked as scanout.
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-25 12:14:18 +0200
Without this the mouse pointer is not rendered correctly
---
gralloc_gbm.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gralloc_gbm.cpp b/gralloc_gbm.cpp
index 17434ca..9b16878 100644
--- a/gralloc_gbm.cpp
+++ b/gralloc_gbm.cpp
@@ -147,7 +147,7 @@ static unsigned int get_pipe_bind(int usage)
bind |= GBM_BO_USE_RENDERING;
if (usage & GRALLOC_USAGE_HW_FB)
bind |= GBM_BO_USE_SCANOUT;
- if (usage & GRALLOC_USAGE_HW_COMPOSER)
+ if ((usage & GRALLOC_USAGE_HW_COMPOSER) && !(usage & (GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)))
bind |= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
return bind;
========================================
Android AOSP 8.1.1
========================================
And this fix to frameworks/base
Fix fatal log on framework startup
From: Martin Fuzzey <martin.fuzzey at flowbird.group>
Date: 2018-07-25 18:52:53 +0200
Do not exit with a fatal error if the EGL_EXT_pixel_format_float extenstion is supported
but no corresponding EGL config exists.
Just behave as if the extension did not exist in that case.
The prevents "F OpenGLRenderer: Device claims wide gamut support, cannot find matching config, error = EGL_SUCCESS"
I think this is actually an Android bug.
Nothing in the spec says that if the extension is supported by an implementation it must also be supported
by at least one config.
---
libs/hwui/renderthread/EglManager.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 16d7736..38df0ae 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -223,7 +223,7 @@ void EglManager::loadConfigs() {
numConfigs = 1;
if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, &numConfigs)
|| numConfigs != 1) {
- LOG_ALWAYS_FATAL(
+ ALOGW(
"Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
}
@@ -256,7 +256,8 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG
initialize();
wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB
- && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+ && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext
+ && (mEglConfigWideGamut != nullptr);
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
==================
Config
==================
Init script in /system/vendor/etc/init/ossgfx.rc
on early-init
setprop ro.hardware.hwcomposer drm
setprop ro.hardware.gralloc gbm
setprop gralloc.gbm.device /dev/dri/renderD129
setprop hwc.drm.device /dev/dri/card1
setprop drm.gpu.vendor_name etnaviv
export EGL_LOG_LEVEL info
setprop debug.egl.trace error
In device.mk:
PRODUCT_PACKAGES += \
android.hardware.graphics.allocator at 2.0-impl \
android.hardware.graphics.allocator at 2.0-service \
android.hardware.graphics.mapper at 2.0-impl
# HW Composer
PRODUCT_PACKAGES += \
android.hardware.graphics.composer at 2.1-impl \
android.hardware.graphics.composer at 2.1-service
# Open source graphics stack
PRODUCT_PACKAGES += \
libdrm_etnaviv \
libGLES_mesa \
gralloc.gbm \
hwcomposer.drm
Best regards,
Martin
More information about the etnaviv
mailing list