From 2b1f1af17f8e8f199cb0dd4f7f1a225529b357c5 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Mon, 11 Oct 2010 16:06:47 +0800 Subject: android: Add DRM-based gralloc. --- src/gralloc/gralloc_gem_pipe.c | 333 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/gralloc/gralloc_gem_pipe.c (limited to 'src/gralloc/gralloc_gem_pipe.c') diff --git a/src/gralloc/gralloc_gem_pipe.c b/src/gralloc/gralloc_gem_pipe.c new file mode 100644 index 0000000000..99a8461627 --- /dev/null +++ b/src/gralloc/gralloc_gem_pipe.c @@ -0,0 +1,333 @@ +#define LOG_TAG "GRALLOC-PIPE" + +#include +#include + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "state_tracker/drm_driver.h" +#include "util/u_inlines.h" +#include "util/u_memory.h" + +#include "gralloc_mod.h" +#include "gralloc_gem.h" + +struct drm_pipe_manager { + pthread_mutex_t mutex; + struct pipe_screen *screen; + struct pipe_context *context; +}; + +struct drm_pipe_buffer { + struct winsys_handle winsys; + uint32_t fb_handle; + struct pipe_resource *resource; + struct pipe_transfer *transfer; +}; + +static void +drm_gem_drv_init_features_locked(struct drm_module_t *drm) +{ + drm->mode_dirty_fb = 0; + drm->mode_page_flip = 0; + + if (strcmp(driver_descriptor.driver_name, "vmwgfx") == 0) + drm->mode_dirty_fb = 1; + + drm->swap_interval = 0; +} + +static int +drm_gem_drv_init_locked(struct drm_module_t *drm) +{ + struct drm_pipe_manager *pm; + + if (drm->gem) + return 0; + + pm = CALLOC(1, sizeof(*pm)); + if (!pm) + return -ENOMEM; + + pthread_mutex_init(&pm->mutex, NULL); + + pm->screen = driver_descriptor.create_screen(drm->fd); + if (!pm->screen) { + LOGE("failed to create pipe screen"); + FREE(pm); + return -EINVAL; + } + + drm->gem = (void *) pm; + + drm_gem_drv_init_features_locked(drm); + + return 0; +} + +int +drm_gem_drv_init(struct drm_module_t *drm) +{ + int ret; + + pthread_mutex_lock(&drm->mutex); + ret = drm_gem_drv_init_locked(drm); + pthread_mutex_unlock(&drm->mutex); + + return ret; +} + +static enum pipe_format +get_pipe_format(int format) +{ + enum pipe_format fmt; + + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + fmt = PIPE_FORMAT_R8G8B8A8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGBX_8888: + fmt = PIPE_FORMAT_R8G8B8X8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGB_888: + fmt = PIPE_FORMAT_R8G8B8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGB_565: + fmt = PIPE_FORMAT_B5G6R5_UNORM; + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + fmt = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + default: + fmt = PIPE_FORMAT_NONE; + break; + } + + return fmt; +} + +static unsigned +get_pipe_bind(int usage) +{ + unsigned bind = PIPE_BIND_SHARED; + + if (usage & GRALLOC_USAGE_SW_READ_MASK) + bind |= PIPE_BIND_TRANSFER_READ; + if (usage & GRALLOC_USAGE_SW_WRITE_MASK) + bind |= PIPE_BIND_TRANSFER_WRITE; + + if (usage & GRALLOC_USAGE_HW_TEXTURE) + bind |= PIPE_BIND_SAMPLER_VIEW; + if (usage & GRALLOC_USAGE_HW_RENDER) + bind |= PIPE_BIND_RENDER_TARGET; + if (usage & GRALLOC_USAGE_HW_FB) { + bind |= PIPE_BIND_RENDER_TARGET; + bind |= PIPE_BIND_SCANOUT; + } + + return bind; +} + +static struct drm_pipe_buffer * +get_pipe_buffer(struct drm_pipe_manager *pm, int width, int height, + int format, int usage, struct winsys_handle *winsys) +{ + struct drm_pipe_buffer *buf; + struct pipe_resource templ; + + memset(&templ, 0, sizeof(templ)); + templ.format = get_pipe_format(format); + templ.bind = get_pipe_bind(usage); + templ.target = PIPE_TEXTURE_2D; + + if (templ.format == PIPE_FORMAT_NONE || + !pm->screen->is_format_supported(pm->screen, templ.format, + templ.target, 0, templ.bind, 0)) { + LOGE("unsupported format 0x%x", format); + return NULL; + } + + buf = CALLOC(1, sizeof(*buf)); + if (!buf) + return NULL; + + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + + if (winsys) { + buf->resource = pm->screen->resource_from_handle(pm->screen, + &templ, winsys); + if (!buf->resource) + goto fail; + + buf->winsys = *winsys; + } + else { + buf->resource = pm->screen->resource_create(pm->screen, &templ); + if (!buf->resource) + goto fail; + + buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED; + if (!pm->screen->resource_get_handle(pm->screen, buf->resource, &buf->winsys)) + goto fail; + } + + /* need the gem handle for fb */ + if (usage & GRALLOC_USAGE_HW_FB) { + struct winsys_handle tmp; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = DRM_API_HANDLE_TYPE_KMS; + if (!pm->screen->resource_get_handle(pm->screen, buf->resource, &tmp)) + goto fail; + + buf->fb_handle = tmp.handle; + } + + return buf; + +fail: + LOGE("failed to allocate pipe buffer"); + if (buf->resource) + pipe_resource_reference(&buf->resource, NULL); + FREE(buf); + + return NULL; +} + +struct drm_bo_t * +drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride) +{ + struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; + struct drm_pipe_buffer *buf; + struct drm_bo_t *bo; + struct pipe_resource templ; + + bo = drm_gem_create_bo(width, height, format, usage); + if (!bo) + return NULL; + + pthread_mutex_lock(&pm->mutex); + buf = get_pipe_buffer(pm, width, height, format, usage, NULL); + pthread_mutex_unlock(&pm->mutex); + + if (buf) { + bo->name = (int) buf->winsys.handle; + bo->stride = (int) buf->winsys.stride; + + bo->fb_handle = buf->fb_handle; + bo->data = (int) buf; + + *stride = bo->stride; + } + else { + free(bo); + bo = NULL; + } + + return bo; +} + +void +drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; + struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; + + pthread_mutex_lock(&pm->mutex); + + if (buf->transfer) + pipe_transfer_destroy(pm->context, buf->transfer); + pipe_resource_reference(&buf->resource, NULL); + + pthread_mutex_unlock(&pm->mutex); + + FREE(buf); + free(bo); +} + +int +drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr) +{ + struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; + struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; + enum pipe_transfer_usage usage = 0; + int ret = 0; + + pthread_mutex_lock(&pm->mutex); + + /* need a context to get transfer */ + if (!pm->context) { + pm->context = pm->screen->context_create(pm->screen, NULL); + if (!pm->context) { + LOGE("failed to create pipe context"); + ret = -ENOMEM; + } + } + + /* the bo was allocated by another process */ + if (!buf && !ret) { + struct winsys_handle winsys; + + memset(&winsys, 0, sizeof(winsys)); + winsys.type = DRM_API_HANDLE_TYPE_SHARED; + winsys.handle = bo->name; + winsys.stride = bo->stride; + + buf = get_pipe_buffer(pm, bo->width, bo->height, + bo->format, bo->usage, &winsys); + if (!buf) { + LOGE("failed to create pipe buffer from name %u", bo->name); + ret = -ENOMEM; + } + + bo->data = (int) buf; + } + + if (buf) { + usage = PIPE_TRANSFER_READ; + if (enable_write) + usage |= PIPE_TRANSFER_WRITE; + + assert(!buf->transfer); + + /* + * ignore x, y, w and h so that returned addr points at the start of the + * buffer + */ + buf->transfer = pipe_get_transfer(pm->context, buf->resource, + 0, 0, usage, 0, 0, bo->width, bo->height); + if (buf->transfer) + *addr = pipe_transfer_map(pm->context, buf->transfer); + else + ret = -ENOMEM; + } + + pthread_mutex_unlock(&pm->mutex); + + return ret; +} + +void +drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; + struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; + + pthread_mutex_lock(&pm->mutex); + + assert(buf && buf->transfer); + + pipe_transfer_unmap(pm->context, buf->transfer); + pipe_transfer_destroy(pm->context, buf->transfer); + buf->transfer = NULL; + + pm->context->flush(pm->context, PIPE_FLUSH_RENDER_CACHE, NULL); + + pthread_mutex_unlock(&pm->mutex); +} -- cgit v1.2.3