/************************************************************************** * * Copyright 2009, VMware, Inc. * All Rights Reserved. * Copyright 2010 George Sapountzis * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "pipe/p_compiler.h" #include "pipe/p_format.h" #include "util/u_inlines.h" #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" #include "state_tracker/sw_winsys.h" #include "state_tracker/drm_driver.h" #include "dri_sw_winsys.h" #ifdef HAVE_ANDROID_PLATFORM #include #include #include #endif struct dri_sw_displaytarget { enum pipe_format format; unsigned width; unsigned height; unsigned stride; unsigned map_flags; #ifdef HAVE_ANDROID_PLATFORM struct ANativeWindowBuffer *androidBuffer; #endif void *data; void *mapped; const void *front_private; }; #ifdef HAVE_ANDROID_PLATFORM const struct gralloc_module_t* get_gralloc() { static const struct gralloc_module_t* gr_module = NULL; const hw_module_t *mod; int err; if (!gr_module) { err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod); if (!err) { gr_module = (gralloc_module_t *) mod; } } return gr_module; } #endif struct dri_sw_winsys { struct sw_winsys base; struct drisw_loader_funcs *lf; }; static inline struct dri_sw_displaytarget * dri_sw_displaytarget( struct sw_displaytarget *dt ) { return (struct dri_sw_displaytarget *)dt; } static inline struct dri_sw_winsys * dri_sw_winsys( struct sw_winsys *ws ) { return (struct dri_sw_winsys *)ws; } static boolean dri_sw_is_displaytarget_format_supported( struct sw_winsys *ws, unsigned tex_usage, enum pipe_format format ) { /* TODO: check visuals or other sensible thing here */ return TRUE; } static struct sw_displaytarget * dri_sw_displaytarget_create(struct sw_winsys *winsys, unsigned tex_usage, enum pipe_format format, unsigned width, unsigned height, unsigned alignment, const void *front_private, unsigned *stride) { struct dri_sw_displaytarget *dri_sw_dt; unsigned nblocksy, size, format_stride; dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget); if(!dri_sw_dt) goto no_dt; dri_sw_dt->format = format; dri_sw_dt->width = width; dri_sw_dt->height = height; dri_sw_dt->front_private = front_private; format_stride = util_format_get_stride(format, width); dri_sw_dt->stride = align(format_stride, alignment); nblocksy = util_format_get_nblocksy(format, height); size = dri_sw_dt->stride * nblocksy; dri_sw_dt->data = align_malloc(size, alignment); if(!dri_sw_dt->data) goto no_data; *stride = dri_sw_dt->stride; return (struct sw_displaytarget *)dri_sw_dt; no_data: FREE(dri_sw_dt); no_dt: return NULL; } static void dri_sw_displaytarget_destroy(struct sw_winsys *ws, struct sw_displaytarget *dt) { struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); #ifdef HAVE_ANDROID_PLATFORM if (dri_sw_dt->androidBuffer) { dri_sw_dt->androidBuffer->common.decRef(&dri_sw_dt->androidBuffer->common); } #endif align_free(dri_sw_dt->data); FREE(dri_sw_dt); } static void * dri_sw_displaytarget_map(struct sw_winsys *ws, struct sw_displaytarget *dt, unsigned flags) { struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); #ifdef HAVE_ANDROID_PLATFORM if (dri_sw_dt->androidBuffer) { if (!get_gralloc()->lock(get_gralloc(), dri_sw_dt->androidBuffer->handle, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, 0, 0, dri_sw_dt->androidBuffer->width, dri_sw_dt->androidBuffer->height, (void**)&dri_sw_dt->mapped)) { dri_sw_dt->map_flags = flags; return dri_sw_dt->mapped; } } #endif dri_sw_dt->mapped = dri_sw_dt->data; if (dri_sw_dt->front_private && (flags & PIPE_TRANSFER_READ)) { struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); dri_sw_ws->lf->get_image((void *)dri_sw_dt->front_private, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride, dri_sw_dt->data); } dri_sw_dt->map_flags = flags; return dri_sw_dt->mapped; } static void dri_sw_displaytarget_unmap(struct sw_winsys *ws, struct sw_displaytarget *dt) { struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_TRANSFER_WRITE)) { struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); dri_sw_ws->lf->put_image2((void *)dri_sw_dt->front_private, dri_sw_dt->data, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride); } dri_sw_dt->map_flags = 0; #ifdef HAVE_ANDROID_PLATFORM if (dri_sw_dt->androidBuffer) { get_gralloc()->unlock(get_gralloc(), dri_sw_dt->androidBuffer->handle); } #endif dri_sw_dt->mapped = NULL; } static struct sw_displaytarget * dri_sw_displaytarget_from_handle(struct sw_winsys *winsys, const struct pipe_resource *templ, struct winsys_handle *whandle, unsigned *stride) { #ifdef HAVE_ANDROID_PLATFORM struct dri_sw_displaytarget *dri_sw_dt; if (whandle->type == DRM_API_HANDLE_TYPE_BUFFER) { dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget); dri_sw_dt->width = templ->width0; dri_sw_dt->height = templ->height0; dri_sw_dt->androidBuffer = whandle->externalBuffer; dri_sw_dt->stride = whandle->stride; dri_sw_dt->androidBuffer->common.incRef(&dri_sw_dt->androidBuffer->common); *stride = dri_sw_dt->stride; return dri_sw_dt; } #endif assert(0); return NULL; } static boolean dri_sw_displaytarget_get_handle(struct sw_winsys *winsys, struct sw_displaytarget *dt, struct winsys_handle *whandle) { assert(0); return FALSE; } static void dri_sw_displaytarget_display(struct sw_winsys *ws, struct sw_displaytarget *dt, void *context_private, struct pipe_box *box) { struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); struct dri_drawable *dri_drawable = (struct dri_drawable *)context_private; unsigned width, height; unsigned blsize = util_format_get_blocksize(dri_sw_dt->format); /* Set the width to 'stride / cpp'. * * PutImage correctly clips to the width of the dst drawable. */ width = dri_sw_dt->stride / blsize; height = dri_sw_dt->height; if (box) { void *data; data = dri_sw_dt->data + (dri_sw_dt->stride * box->y) + box->x * blsize; dri_sw_ws->lf->put_image2(dri_drawable, data, box->x, box->y, box->width, box->height, dri_sw_dt->stride); } else { dri_sw_ws->lf->put_image(dri_drawable, dri_sw_dt->data, width, height); } } static void dri_destroy_sw_winsys(struct sw_winsys *winsys) { FREE(winsys); } struct sw_winsys * dri_create_sw_winsys(struct drisw_loader_funcs *lf) { struct dri_sw_winsys *ws; ws = CALLOC_STRUCT(dri_sw_winsys); if (!ws) return NULL; ws->lf = lf; ws->base.destroy = dri_destroy_sw_winsys; ws->base.is_displaytarget_format_supported = dri_sw_is_displaytarget_format_supported; /* screen texture functions */ ws->base.displaytarget_create = dri_sw_displaytarget_create; ws->base.displaytarget_destroy = dri_sw_displaytarget_destroy; ws->base.displaytarget_from_handle = dri_sw_displaytarget_from_handle; ws->base.displaytarget_get_handle = dri_sw_displaytarget_get_handle; /* texture functions */ ws->base.displaytarget_map = dri_sw_displaytarget_map; ws->base.displaytarget_unmap = dri_sw_displaytarget_unmap; ws->base.displaytarget_display = dri_sw_displaytarget_display; return &ws->base; } /* vim: set sw=3 ts=8 sts=3 expandtab: */