| /************************************************************************** |
| * |
| * Copyright 2009 Younes Manton. |
| * 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 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 TUNGSTEN GRAPHICS 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 <vl_winsys.h> |
| #include <X11/Xutil.h> |
| #include <pipe/internal/p_winsys_screen.h> |
| #include <pipe/p_state.h> |
| #include <pipe/p_inlines.h> |
| #include <util/u_memory.h> |
| #include <util/u_math.h> |
| #include <softpipe/sp_winsys.h> |
| #include <softpipe/sp_video_context.h> |
| #include <softpipe/sp_texture.h> |
| |
| /* pipe_winsys implementation */ |
| |
| struct xsp_pipe_winsys |
| { |
| struct pipe_winsys base; |
| Display *display; |
| int screen; |
| XImage *fbimage; |
| }; |
| |
| struct xsp_context |
| { |
| Drawable drawable; |
| |
| void (*pipe_destroy)(struct pipe_video_context *vpipe); |
| }; |
| |
| struct xsp_buffer |
| { |
| struct pipe_buffer base; |
| boolean is_user_buffer; |
| void *data; |
| void *mapped_data; |
| }; |
| |
| static struct pipe_buffer* xsp_buffer_create(struct pipe_winsys *pws, unsigned alignment, unsigned usage, unsigned size) |
| { |
| struct xsp_buffer *buffer; |
| |
| assert(pws); |
| |
| buffer = calloc(1, sizeof(struct xsp_buffer)); |
| pipe_reference_init(&buffer->base.reference, 1); |
| buffer->base.alignment = alignment; |
| buffer->base.usage = usage; |
| buffer->base.size = size; |
| buffer->data = align_malloc(size, alignment); |
| |
| return (struct pipe_buffer*)buffer; |
| } |
| |
| static struct pipe_buffer* xsp_user_buffer_create(struct pipe_winsys *pws, void *data, unsigned size) |
| { |
| struct xsp_buffer *buffer; |
| |
| assert(pws); |
| |
| buffer = calloc(1, sizeof(struct xsp_buffer)); |
| pipe_reference_init(&buffer->base.reference, 1); |
| buffer->base.size = size; |
| buffer->is_user_buffer = TRUE; |
| buffer->data = data; |
| |
| return (struct pipe_buffer*)buffer; |
| } |
| |
| static void* xsp_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buffer, unsigned flags) |
| { |
| struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; |
| |
| assert(pws); |
| assert(buffer); |
| |
| xsp_buf->mapped_data = xsp_buf->data; |
| |
| return xsp_buf->mapped_data; |
| } |
| |
| static void xsp_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buffer) |
| { |
| struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; |
| |
| assert(pws); |
| assert(buffer); |
| |
| xsp_buf->mapped_data = NULL; |
| } |
| |
| static void xsp_buffer_destroy(struct pipe_buffer *buffer) |
| { |
| struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; |
| |
| assert(buffer); |
| |
| if (!xsp_buf->is_user_buffer) |
| align_free(xsp_buf->data); |
| |
| free(xsp_buf); |
| } |
| |
| static struct pipe_buffer* xsp_surface_buffer_create |
| ( |
| struct pipe_winsys *pws, |
| unsigned width, |
| unsigned height, |
| enum pipe_format format, |
| unsigned usage, |
| unsigned tex_usage, |
| unsigned *stride |
| ) |
| { |
| const unsigned int ALIGNMENT = 1; |
| struct pipe_format_block block; |
| unsigned nblocksx, nblocksy; |
| |
| pf_get_block(format, &block); |
| nblocksx = pf_get_nblocksx(&block, width); |
| nblocksy = pf_get_nblocksy(&block, height); |
| *stride = align(nblocksx * block.size, ALIGNMENT); |
| |
| return pws->buffer_create(pws, ALIGNMENT, usage, |
| *stride * nblocksy); |
| } |
| |
| static void xsp_fence_reference(struct pipe_winsys *pws, struct pipe_fence_handle **ptr, struct pipe_fence_handle *fence) |
| { |
| assert(pws); |
| assert(ptr); |
| assert(fence); |
| } |
| |
| static int xsp_fence_signalled(struct pipe_winsys *pws, struct pipe_fence_handle *fence, unsigned flag) |
| { |
| assert(pws); |
| assert(fence); |
| |
| return 0; |
| } |
| |
| static int xsp_fence_finish(struct pipe_winsys *pws, struct pipe_fence_handle *fence, unsigned flag) |
| { |
| assert(pws); |
| assert(fence); |
| |
| return 0; |
| } |
| |
| static void xsp_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surface, void *context_private) |
| { |
| struct xsp_pipe_winsys *xsp_winsys; |
| struct xsp_context *xsp_context; |
| |
| assert(pws); |
| assert(surface); |
| assert(context_private); |
| |
| xsp_winsys = (struct xsp_pipe_winsys*)pws; |
| xsp_context = (struct xsp_context*)context_private; |
| xsp_winsys->fbimage->width = surface->width; |
| xsp_winsys->fbimage->height = surface->height; |
| xsp_winsys->fbimage->bytes_per_line = surface->width * (xsp_winsys->fbimage->bits_per_pixel >> 3); |
| xsp_winsys->fbimage->data = (char*)((struct xsp_buffer *)softpipe_texture(surface->texture)->buffer)->data + surface->offset; |
| |
| XPutImage |
| ( |
| xsp_winsys->display, xsp_context->drawable, |
| XDefaultGC(xsp_winsys->display, xsp_winsys->screen), |
| xsp_winsys->fbimage, 0, 0, 0, 0, |
| surface->width, surface->height |
| ); |
| XFlush(xsp_winsys->display); |
| } |
| |
| static const char* xsp_get_name(struct pipe_winsys *pws) |
| { |
| assert(pws); |
| return "X11 SoftPipe"; |
| } |
| |
| static void xsp_destroy(struct pipe_winsys *pws) |
| { |
| struct xsp_pipe_winsys *xsp_winsys = (struct xsp_pipe_winsys*)pws; |
| |
| assert(pws); |
| |
| /* XDestroyImage() wants to free the data as well */ |
| xsp_winsys->fbimage->data = NULL; |
| |
| XDestroyImage(xsp_winsys->fbimage); |
| FREE(xsp_winsys); |
| } |
| |
| /* Called through pipe_video_context::destroy() */ |
| static void xsp_pipe_destroy(struct pipe_video_context *vpipe) |
| { |
| struct xsp_context *xsp_context; |
| |
| assert(vpipe); |
| |
| xsp_context = vpipe->priv; |
| |
| /* Call the original destroy */ |
| xsp_context->pipe_destroy(vpipe); |
| |
| FREE(xsp_context); |
| } |
| |
| /* Show starts here */ |
| |
| Drawable |
| vl_video_bind_drawable(struct pipe_video_context *vpipe, Drawable drawable) |
| { |
| struct xsp_context *xsp_context; |
| Drawable old_drawable; |
| |
| assert(vpipe); |
| |
| xsp_context = vpipe->priv; |
| old_drawable = xsp_context->drawable; |
| xsp_context->drawable = drawable; |
| |
| return old_drawable; |
| } |
| |
| struct pipe_screen* |
| vl_screen_create(Display *display, int screen) |
| { |
| struct xsp_pipe_winsys *xsp_winsys; |
| |
| assert(display); |
| |
| xsp_winsys = CALLOC_STRUCT(xsp_pipe_winsys); |
| if (!xsp_winsys) |
| return NULL; |
| |
| xsp_winsys->base.buffer_create = xsp_buffer_create; |
| xsp_winsys->base.user_buffer_create = xsp_user_buffer_create; |
| xsp_winsys->base.buffer_map = xsp_buffer_map; |
| xsp_winsys->base.buffer_unmap = xsp_buffer_unmap; |
| xsp_winsys->base.buffer_destroy = xsp_buffer_destroy; |
| xsp_winsys->base.surface_buffer_create = xsp_surface_buffer_create; |
| xsp_winsys->base.fence_reference = xsp_fence_reference; |
| xsp_winsys->base.fence_signalled = xsp_fence_signalled; |
| xsp_winsys->base.fence_finish = xsp_fence_finish; |
| xsp_winsys->base.flush_frontbuffer = xsp_flush_frontbuffer; |
| xsp_winsys->base.get_name = xsp_get_name; |
| xsp_winsys->base.destroy = xsp_destroy; |
| xsp_winsys->display = display; |
| xsp_winsys->screen = screen; |
| xsp_winsys->fbimage = XCreateImage |
| ( |
| display, |
| XDefaultVisual(display, screen), |
| XDefaultDepth(display, screen), |
| ZPixmap, |
| 0, |
| NULL, |
| 0, /* Don't know the width and height until flush_frontbuffer */ |
| 0, |
| 32, |
| 0 |
| ); |
| |
| if (!xsp_winsys->fbimage) { |
| FREE(xsp_winsys); |
| return NULL; |
| } |
| |
| XInitImage(xsp_winsys->fbimage); |
| |
| return softpipe_create_screen(&xsp_winsys->base); |
| } |
| |
| struct pipe_video_context* |
| vl_video_create(Display *display, int screen, |
| struct pipe_screen *p_screen, |
| enum pipe_video_profile profile, |
| enum pipe_video_chroma_format chroma_format, |
| unsigned width, unsigned height) |
| { |
| struct pipe_video_context *vpipe; |
| struct xsp_context *xsp_context; |
| |
| assert(p_screen); |
| assert(width && height); |
| |
| vpipe = sp_video_create(p_screen, profile, chroma_format, width, height); |
| if (!vpipe) |
| return NULL; |
| |
| xsp_context = CALLOC_STRUCT(xsp_context); |
| if (!xsp_context) { |
| vpipe->destroy(vpipe); |
| return NULL; |
| } |
| |
| /* Override this so we can free our xsp_context when the pipe is freed */ |
| xsp_context->pipe_destroy = vpipe->destroy; |
| vpipe->destroy = xsp_pipe_destroy; |
| |
| vpipe->priv = xsp_context; |
| |
| return vpipe; |
| } |