diff options
Diffstat (limited to 'src/gallium/winsys/radeon/drm')
-rw-r--r-- | src/gallium/winsys/radeon/drm/Makefile | 17 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/SConscript | 18 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_buffer.h | 86 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_drm.c | 200 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_drm.h | 66 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_drm_buffer.c | 385 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_r300.c | 348 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_r300.h | 30 | ||||
-rw-r--r-- | src/gallium/winsys/radeon/drm/radeon_winsys.h | 86 |
9 files changed, 1236 insertions, 0 deletions
diff --git a/src/gallium/winsys/radeon/drm/Makefile b/src/gallium/winsys/radeon/drm/Makefile new file mode 100644 index 00000000000..7f69e392735 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/Makefile @@ -0,0 +1,17 @@ + +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = radeonwinsys + +C_SOURCES = \ + radeon_drm_buffer.c \ + radeon_drm.c \ + radeon_r300.c + +LIBRARY_INCLUDES = -I$(TOP)/src/gallium/drivers/r300 \ + $(shell pkg-config libdrm --cflags-only-I) + +include ../../../Makefile.template + +symlinks: diff --git a/src/gallium/winsys/radeon/drm/SConscript b/src/gallium/winsys/radeon/drm/SConscript new file mode 100644 index 00000000000..f4e9c397bdf --- /dev/null +++ b/src/gallium/winsys/radeon/drm/SConscript @@ -0,0 +1,18 @@ +Import('*') + +env = drienv.Clone() + +radeon_sources = [ + 'radeon_buffer.c', + 'radeon_drm.c', + 'radeon_r300.c', +] + +env.Append(CPPPATH = '#/src/gallium/drivers/r300') + +radeonwinsys = env.ConvenienceLibrary( + target ='radeonwinsys', + source = radeon_sources, +) + +Export('radeonwinsys') diff --git a/src/gallium/winsys/radeon/drm/radeon_buffer.h b/src/gallium/winsys/radeon/drm/radeon_buffer.h new file mode 100644 index 00000000000..218a3763018 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_buffer.h @@ -0,0 +1,86 @@ +/* + * Copyright © 2008 Jérôme Glisse + * 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 <[email protected]> + */ +#ifndef RADEON_BUFFER_H +#define RADEON_BUFFER_H + +#include <stdio.h> + +#include "pipe/p_defines.h" +#include "util/u_inlines.h" + +#include "pipebuffer/pb_buffer.h" +#include "pipebuffer/pb_bufmgr.h" + +#include "radeon_bo.h" +#include "radeon_cs.h" + +#include "radeon_winsys.h" + + +#define RADEON_MAX_BOS 24 + +static INLINE struct pb_buffer * +radeon_pb_buffer(struct r300_winsys_buffer *buffer) +{ + return (struct pb_buffer *)buffer; +} + +static INLINE struct r300_winsys_buffer * +radeon_libdrm_winsys_buffer(struct pb_buffer *buffer) +{ + return (struct r300_winsys_buffer *)buffer; +} + +struct pb_manager * +radeon_drm_bufmgr_create(struct radeon_libdrm_winsys *rws); + +boolean radeon_drm_bufmgr_add_buffer(struct pb_buffer *_buf, + uint32_t rd, uint32_t wd); + + +void radeon_drm_bufmgr_write_reloc(struct pb_buffer *_buf, + uint32_t rd, uint32_t wd, + uint32_t flags); + +struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr, + uint32_t handle); + +void radeon_drm_bufmgr_set_tiling(struct pb_buffer *_buf, + enum r300_buffer_tiling microtiled, + enum r300_buffer_tiling macrotiled, + uint32_t pitch); + +void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr); + +boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf, + struct winsys_handle *whandle); + +boolean radeon_drm_bufmgr_is_buffer_referenced(struct pb_buffer *_buf); +#endif diff --git a/src/gallium/winsys/radeon/drm/radeon_drm.c b/src/gallium/winsys/radeon/drm/radeon_drm.c new file mode 100644 index 00000000000..3dfcc5aef07 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_drm.c @@ -0,0 +1,200 @@ +/* + * Copyright © 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: + * Corbin Simpson <[email protected]> + * Joakim Sindholt <[email protected]> + */ + +#include "radeon_drm.h" +#include "radeon_r300.h" +#include "radeon_buffer.h" + +#include "r300_winsys.h" +#include "trace/tr_drm.h" + +#include "util/u_memory.h" + +#include "xf86drm.h" +#include <sys/ioctl.h> + +static struct radeon_libdrm_winsys * +radeon_winsys_create(int fd) +{ + struct radeon_libdrm_winsys *rws; + + rws = CALLOC_STRUCT(radeon_libdrm_winsys); + if (rws == NULL) { + return NULL; + } + + rws->fd = fd; + return rws; +} + +/* Helper function to do the ioctls needed for setup and init. */ +static void do_ioctls(int fd, struct radeon_libdrm_winsys* winsys) +{ + struct drm_radeon_gem_info gem_info = {0}; + struct drm_radeon_info info = {0}; + int target = 0; + int retval; + drmVersionPtr version; + + info.value = (unsigned long)⌖ + + /* We do things in a specific order here. + * + * DRM version first. We need to be sure we're running on a KMS chipset. + * This is also for some features. + * + * Then, the PCI ID. This is essential and should return usable numbers + * for all Radeons. If this fails, we probably got handed an FD for some + * non-Radeon card. + * + * The GB and Z pipe requests should always succeed, but they might not + * return sensical values for all chipsets, but that's alright because + * the pipe drivers already know that. + * + * The GEM info is actually bogus on the kernel side, as well as our side + * (see radeon_gem_info_ioctl in radeon_gem.c) but that's alright because + * we don't actually use the info for anything yet. */ + + version = drmGetVersion(fd); + if (version->version_major != 2) { + fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " + "only compatible with 2.x.x\n", __FUNCTION__, + version->version_major, version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + exit(1); + } + +/* XXX Remove this ifdef when libdrm version 2.4.19 becomes mandatory. */ +#ifdef RADEON_BO_FLAGS_MICRO_TILE_SQUARE + // Supported since 2.1.0. + winsys->squaretiling = version->version_major > 2 || + version->version_minor >= 1; +#endif + + info.request = RADEON_INFO_DEVICE_ID; + retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); + if (retval) { + fprintf(stderr, "%s: Failed to get PCI ID, " + "error number %d\n", __FUNCTION__, retval); + exit(1); + } + winsys->pci_id = target; + + info.request = RADEON_INFO_NUM_GB_PIPES; + retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); + if (retval) { + fprintf(stderr, "%s: Failed to get GB pipe count, " + "error number %d\n", __FUNCTION__, retval); + exit(1); + } + winsys->gb_pipes = target; + + info.request = RADEON_INFO_NUM_Z_PIPES; + retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); + if (retval) { + fprintf(stderr, "%s: Failed to get Z pipe count, " + "error number %d\n", __FUNCTION__, retval); + exit(1); + } + winsys->z_pipes = target; + + retval = drmCommandWriteRead(fd, DRM_RADEON_GEM_INFO, + &gem_info, sizeof(gem_info)); + if (retval) { + fprintf(stderr, "%s: Failed to get MM info, error number %d\n", + __FUNCTION__, retval); + exit(1); + } + winsys->gart_size = gem_info.gart_size; + winsys->vram_size = gem_info.vram_size; + + debug_printf("radeon: Successfully grabbed chipset info from kernel!\n" + "radeon: DRM version: %d.%d.%d ID: 0x%04x GB: %d Z: %d\n" + "radeon: GART size: %d MB VRAM size: %d MB\n", + version->version_major, version->version_minor, + version->version_patchlevel, winsys->pci_id, + winsys->gb_pipes, winsys->z_pipes, + winsys->gart_size / 1024 / 1024, + winsys->vram_size / 1024 / 1024); + + drmFreeVersion(version); +} + +/* Create a pipe_screen. */ +struct pipe_screen* radeon_create_screen(struct drm_api* api, + int drmFB, + struct drm_create_screen_arg *arg) +{ + struct radeon_libdrm_winsys* rws; + boolean ret; + + rws = radeon_winsys_create(drmFB); + if (!rws) + return NULL; + + do_ioctls(drmFB, rws); + + /* The state tracker can organize a softpipe fallback if no hw + * driver is found. + */ + if (is_r3xx(rws->pci_id)) { + ret = radeon_setup_winsys(drmFB, rws); + if (ret == FALSE) + goto fail; + return r300_create_screen(&rws->base); + } + +fail: + FREE(rws); + return NULL; +} + +static void radeon_drm_api_destroy(struct drm_api *api) +{ + return; +} + +struct drm_api drm_api_hooks = { + .name = "radeon", + .driver_name = "radeon", + .create_screen = radeon_create_screen, + .destroy = radeon_drm_api_destroy, +}; + +struct drm_api* drm_api_create() +{ +#ifdef DEBUG + return trace_drm_create(&drm_api_hooks); +#else + return &drm_api_hooks; +#endif +} diff --git a/src/gallium/winsys/radeon/drm/radeon_drm.h b/src/gallium/winsys/radeon/drm/radeon_drm.h new file mode 100644 index 00000000000..2dc077c0521 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_drm.h @@ -0,0 +1,66 @@ +/* + * Copyright © 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: + * Corbin Simpson <[email protected]> + */ +#ifndef RADEON_DRM_H +#define RADEON_DRM_H + +#include "state_tracker/drm_api.h" + + +struct pipe_screen* radeon_create_screen(struct drm_api* api, + int drmFB, + struct drm_create_screen_arg *arg); + +boolean radeon_buffer_from_texture(struct drm_api* api, + struct pipe_screen* screen, + struct pipe_texture* texture, + struct pipe_buffer** buffer, + unsigned* stride); + +boolean radeon_handle_from_buffer(struct drm_api* api, + struct pipe_screen* screen, + struct pipe_buffer* buffer, + unsigned* handle); + +boolean radeon_global_handle_from_buffer(struct drm_api* api, + struct pipe_screen* screen, + struct pipe_buffer* buffer, + unsigned* handle); + +void radeon_destroy_drm_api(struct drm_api* api); + +/* Guess at whether this chipset should use r300g. + * + * I believe that this check is valid, but I haven't been exhaustive. */ +static INLINE boolean is_r3xx(int pciid) +{ + return (pciid > 0x3150) && (pciid < 0x796f); +} + +#endif diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c b/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c new file mode 100644 index 00000000000..66f61322457 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c @@ -0,0 +1,385 @@ + +#include <sys/ioctl.h> +#include "radeon_drm.h" +#include "radeon_bo_gem.h" +#include "radeon_cs_gem.h" +#include "radeon_buffer.h" + +#include "util/u_inlines.h" +#include "util/u_memory.h" +#include "util/u_simple_list.h" +#include "pipebuffer/pb_buffer.h" +#include "pipebuffer/pb_bufmgr.h" + +#include "radeon_winsys.h" +struct radeon_drm_bufmgr; + +struct radeon_drm_buffer { + struct pb_buffer base; + struct radeon_drm_bufmgr *mgr; + + struct radeon_bo *bo; + + boolean flinked; + uint32_t flink; + + struct radeon_drm_buffer *next, *prev; +}; + +extern const struct pb_vtbl radeon_drm_buffer_vtbl; + + +static INLINE struct radeon_drm_buffer * +radeon_drm_buffer(struct pb_buffer *buf) +{ + assert(buf); + assert(buf->vtbl == &radeon_drm_buffer_vtbl); + return (struct radeon_drm_buffer *)buf; +} + +struct radeon_drm_bufmgr { + struct pb_manager base; + struct radeon_libdrm_winsys *rws; + struct radeon_drm_buffer buffer_map_list; +}; + +static INLINE struct radeon_drm_bufmgr * +radeon_drm_bufmgr(struct pb_manager *mgr) +{ + assert(mgr); + return (struct radeon_drm_bufmgr *)mgr; +} + +static void +radeon_drm_buffer_destroy(struct pb_buffer *_buf) +{ + struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf); + + if (buf->bo->ptr != NULL) { + remove_from_list(buf); + radeon_bo_unmap(buf->bo); + buf->bo->ptr = NULL; + } + radeon_bo_unref(buf->bo); + + FREE(buf); +} + +static void * +radeon_drm_buffer_map(struct pb_buffer *_buf, + unsigned flags) +{ + struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf); + int write = 0; + + if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) { + if ((_buf->base.usage & PIPE_BUFFER_USAGE_VERTEX) || + (_buf->base.usage & PIPE_BUFFER_USAGE_INDEX)) + if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs)) + return NULL; + } + + if (buf->bo->ptr != NULL) + return buf->bo->ptr; + + if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) { + uint32_t domain; + if (radeon_bo_is_busy(buf->bo, &domain)) + return NULL; + } + + if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs)) { + buf->mgr->rws->flush_cb(buf->mgr->rws->flush_data); + } + + if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) { + write = 1; + } + + if (radeon_bo_map(buf->bo, write)) { + return NULL; + } + insert_at_tail(&buf->mgr->buffer_map_list, buf); + return buf->bo->ptr; +} + +static void +radeon_drm_buffer_unmap(struct pb_buffer *_buf) +{ + (void)_buf; +} + +static void +radeon_drm_buffer_get_base_buffer(struct pb_buffer *buf, + struct pb_buffer **base_buf, + unsigned *offset) +{ + *base_buf = buf; + *offset = 0; +} + + +static enum pipe_error +radeon_drm_buffer_validate(struct pb_buffer *_buf, + struct pb_validate *vl, + unsigned flags) +{ + /* Always pinned */ + return PIPE_OK; +} + +static void +radeon_drm_buffer_fence(struct pb_buffer *buf, + struct pipe_fence_handle *fence) +{ +} + +const struct pb_vtbl radeon_drm_buffer_vtbl = { + radeon_drm_buffer_destroy, + radeon_drm_buffer_map, + radeon_drm_buffer_unmap, + radeon_drm_buffer_validate, + radeon_drm_buffer_fence, + radeon_drm_buffer_get_base_buffer, +}; + + +static uint32_t radeon_domain_from_usage(unsigned usage) +{ + uint32_t domain = 0; + + if (usage & PIPE_BUFFER_USAGE_GPU_WRITE) { + domain |= RADEON_GEM_DOMAIN_VRAM; + } + 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; + } + + return domain; +} + +struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr, + uint32_t handle) +{ + struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr); + struct radeon_libdrm_winsys *rws = mgr->rws; + struct radeon_drm_buffer *buf; + struct radeon_bo *bo; + + bo = radeon_bo_open(rws->bom, handle, 0, + 0, 0, 0); + if (bo == NULL) + return NULL; + + buf = CALLOC_STRUCT(radeon_drm_buffer); + if (!buf) { + radeon_bo_unref(bo); + return NULL; + } + + make_empty_list(buf); + + pipe_reference_init(&buf->base.base.reference, 1); + buf->base.base.alignment = 0; + buf->base.base.usage = PIPE_BUFFER_USAGE_PIXEL; + buf->base.base.size = 0; + buf->base.vtbl = &radeon_drm_buffer_vtbl; + buf->mgr = mgr; + + buf->bo = bo; + + return &buf->base; +} + +static struct pb_buffer * +radeon_drm_bufmgr_create_buffer(struct pb_manager *_mgr, + pb_size size, + const struct pb_desc *desc) +{ + struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr); + struct radeon_libdrm_winsys *rws = mgr->rws; + struct radeon_drm_buffer *buf; + uint32_t domain; + + buf = CALLOC_STRUCT(radeon_drm_buffer); + if (!buf) + goto error1; + + pipe_reference_init(&buf->base.base.reference, 1); + buf->base.base.alignment = desc->alignment; + buf->base.base.usage = desc->usage; + buf->base.base.size = size; + buf->base.vtbl = &radeon_drm_buffer_vtbl; + buf->mgr = mgr; + + make_empty_list(buf); + domain = radeon_domain_from_usage(desc->usage); + buf->bo = radeon_bo_open(rws->bom, 0, size, + desc->alignment, domain, 0); + if (buf->bo == NULL) + goto error2; + + return &buf->base; + + error2: + FREE(buf); + error1: + return NULL; +} + +static void +radeon_drm_bufmgr_flush(struct pb_manager *mgr) +{ + /* NOP */ +} + +static void +radeon_drm_bufmgr_destroy(struct pb_manager *_mgr) +{ + struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr); + FREE(mgr); +} + +struct pb_manager * +radeon_drm_bufmgr_create(struct radeon_libdrm_winsys *rws) +{ + struct radeon_drm_bufmgr *mgr; + + mgr = CALLOC_STRUCT(radeon_drm_bufmgr); + if (!mgr) + return NULL; + + mgr->base.destroy = radeon_drm_bufmgr_destroy; + mgr->base.create_buffer = radeon_drm_bufmgr_create_buffer; + mgr->base.flush = radeon_drm_bufmgr_flush; + + mgr->rws = rws; + make_empty_list(&mgr->buffer_map_list); + return &mgr->base; +} + +static struct radeon_drm_buffer *get_drm_buffer(struct pb_buffer *_buf) +{ + struct radeon_drm_buffer *buf; + if (_buf->vtbl == &radeon_drm_buffer_vtbl) { + buf = radeon_drm_buffer(_buf); + } else { + struct pb_buffer *base_buf; + pb_size offset; + pb_get_base_buffer(_buf, &base_buf, &offset); + + buf = radeon_drm_buffer(base_buf); + } + return buf; +} + +boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf, + struct winsys_handle *whandle) +{ + int retval, fd; + struct drm_gem_flink flink; + struct radeon_drm_buffer *buf = get_drm_buffer(_buf); + if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { + if (!buf->flinked) { + fd = buf->mgr->rws->fd; + flink.handle = buf->bo->handle; + + retval = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + if (retval) { + return FALSE; + } + + buf->flinked = TRUE; + buf->flink = flink.name; + } + whandle->handle = buf->flink; + } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) { + whandle->handle = buf->bo->handle; + } + return TRUE; +} + + +void radeon_drm_bufmgr_set_tiling(struct pb_buffer *_buf, + enum r300_buffer_tiling microtiled, + enum r300_buffer_tiling macrotiled, + uint32_t pitch) +{ + struct radeon_drm_buffer *buf = get_drm_buffer(_buf); + uint32_t flags = 0, old_flags, old_pitch; + if (microtiled == R300_BUFFER_TILED) + flags |= RADEON_BO_FLAGS_MICRO_TILE; +/* XXX Remove this ifdef when libdrm version 2.4.19 becomes mandatory. */ +#ifdef RADEON_BO_FLAGS_MICRO_TILE_SQUARE + else if (microtiled == R300_BUFFER_SQUARETILED) + flags |= RADEON_BO_FLAGS_MICRO_TILE_SQUARE; +#endif + if (macrotiled == R300_BUFFER_TILED) + flags |= RADEON_BO_FLAGS_MACRO_TILE; + + radeon_bo_get_tiling(buf->bo, &old_flags, &old_pitch); + + if (flags != old_flags || pitch != old_pitch) { + /* Tiling determines how DRM treats the buffer data. + * We must flush CS when changing it if the buffer is referenced. */ + if (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs)) { + buf->mgr->rws->flush_cb(buf->mgr->rws->flush_data); + } + } + radeon_bo_set_tiling(buf->bo, flags, pitch); + +} + +boolean radeon_drm_bufmgr_add_buffer(struct pb_buffer *_buf, + uint32_t rd, uint32_t wd) +{ + struct radeon_drm_buffer *buf = get_drm_buffer(_buf); + radeon_cs_space_add_persistent_bo(buf->mgr->rws->cs, buf->bo, + rd, wd); + return TRUE; +} + +void radeon_drm_bufmgr_write_reloc(struct pb_buffer *_buf, + uint32_t rd, uint32_t wd, + uint32_t flags) +{ + struct radeon_drm_buffer *buf = get_drm_buffer(_buf); + int retval; + + retval = radeon_cs_write_reloc(buf->mgr->rws->cs, + buf->bo, rd, wd, flags); + if (retval) { + debug_printf("radeon: Relocation of %p (%d, %d, %d) failed!\n", + buf, rd, wd, flags); + } +} + +boolean radeon_drm_bufmgr_is_buffer_referenced(struct pb_buffer *_buf) +{ + struct radeon_drm_buffer *buf = get_drm_buffer(_buf); + uint32_t domain; + + return (radeon_bo_is_referenced_by_cs(buf->bo, buf->mgr->rws->cs) || + radeon_bo_is_busy(buf->bo, &domain)); +} + + +void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr) +{ + struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr); + struct radeon_drm_buffer *rpb, *t_rpb; + + foreach_s(rpb, t_rpb, &mgr->buffer_map_list) { + radeon_bo_unmap(rpb->bo); + rpb->bo->ptr = NULL; + remove_from_list(rpb); + } + + make_empty_list(&mgr->buffer_map_list); +} diff --git a/src/gallium/winsys/radeon/drm/radeon_r300.c b/src/gallium/winsys/radeon/drm/radeon_r300.c new file mode 100644 index 00000000000..38fcf889c8b --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_r300.c @@ -0,0 +1,348 @@ +/* + * Copyright 2008 Corbin Simpson <[email protected]> + * + * 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 + * on 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 + * THE AUTHOR(S) AND/OR THEIR 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 "radeon_r300.h" +#include "radeon_buffer.h" + +#include "radeon_bo_gem.h" +#include "radeon_cs_gem.h" +#include "state_tracker/drm_api.h" + +static struct r300_winsys_buffer * +radeon_r300_winsys_buffer_create(struct r300_winsys_screen *rws, + unsigned alignment, + unsigned usage, + unsigned size) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + struct pb_desc desc; + struct pb_manager *provider; + struct pb_buffer *buffer; + + memset(&desc, 0, sizeof(desc)); + desc.alignment = alignment; + desc.usage = usage; + + if (usage & PIPE_BUFFER_USAGE_CONSTANT) + provider = ws->mman; + else if ((usage & PIPE_BUFFER_USAGE_VERTEX) || + (usage & PIPE_BUFFER_USAGE_INDEX)) + provider = ws->cman; + else + provider = ws->kman; + buffer = provider->create_buffer(provider, size, &desc); + if (!buffer) + return NULL; + + return radeon_libdrm_winsys_buffer(buffer); +} + +static void radeon_r300_winsys_buffer_destroy(struct r300_winsys_buffer *buf) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + + pb_destroy(_buf); +} +static void radeon_r300_winsys_buffer_set_tiling(struct r300_winsys_screen *rws, + struct r300_winsys_buffer *buf, + uint32_t pitch, + enum r300_buffer_tiling microtiled, + enum r300_buffer_tiling macrotiled) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + radeon_drm_bufmgr_set_tiling(_buf, microtiled, macrotiled, pitch); +} + +static void *radeon_r300_winsys_buffer_map(struct r300_winsys_screen *ws, + struct r300_winsys_buffer *buf, + unsigned usage) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + + return pb_map(_buf, usage); +} + +static void radeon_r300_winsys_buffer_unmap(struct r300_winsys_screen *ws, + struct r300_winsys_buffer *buf) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + + pb_unmap(_buf); +} + +static void radeon_r300_winsys_buffer_reference(struct r300_winsys_screen *rws, + struct r300_winsys_buffer **pdst, + struct r300_winsys_buffer *src) +{ + struct pb_buffer *_src = radeon_pb_buffer(src); + struct pb_buffer *_dst = radeon_pb_buffer(*pdst); + + pb_reference(&_dst, _src); + + *pdst = radeon_libdrm_winsys_buffer(_dst); +} + +static boolean radeon_r300_winsys_is_buffer_referenced(struct r300_winsys_screen *rws, + struct r300_winsys_buffer *buf) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + + return radeon_drm_bufmgr_is_buffer_referenced(_buf); +} + +static struct r300_winsys_buffer *radeon_r300_winsys_buffer_from_handle(struct r300_winsys_screen *rws, + struct pipe_screen *screen, + struct winsys_handle *whandle, + unsigned *stride) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + struct pb_buffer *_buf; + + _buf = radeon_drm_bufmgr_create_buffer_from_handle(ws->kman, whandle->handle); + *stride = whandle->stride; + return radeon_libdrm_winsys_buffer(_buf); +} + +static boolean radeon_r300_winsys_buffer_get_handle(struct r300_winsys_screen *rws, + struct r300_winsys_buffer *buffer, + unsigned stride, + struct winsys_handle *whandle) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buffer); + boolean ret; + ret = radeon_drm_bufmgr_get_handle(_buf, whandle); + if (ret) + whandle->stride = stride; + return ret; +} + +static void radeon_set_flush_cb(struct r300_winsys_screen *rws, + void (*flush_cb)(void *), + void *data) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + ws->flush_cb = flush_cb; + ws->flush_data = data; + radeon_cs_space_set_flush(ws->cs, flush_cb, data); +} + +static boolean radeon_add_buffer(struct r300_winsys_screen *rws, + struct r300_winsys_buffer *buf, + uint32_t rd, + uint32_t wd) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + + return radeon_drm_bufmgr_add_buffer(_buf, rd, wd); +} + +static boolean radeon_validate(struct r300_winsys_screen *rws) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + if (radeon_cs_space_check(ws->cs) < 0) { + return FALSE; + } + + /* Things are fine, we can proceed as normal. */ + return TRUE; +} + +static boolean radeon_check_cs(struct r300_winsys_screen *rws, int size) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + struct radeon_cs *cs = ws->cs; + + return radeon_validate(rws) && cs->cdw + size <= cs->ndw; +} + +static void radeon_begin_cs(struct r300_winsys_screen *rws, + int size, + const char* file, + const char* function, + int line) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + radeon_cs_begin(ws->cs, size, file, function, line); +} + +static void radeon_write_cs_dword(struct r300_winsys_screen *rws, + uint32_t dword) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + radeon_cs_write_dword(ws->cs, dword); +} + +static void radeon_write_cs_reloc(struct r300_winsys_screen *rws, + struct r300_winsys_buffer *buf, + uint32_t rd, + uint32_t wd, + uint32_t flags) +{ + struct pb_buffer *_buf = radeon_pb_buffer(buf); + radeon_drm_bufmgr_write_reloc(_buf, rd, wd, flags); +} + +static void radeon_reset_bos(struct r300_winsys_screen *rws) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + radeon_cs_space_reset_bos(ws->cs); +} + +static void radeon_end_cs(struct r300_winsys_screen *rws, + const char* file, + const char* function, + int line) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + radeon_cs_end(ws->cs, file, function, line); +} + +static void radeon_flush_cs(struct r300_winsys_screen *rws) +{ + struct radeon_libdrm_winsys *ws = radeon_winsys_screen(rws); + int retval; + + /* Don't flush a zero-sized CS. */ + if (!ws->cs->cdw) { + return; + } + + radeon_drm_bufmgr_flush_maps(ws->kman); + /* Emit the CS. */ + retval = radeon_cs_emit(ws->cs); + if (retval) { + debug_printf("radeon: Bad CS, dumping...\n"); + radeon_cs_print(ws->cs, stderr); + } + + /* Reset CS. + * Someday, when we care about performance, we should really find a way + * to rotate between two or three CS objects so that the GPU can be + * spinning through one CS while another one is being filled. */ + radeon_cs_erase(ws->cs); +} + +static uint32_t radeon_get_value(struct r300_winsys_screen *rws, + enum r300_value_id id) +{ + struct radeon_libdrm_winsys *ws = (struct radeon_libdrm_winsys *)rws; + + switch(id) { + case R300_VID_PCI_ID: + return ws->pci_id; + case R300_VID_GB_PIPES: + return ws->gb_pipes; + case R300_VID_Z_PIPES: + return ws->z_pipes; + case R300_VID_SQUARE_TILING_SUPPORT: + return ws->squaretiling; + } + return 0; +} + +static void +radeon_winsys_destroy(struct r300_winsys_screen *rws) +{ + struct radeon_libdrm_winsys *ws = (struct radeon_libdrm_winsys *)rws; + radeon_cs_destroy(ws->cs); + + ws->cman->destroy(ws->cman); + ws->kman->destroy(ws->kman); + ws->mman->destroy(ws->mman); + + radeon_bo_manager_gem_dtor(ws->bom); + radeon_cs_manager_gem_dtor(ws->csm); +} + +boolean +radeon_setup_winsys(int fd, struct radeon_libdrm_winsys* ws) +{ + + ws->csm = radeon_cs_manager_gem_ctor(fd); + if (!ws->csm) + goto fail; + ws->bom = radeon_bo_manager_gem_ctor(fd); + if (!ws->bom) + goto fail; + ws->kman = radeon_drm_bufmgr_create(ws); + if (!ws->kman) + goto fail; + + ws->cman = pb_cache_manager_create(ws->kman, 100000); + if (!ws->cman) + goto fail; + + ws->mman = pb_malloc_bufmgr_create(); + if (!ws->mman) + goto fail; + + /* Size limit on IBs is 64 kibibytes. */ + ws->cs = radeon_cs_create(ws->csm, 1024 * 64 / 4); + if (!ws->cs) + goto fail; + radeon_cs_set_limit(ws->cs, + RADEON_GEM_DOMAIN_GTT, ws->gart_size); + radeon_cs_set_limit(ws->cs, + RADEON_GEM_DOMAIN_VRAM, ws->vram_size); + + ws->base.add_buffer = radeon_add_buffer; + ws->base.validate = radeon_validate; + ws->base.destroy = radeon_winsys_destroy; + ws->base.check_cs = radeon_check_cs; + ws->base.begin_cs = radeon_begin_cs; + ws->base.write_cs_dword = radeon_write_cs_dword; + ws->base.write_cs_reloc = radeon_write_cs_reloc; + ws->base.end_cs = radeon_end_cs; + ws->base.flush_cs = radeon_flush_cs; + ws->base.reset_bos = radeon_reset_bos; + ws->base.set_flush_cb = radeon_set_flush_cb; + ws->base.get_value = radeon_get_value; + + ws->base.buffer_create = radeon_r300_winsys_buffer_create; + ws->base.buffer_destroy = radeon_r300_winsys_buffer_destroy; + ws->base.buffer_set_tiling = radeon_r300_winsys_buffer_set_tiling; + ws->base.buffer_map = radeon_r300_winsys_buffer_map; + ws->base.buffer_unmap = radeon_r300_winsys_buffer_unmap; + ws->base.buffer_reference = radeon_r300_winsys_buffer_reference; + ws->base.buffer_from_handle = radeon_r300_winsys_buffer_from_handle; + ws->base.buffer_get_handle = radeon_r300_winsys_buffer_get_handle; + ws->base.is_buffer_referenced = radeon_r300_winsys_is_buffer_referenced; + return TRUE; + +fail: + if (ws->csm) + radeon_cs_manager_gem_dtor(ws->csm); + + if (ws->bom) + radeon_bo_manager_gem_dtor(ws->bom); + + if (ws->cman) + ws->cman->destroy(ws->cman); + if (ws->kman) + ws->kman->destroy(ws->kman); + if (ws->mman) + ws->mman->destroy(ws->mman); + + if (ws->cs) + radeon_cs_destroy(ws->cs); + return FALSE; +} diff --git a/src/gallium/winsys/radeon/drm/radeon_r300.h b/src/gallium/winsys/radeon/drm/radeon_r300.h new file mode 100644 index 00000000000..2703464ad8f --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_r300.h @@ -0,0 +1,30 @@ +/* + * Copyright 2008 Corbin Simpson <[email protected]> + * + * 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 + * on 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 + * THE AUTHOR(S) AND/OR THEIR 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. */ + +#ifndef RADEON_R300_H +#define RADEON_R300_H + +#include "radeon_winsys.h" + +boolean radeon_setup_winsys(int fd, struct radeon_libdrm_winsys* winsys); + +#endif /* RADEON_R300_H */ diff --git a/src/gallium/winsys/radeon/drm/radeon_winsys.h b/src/gallium/winsys/radeon/drm/radeon_winsys.h new file mode 100644 index 00000000000..4260dbaad72 --- /dev/null +++ b/src/gallium/winsys/radeon/drm/radeon_winsys.h @@ -0,0 +1,86 @@ +/* + * Copyright © 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: + * Corbin Simpson <[email protected]> + */ +#ifndef RADEON_WINSYS_H +#define RADEON_WINSYS_H + +#include "r300_winsys.h" + +struct radeon_libdrm_winsys { + /* Parent class. */ + struct r300_winsys_screen base; + + struct pb_manager *kman; + + struct pb_manager *cman; + + struct pb_manager *mman; + + /* PCI ID */ + uint32_t pci_id; + + /* GB pipe count */ + uint32_t gb_pipes; + + /* Z pipe count (rv530 only) */ + uint32_t z_pipes; + + /* GART size. */ + uint32_t gart_size; + + /* VRAM size. */ + uint32_t vram_size; + + /* Square tiling support. */ + boolean squaretiling; + + /* DRM FD */ + int fd; + + /* Radeon BO manager. */ + struct radeon_bo_manager *bom; + + /* Radeon CS manager. */ + struct radeon_cs_manager *csm; + + /* Current CS. */ + struct radeon_cs *cs; + + /* Flush CB */ + void (*flush_cb)(void *); + void *flush_data; +}; + +static INLINE struct radeon_libdrm_winsys * +radeon_winsys_screen(struct r300_winsys_screen *base) +{ + return (struct radeon_libdrm_winsys *)base; +} + +#endif |