/* * Copyright © 2008 Jérôme Glisse * 2009 Corbin Simpson * 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: * Jérôme Glisse * Corbin Simpson */ #include "radeon_buffer.h" #include "radeon_bo_gem.h" #include "softpipe/sp_texture.h" #include "r300_context.h" #include "util/u_format.h" #include "util/u_math.h" #include struct radeon_vl_context { Display *display; int screen; Drawable drawable; }; static const char *radeon_get_name(struct pipe_winsys *ws) { return "Radeon/GEM+KMS"; } static struct pipe_buffer *radeon_buffer_create(struct pipe_winsys *ws, unsigned alignment, unsigned usage, unsigned size) { struct radeon_winsys *radeon_ws = (struct radeon_winsys *)ws; struct radeon_pipe_buffer *radeon_buffer; uint32_t domain; radeon_buffer = CALLOC_STRUCT(radeon_pipe_buffer); if (radeon_buffer == NULL) { return NULL; } pipe_reference_init(&radeon_buffer->base.reference, 1); radeon_buffer->base.alignment = alignment; radeon_buffer->base.usage = usage; radeon_buffer->base.size = size; domain = 0; if (usage & PIPE_BUFFER_USAGE_PIXEL) { domain |= RADEON_GEM_DOMAIN_VRAM; } if (usage & PIPE_BUFFER_USAGE_VERTEX) { domain |= RADEON_GEM_DOMAIN_GTT; } if (usage & PIPE_BUFFER_USAGE_INDEX) { domain |= RADEON_GEM_DOMAIN_GTT; } radeon_buffer->bo = radeon_bo_open(radeon_ws->priv->bom, 0, size, alignment, domain, 0); if (radeon_buffer->bo == NULL) { FREE(radeon_buffer); return NULL; } return &radeon_buffer->base; } static struct pipe_buffer *radeon_buffer_user_create(struct pipe_winsys *ws, void *ptr, unsigned bytes) { struct radeon_pipe_buffer *radeon_buffer; radeon_buffer = (struct radeon_pipe_buffer*)radeon_buffer_create(ws, 0, 0, bytes); if (radeon_buffer == NULL) { return NULL; } radeon_bo_map(radeon_buffer->bo, 1); memcpy(radeon_buffer->bo->ptr, ptr, bytes); radeon_bo_unmap(radeon_buffer->bo); return &radeon_buffer->base; } static struct pipe_buffer *radeon_surface_buffer_create(struct pipe_winsys *ws, unsigned width, unsigned height, enum pipe_format format, unsigned usage, unsigned tex_usage, unsigned *stride) { /* Radeons enjoy things in multiples of 32. */ /* XXX this can be 32 when POT */ const unsigned alignment = 64; unsigned nblocksy, size; nblocksy = util_format_get_nblocksy(format, height); *stride = align(util_format_get_stride(format, width), alignment); size = *stride * nblocksy; return radeon_buffer_create(ws, 64, usage, size); } static void radeon_buffer_del(struct pipe_buffer *buffer) { struct radeon_pipe_buffer *radeon_buffer = (struct radeon_pipe_buffer*)buffer; radeon_bo_unref(radeon_buffer->bo); free(radeon_buffer); } static void *radeon_buffer_map(struct pipe_winsys *ws, struct pipe_buffer *buffer, unsigned flags) { struct radeon_winsys_priv *priv = ((struct radeon_winsys *)ws)->priv; struct radeon_pipe_buffer *radeon_buffer = (struct radeon_pipe_buffer*)buffer; int write = 0; if (radeon_bo_is_referenced_by_cs(radeon_buffer->bo, priv->cs)) { priv->flush_cb(priv->flush_data); } if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) { uint32_t domain; if (radeon_bo_is_busy(radeon_buffer->bo, &domain)) return NULL; } if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) { write = 1; } if (radeon_bo_map(radeon_buffer->bo, write)) { return NULL; } return radeon_buffer->bo->ptr; } static void radeon_buffer_unmap(struct pipe_winsys *ws, struct pipe_buffer *buffer) { struct radeon_pipe_buffer *radeon_buffer = (struct radeon_pipe_buffer*)buffer; radeon_bo_unmap(radeon_buffer->bo); } static void radeon_fence_reference(struct pipe_winsys *ws, struct pipe_fence_handle **ptr, struct pipe_fence_handle *pfence) { } static int radeon_fence_signalled(struct pipe_winsys *ws, struct pipe_fence_handle *pfence, unsigned flag) { return 1; } static int radeon_fence_finish(struct pipe_winsys *ws, struct pipe_fence_handle *pfence, unsigned flag) { return 0; } static void radeon_display_surface(struct pipe_winsys *pws, struct pipe_surface *psurf, struct radeon_vl_context *rvl_ctx) { struct r300_texture *r300tex = (struct r300_texture *)(psurf->texture); XImage *ximage; void *data; ximage = XCreateImage(rvl_ctx->display, XDefaultVisual(rvl_ctx->display, rvl_ctx->screen), XDefaultDepth(rvl_ctx->display, rvl_ctx->screen), ZPixmap, 0, /* format, offset */ NULL, /* data */ 0, 0, /* size */ 32, /* bitmap_pad */ 0); /* bytes_per_line */ assert(ximage->format); assert(ximage->bitmap_unit); data = pws->buffer_map(pws, r300tex->buffer, 0); /* update XImage's fields */ ximage->data = data; ximage->width = psurf->width; ximage->height = psurf->height; ximage->bytes_per_line = psurf->width * (ximage->bits_per_pixel >> 3); XPutImage(rvl_ctx->display, rvl_ctx->drawable, XDefaultGC(rvl_ctx->display, rvl_ctx->screen), ximage, 0, 0, 0, 0, psurf->width, psurf->height); XSync(rvl_ctx->display, 0); ximage->data = NULL; XDestroyImage(ximage); pws->buffer_unmap(pws, r300tex->buffer); } static void radeon_flush_frontbuffer(struct pipe_winsys *pipe_winsys, struct pipe_surface *pipe_surface, void *context_private) { struct radeon_vl_context *rvl_ctx; rvl_ctx = (struct radeon_vl_context *) context_private; radeon_display_surface(pipe_winsys, pipe_surface, rvl_ctx); } struct radeon_winsys* radeon_pipe_winsys(int fd) { struct radeon_winsys* radeon_ws; radeon_ws = CALLOC_STRUCT(radeon_winsys); if (radeon_ws == NULL) { return NULL; } radeon_ws->priv = CALLOC_STRUCT(radeon_winsys_priv); if (radeon_ws->priv == NULL) { FREE(radeon_ws); return NULL; } radeon_ws->priv->fd = fd; radeon_ws->priv->bom = radeon_bo_manager_gem_ctor(fd); radeon_ws->base.flush_frontbuffer = radeon_flush_frontbuffer; radeon_ws->base.buffer_create = radeon_buffer_create; radeon_ws->base.user_buffer_create = radeon_buffer_user_create; radeon_ws->base.surface_buffer_create = radeon_surface_buffer_create; radeon_ws->base.buffer_map = radeon_buffer_map; radeon_ws->base.buffer_unmap = radeon_buffer_unmap; radeon_ws->base.buffer_destroy = radeon_buffer_del; radeon_ws->base.fence_reference = radeon_fence_reference; radeon_ws->base.fence_signalled = radeon_fence_signalled; radeon_ws->base.fence_finish = radeon_fence_finish; radeon_ws->base.get_name = radeon_get_name; return radeon_ws; } #if 0 static struct pipe_buffer *radeon_buffer_from_handle(struct radeon_screen *radeon_screen, uint32_t handle) { struct radeon_pipe_buffer *radeon_buffer; struct radeon_bo *bo = NULL; bo = radeon_bo_open(radeon_screen->bom, handle, 0, 0, 0, 0); if (bo == NULL) { return NULL; } radeon_buffer = calloc(1, sizeof(struct radeon_pipe_buffer)); if (radeon_buffer == NULL) { radeon_bo_unref(bo); return NULL; } pipe_reference_init(&radeon_buffer->base.reference, 1); radeon_buffer->base.usage = PIPE_BUFFER_USAGE_PIXEL; radeon_buffer->bo = bo; return &radeon_buffer->base; } struct pipe_surface *radeon_surface_from_handle(struct radeon_context *radeon_context, uint32_t handle, enum pipe_format format, int w, int h, int pitch) { struct pipe_screen *pipe_screen = radeon_context->pipe_screen; struct pipe_winsys *pipe_winsys = radeon_context->pipe_winsys; struct pipe_texture tmpl; struct pipe_surface *ps; struct pipe_texture *pt; struct pipe_buffer *pb; pb = radeon_buffer_from_handle(radeon_context->radeon_screen, handle); if (pb == NULL) { return NULL; } memset(&tmpl, 0, sizeof(tmpl)); tmpl.tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET; tmpl.target = PIPE_TEXTURE_2D; tmpl.width0 = w; tmpl.height0 = h; tmpl.depth0 = 1; tmpl.format = format; pt = pipe_screen->texture_blanket(pipe_screen, &tmpl, &pitch, pb); if (pt == NULL) { pipe_buffer_reference(&pb, NULL); } ps = pipe_screen->get_tex_surface(pipe_screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE); return ps; } #endif