/************************************************************************** * * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA * All Rights Reserved. * * 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 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 * THE COPYRIGHT HOLDERS, AUTHORS 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. * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * **************************************************************************/ /* * Authors: * Keith Whitwell * Brian Paul */ #include "xlib.h" #ifdef GALLIUM_CELL #include "xm_api.h" #undef ASSERT #undef Elements #include "pipe/internal/p_winsys_screen.h" #include "pipe/p_format.h" #include "pipe/p_context.h" #include "pipe/p_inlines.h" #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" #include "cell/ppu/cell_context.h" #include "cell/ppu/cell_screen.h" #include "cell/ppu/cell_winsys.h" #include "cell/ppu/cell_texture.h" /** * Subclass of pipe_buffer for Xlib winsys. * Low-level OS/window system memory buffer */ struct xm_buffer { struct pipe_buffer base; boolean userBuffer; /** Is this a user-space buffer? */ void *data; void *mapped; XImage *tempImage; int shm; }; /** * Subclass of pipe_winsys for Xlib winsys */ struct xmesa_pipe_winsys { struct pipe_winsys base; }; /** Cast wrapper */ static INLINE struct xm_buffer * xm_buffer( struct pipe_buffer *buf ) { return (struct xm_buffer *)buf; } /* Most callbacks map direcly onto dri_bufmgr operations: */ static void * xm_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buf, unsigned flags) { struct xm_buffer *xm_buf = xm_buffer(buf); xm_buf->mapped = xm_buf->data; return xm_buf->mapped; } static void xm_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf) { struct xm_buffer *xm_buf = xm_buffer(buf); xm_buf->mapped = NULL; } static void xm_buffer_destroy(/*struct pipe_winsys *pws,*/ struct pipe_buffer *buf) { struct xm_buffer *oldBuf = xm_buffer(buf); if (oldBuf) { if (oldBuf->data) { if (!oldBuf->userBuffer) { align_free(oldBuf->data); } oldBuf->data = NULL; } free(oldBuf); } } /** * For Cell. Basically, rearrange the pixels/quads from this layout: * +--+--+--+--+ * |p0|p1|p2|p3|.... * +--+--+--+--+ * * to this layout: * +--+--+ * |p0|p1|.... * +--+--+ * |p2|p3| * +--+--+ */ static void twiddle_tile(const uint *tileIn, uint *tileOut) { int y, x; for (y = 0; y < TILE_SIZE; y+=2) { for (x = 0; x < TILE_SIZE; x+=2) { int k = 4 * (y/2 * TILE_SIZE/2 + x/2); tileOut[y * TILE_SIZE + (x + 0)] = tileIn[k]; tileOut[y * TILE_SIZE + (x + 1)] = tileIn[k+1]; tileOut[(y + 1) * TILE_SIZE + (x + 0)] = tileIn[k+2]; tileOut[(y + 1) * TILE_SIZE + (x + 1)] = tileIn[k+3]; } } } /** * Display a surface that's in a tiled configuration. That is, all the * pixels for a TILE_SIZExTILE_SIZE block are contiguous in memory. */ static void xlib_cell_display_surface(struct xmesa_buffer *b, struct pipe_surface *surf) { XImage *ximage; struct xm_buffer *xm_buf = xm_buffer( cell_texture(surf->texture)->buffer); const uint tilesPerRow = (surf->width + TILE_SIZE - 1) / TILE_SIZE; uint x, y; ximage = b->tempImage; /* check that the XImage has been previously initialized */ assert(ximage->format); assert(ximage->bitmap_unit); /* update XImage's fields */ ximage->width = TILE_SIZE; ximage->height = TILE_SIZE; ximage->bytes_per_line = TILE_SIZE * 4; for (y = 0; y < surf->height; y += TILE_SIZE) { for (x = 0; x < surf->width; x += TILE_SIZE) { uint tmpTile[TILE_SIZE * TILE_SIZE]; int tx = x / TILE_SIZE; int ty = y / TILE_SIZE; int offset = ty * tilesPerRow + tx; int w = TILE_SIZE; int h = TILE_SIZE; if (y + h > surf->height) h = surf->height - y; if (x + w > surf->width) w = surf->width - x; /* offset in pixels */ offset *= TILE_SIZE * TILE_SIZE; /* twiddle from ximage buffer to temp tile */ twiddle_tile((uint *) xm_buf->data + offset, tmpTile); /* display temp tile data */ ximage->data = (char *) tmpTile; XPutImage(b->xm_visual->display, b->drawable, b->gc, ximage, 0, 0, x, y, w, h); } } } static void xm_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surf, void *context_private) { /* * The front color buffer is actually just another XImage buffer. * This function copies that XImage to the actual X Window. */ XMesaContext xmctx = (XMesaContext) context_private; if (xmctx) xlib_cell_display_surface(xmctx->xm_buffer, surf); } static const char * xm_get_name(struct pipe_winsys *pws) { return "Xlib/Cell"; } static struct pipe_buffer * xm_buffer_create(struct pipe_winsys *pws, unsigned alignment, unsigned usage, unsigned size) { struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer); pipe_reference_init(&buffer->base.reference, 1); buffer->base.alignment = alignment; buffer->base.usage = usage; buffer->base.size = size; if (buffer->data == NULL) { buffer->shm = 0; /* align to 16-byte multiple for Cell */ buffer->data = align_malloc(size, max(alignment, 16)); } return &buffer->base; } /** * Create buffer which wraps user-space data. */ static struct pipe_buffer * xm_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes) { struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer); pipe_reference_init(&buffer->base.reference, 1); buffer->base.size = bytes; buffer->userBuffer = TRUE; buffer->data = ptr; buffer->shm = 0; return &buffer->base; } static struct pipe_buffer * xm_surface_buffer_create(struct pipe_winsys *winsys, unsigned width, unsigned height, enum pipe_format format, unsigned usage, unsigned tex_usage, unsigned *stride) { const unsigned alignment = 64; unsigned nblocksy; nblocksy = util_format_get_nblocksy(format, height); *stride = align(util_format_get_stride(format, width), alignment); return winsys->buffer_create(winsys, alignment, usage, /* XXX a bit of a hack */ *stride * align(nblocksy, TILE_SIZE)); } /* * Fence functions - basically nothing to do, as we don't create any actual * fence objects. */ static void xm_fence_reference(struct pipe_winsys *sws, struct pipe_fence_handle **ptr, struct pipe_fence_handle *fence) { } static int xm_fence_signalled(struct pipe_winsys *sws, struct pipe_fence_handle *fence, unsigned flag) { return 0; } static int xm_fence_finish(struct pipe_winsys *sws, struct pipe_fence_handle *fence, unsigned flag) { return 0; } static struct pipe_winsys * xlib_create_cell_winsys( void ) { static struct xmesa_pipe_winsys *ws = NULL; if (!ws) { ws = CALLOC_STRUCT(xmesa_pipe_winsys); /* Fill in this struct with callbacks that pipe will need to * communicate with the window system, buffer manager, etc. */ ws->base.buffer_create = xm_buffer_create; ws->base.user_buffer_create = xm_user_buffer_create; ws->base.buffer_map = xm_buffer_map; ws->base.buffer_unmap = xm_buffer_unmap; ws->base.buffer_destroy = xm_buffer_destroy; ws->base.surface_buffer_create = xm_surface_buffer_create; ws->base.fence_reference = xm_fence_reference; ws->base.fence_signalled = xm_fence_signalled; ws->base.fence_finish = xm_fence_finish; ws->base.flush_frontbuffer = xm_flush_frontbuffer; ws->base.get_name = xm_get_name; } return &ws->base; } static struct pipe_screen * xlib_create_cell_screen( void ) { struct pipe_winsys *winsys; struct pipe_screen *screen; winsys = xlib_create_cell_winsys(); if (winsys == NULL) return NULL; screen = cell_create_screen(winsys); if (screen == NULL) goto fail; return screen; fail: if (winsys) winsys->destroy( winsys ); return NULL; } static struct pipe_context * xlib_create_cell_context( struct pipe_screen *screen, void *priv ) { struct pipe_context *pipe; /* This takes a cell_winsys pointer, but probably that should be * created and stored at screen creation, not context creation. * * The actual cell_winsys value isn't used for anything, so just * passing NULL for now. */ pipe = cell_create_context( screen, NULL); if (pipe == NULL) goto fail; pipe->priv = priv; return pipe; fail: return NULL; } struct xm_driver xlib_cell_driver = { .create_pipe_screen = xlib_create_cell_screen, .create_pipe_context = xlib_create_cell_context, .display_surface = xlib_cell_display_surface, }; #else struct xm_driver xlib_cell_driver = { .create_pipe_screen = NULL, .create_pipe_context = NULL, .display_surface = NULL, }; #endif