From 4f57abfe66091281c9f59c14e6ea27b524b55d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 17 Nov 2009 11:14:54 -0500 Subject: Move libdrm/ up one level --- radeon/Makefile.am | 54 ++++++ radeon/libdrm_radeon.pc.in | 10 + radeon/radeon_bo.h | 215 +++++++++++++++++++++ radeon/radeon_bo_gem.c | 343 +++++++++++++++++++++++++++++++++ radeon/radeon_bo_gem.h | 43 +++++ radeon/radeon_cs.h | 246 ++++++++++++++++++++++++ radeon/radeon_cs_gem.c | 458 +++++++++++++++++++++++++++++++++++++++++++++ radeon/radeon_cs_gem.h | 41 ++++ radeon/radeon_cs_space.c | 234 +++++++++++++++++++++++ radeon/radeon_track.c | 141 ++++++++++++++ radeon/radeon_track.h | 64 +++++++ 11 files changed, 1849 insertions(+) create mode 100644 radeon/Makefile.am create mode 100644 radeon/libdrm_radeon.pc.in create mode 100644 radeon/radeon_bo.h create mode 100644 radeon/radeon_bo_gem.c create mode 100644 radeon/radeon_bo_gem.h create mode 100644 radeon/radeon_cs.h create mode 100644 radeon/radeon_cs_gem.c create mode 100644 radeon/radeon_cs_gem.h create mode 100644 radeon/radeon_cs_space.c create mode 100644 radeon/radeon_track.c create mode 100644 radeon/radeon_track.h (limited to 'radeon') diff --git a/radeon/Makefile.am b/radeon/Makefile.am new file mode 100644 index 00000000..dd136b1f --- /dev/null +++ b/radeon/Makefile.am @@ -0,0 +1,54 @@ +# Copyright © 2008 Jérôme Glisse +# +# 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, sublicense, +# 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 NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS 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. +# +# Authors: +# Jérôme Glisse + +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/radeon \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/include/drm + +libdrm_radeon_la_LTLIBRARIES = libdrm_radeon.la +libdrm_radeon_ladir = $(libdir) +libdrm_radeon_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ + +libdrm_radeon_la_SOURCES = \ + radeon_bo_gem.c \ + radeon_cs_gem.c \ + radeon_cs_space.c \ + radeon_track.c + +libdrm_radeonincludedir = ${includedir}/drm +libdrm_radeoninclude_HEADERS = \ + radeon_bo.h \ + radeon_cs.h \ + radeon_bo_gem.h \ + radeon_cs_gem.h \ + radeon_track.h + +pkgconfigdir = @pkgconfigdir@ +pkgconfig_DATA = libdrm_radeon.pc + +EXTRA_DIST = libdrm_radeon.pc.in diff --git a/radeon/libdrm_radeon.pc.in b/radeon/libdrm_radeon.pc.in new file mode 100644 index 00000000..33068448 --- /dev/null +++ b/radeon/libdrm_radeon.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_radeon +Description: Userspace interface to kernel DRM services for radeon +Version: 1.0.1 +Libs: -L${libdir} -ldrm_radeon +Cflags: -I${includedir} -I${includedir}/drm diff --git a/radeon/radeon_bo.h b/radeon/radeon_bo.h new file mode 100644 index 00000000..1e2e6c20 --- /dev/null +++ b/radeon/radeon_bo.h @@ -0,0 +1,215 @@ +/* + * 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 + */ +#ifndef RADEON_BO_H +#define RADEON_BO_H + +#include +#include +#include "radeon_track.h" + +/* bo object */ +#define RADEON_BO_FLAGS_MACRO_TILE 1 +#define RADEON_BO_FLAGS_MICRO_TILE 2 + +struct radeon_bo_manager; + +struct radeon_bo { + uint32_t alignment; + uint32_t handle; + uint32_t size; + uint32_t domains; + uint32_t flags; + unsigned cref; +#ifdef RADEON_BO_TRACK + struct radeon_track *track; +#endif + void *ptr; + struct radeon_bo_manager *bom; + uint32_t space_accounted; +}; + +/* bo functions */ +struct radeon_bo_funcs { + struct radeon_bo *(*bo_open)(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags); + void (*bo_ref)(struct radeon_bo *bo); + struct radeon_bo *(*bo_unref)(struct radeon_bo *bo); + int (*bo_map)(struct radeon_bo *bo, int write); + int (*bo_unmap)(struct radeon_bo *bo); + int (*bo_wait)(struct radeon_bo *bo); + int (*bo_is_static)(struct radeon_bo *bo); + int (*bo_set_tiling)(struct radeon_bo *bo, uint32_t tiling_flags, + uint32_t pitch); + int (*bo_get_tiling)(struct radeon_bo *bo, uint32_t *tiling_flags, + uint32_t *pitch); + int (*bo_is_busy)(struct radeon_bo *bo, uint32_t *domain); +}; + +struct radeon_bo_manager { + struct radeon_bo_funcs *funcs; + int fd; + struct radeon_tracker tracker; +}; + +static inline void _radeon_bo_debug(struct radeon_bo *bo, + const char *op, + const char *file, + const char *func, + int line) +{ + fprintf(stderr, "%s %p 0x%08X 0x%08X 0x%08X [%s %s %d]\n", + op, bo, bo->handle, bo->size, bo->cref, file, func, line); +} + +static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags, + const char *file, + const char *func, + int line) +{ + struct radeon_bo *bo; + + bo = bom->funcs->bo_open(bom, handle, size, alignment, domains, flags); +#ifdef RADEON_BO_TRACK + if (bo) { + bo->track = radeon_tracker_add_track(&bom->tracker, bo->handle); + radeon_track_add_event(bo->track, file, func, "open", line); + } +#endif + return bo; +} + +static inline void _radeon_bo_ref(struct radeon_bo *bo, + const char *file, + const char *func, + int line) +{ + bo->cref++; +#ifdef RADEON_BO_TRACK + radeon_track_add_event(bo->track, file, func, "ref", line); +#endif + bo->bom->funcs->bo_ref(bo); +} + +static inline struct radeon_bo *_radeon_bo_unref(struct radeon_bo *bo, + const char *file, + const char *func, + int line) +{ + bo->cref--; +#ifdef RADEON_BO_TRACK + radeon_track_add_event(bo->track, file, func, "unref", line); + if (bo->cref <= 0) { + radeon_tracker_remove_track(&bo->bom->tracker, bo->track); + bo->track = NULL; + } +#endif + return bo->bom->funcs->bo_unref(bo); +} + +static inline int _radeon_bo_map(struct radeon_bo *bo, + int write, + const char *file, + const char *func, + int line) +{ + return bo->bom->funcs->bo_map(bo, write); +} + +static inline int _radeon_bo_unmap(struct radeon_bo *bo, + const char *file, + const char *func, + int line) +{ + return bo->bom->funcs->bo_unmap(bo); +} + +static inline int _radeon_bo_wait(struct radeon_bo *bo, + const char *file, + const char *func, + int line) +{ + return bo->bom->funcs->bo_wait(bo); +} + +static inline int _radeon_bo_is_busy(struct radeon_bo *bo, + uint32_t *domain, + const char *file, + const char *func, + int line) +{ + return bo->bom->funcs->bo_is_busy(bo, domain); +} + +static inline int radeon_bo_set_tiling(struct radeon_bo *bo, + uint32_t tiling_flags, uint32_t pitch) +{ + return bo->bom->funcs->bo_set_tiling(bo, tiling_flags, pitch); +} + +static inline int radeon_bo_get_tiling(struct radeon_bo *bo, + uint32_t *tiling_flags, uint32_t *pitch) +{ + return bo->bom->funcs->bo_get_tiling(bo, tiling_flags, pitch); +} + +static inline int radeon_bo_is_static(struct radeon_bo *bo) +{ + if (bo->bom->funcs->bo_is_static) + return bo->bom->funcs->bo_is_static(bo); + return 0; +} + +#define radeon_bo_open(bom, h, s, a, d, f)\ + _radeon_bo_open(bom, h, s, a, d, f, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_ref(bo)\ + _radeon_bo_ref(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_unref(bo)\ + _radeon_bo_unref(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_map(bo, w)\ + _radeon_bo_map(bo, w, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_unmap(bo)\ + _radeon_bo_unmap(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_debug(bo, opcode)\ + _radeon_bo_debug(bo, opcode, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_wait(bo) \ + _radeon_bo_wait(bo, __FILE__, __func__, __LINE__) +#define radeon_bo_is_busy(bo, domain) \ + _radeon_bo_is_busy(bo, domain, __FILE__, __func__, __LINE__) + +#endif diff --git a/radeon/radeon_bo_gem.c b/radeon/radeon_bo_gem.c new file mode 100644 index 00000000..d34f24cd --- /dev/null +++ b/radeon/radeon_bo_gem.c @@ -0,0 +1,343 @@ +/* + * Copyright © 2008 Dave Airlie + * 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: + * Dave Airlie + * Jérôme Glisse + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "xf86drm.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_bo.h" +#include "radeon_bo_gem.h" + +struct radeon_bo_gem { + struct radeon_bo base; + uint32_t name; + int map_count; + void *priv_ptr; +}; + +struct bo_manager_gem { + struct radeon_bo_manager base; +}; + +static int bo_wait(struct radeon_bo *bo); + +static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags) +{ + struct radeon_bo_gem *bo; + int r; + + bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); + if (bo == NULL) { + return NULL; + } + + bo->base.bom = bom; + bo->base.handle = 0; + bo->base.size = size; + bo->base.alignment = alignment; + bo->base.domains = domains; + bo->base.flags = flags; + bo->base.ptr = NULL; + bo->map_count = 0; + if (handle) { + struct drm_gem_open open_arg; + + memset(&open_arg, 0, sizeof(open_arg)); + open_arg.name = handle; + r = ioctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (r != 0) { + free(bo); + return NULL; + } + bo->base.handle = open_arg.handle; + bo->base.size = open_arg.size; + bo->name = handle; + } else { + struct drm_radeon_gem_create args; + + args.size = size; + args.alignment = alignment; + args.initial_domain = bo->base.domains; + args.flags = 0; + args.handle = 0; + r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, + &args, sizeof(args)); + bo->base.handle = args.handle; + if (r) { + fprintf(stderr, "Failed to allocate :\n"); + fprintf(stderr, " size : %d bytes\n", size); + fprintf(stderr, " alignment : %d bytes\n", alignment); + fprintf(stderr, " domains : %d\n", bo->base.domains); + free(bo); + return NULL; + } + } + radeon_bo_ref((struct radeon_bo*)bo); + return (struct radeon_bo*)bo; +} + +static void bo_ref(struct radeon_bo *bo) +{ +} + +static struct radeon_bo *bo_unref(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + struct drm_gem_close args; + + if (bo == NULL) { + return NULL; + } + if (bo->cref) { + return bo; + } + if (bo_gem->priv_ptr) { + munmap(bo_gem->priv_ptr, bo->size); + } + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + + /* close object */ + args.handle = bo->handle; + ioctl(bo->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); + memset(bo_gem, 0, sizeof(struct radeon_bo_gem)); + free(bo_gem); + return NULL; +} + +static int bo_map(struct radeon_bo *bo, int write) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + struct drm_radeon_gem_mmap args; + int r; + void *ptr; + + if (bo_gem->map_count++ != 0) { + return 0; + } + if (bo_gem->priv_ptr) { + goto wait; + } + + bo->ptr = NULL; + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + args.offset = 0; + args.size = (uint64_t)bo->size; + r = drmCommandWriteRead(bo->bom->fd, + DRM_RADEON_GEM_MMAP, + &args, + sizeof(args)); + if (r) { + fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", + bo, bo->handle, r); + return r; + } + ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, bo->bom->fd, args.addr_ptr); + if (ptr == MAP_FAILED) + return -errno; + bo_gem->priv_ptr = ptr; +wait: + bo->ptr = bo_gem->priv_ptr; + r = bo_wait(bo); + if (r) + return r; + return 0; +} + +static int bo_unmap(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + + if (--bo_gem->map_count > 0) { + return 0; + } + //munmap(bo->ptr, bo->size); + bo->ptr = NULL; + return 0; +} + +static int bo_wait(struct radeon_bo *bo) +{ + struct drm_radeon_gem_wait_idle args; + int ret; + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + do { + ret = drmCommandWriteRead(bo->bom->fd, DRM_RADEON_GEM_WAIT_IDLE, + &args, sizeof(args)); + } while (ret == -EBUSY); + return ret; +} + +static int bo_is_busy(struct radeon_bo *bo, uint32_t *domain) +{ + struct drm_radeon_gem_busy args; + int ret; + + args.handle = bo->handle; + args.domain = 0; + + ret = drmCommandWriteRead(bo->bom->fd, DRM_RADEON_GEM_BUSY, + &args, sizeof(args)); + + *domain = args.domain; + return ret; +} + +static int bo_set_tiling(struct radeon_bo *bo, uint32_t tiling_flags, + uint32_t pitch) +{ + struct drm_radeon_gem_set_tiling args; + int r; + + args.handle = bo->handle; + args.tiling_flags = tiling_flags; + args.pitch = pitch; + + r = drmCommandWriteRead(bo->bom->fd, + DRM_RADEON_GEM_SET_TILING, + &args, + sizeof(args)); + return r; +} + +static int bo_get_tiling(struct radeon_bo *bo, uint32_t *tiling_flags, + uint32_t *pitch) +{ + struct drm_radeon_gem_set_tiling args; + int r; + + args.handle = bo->handle; + + r = drmCommandWriteRead(bo->bom->fd, + DRM_RADEON_GEM_GET_TILING, + &args, + sizeof(args)); + + if (r) + return r; + + *tiling_flags = args.tiling_flags; + *pitch = args.pitch; + return r; +} + +static struct radeon_bo_funcs bo_gem_funcs = { + bo_open, + bo_ref, + bo_unref, + bo_map, + bo_unmap, + bo_wait, + NULL, + bo_set_tiling, + bo_get_tiling, + bo_is_busy, +}; + +struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd) +{ + struct bo_manager_gem *bomg; + + bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem)); + if (bomg == NULL) { + return NULL; + } + bomg->base.funcs = &bo_gem_funcs; + bomg->base.fd = fd; + return (struct radeon_bo_manager*)bomg; +} + +void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom) +{ + struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom; + + if (bom == NULL) { + return; + } + free(bomg); +} + +uint32_t radeon_gem_name_bo(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + return bo_gem->name; +} + +int radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name) +{ + struct drm_gem_flink flink; + int r; + + flink.handle = bo->handle; + r = ioctl(bo->bom->fd, DRM_IOCTL_GEM_FLINK, &flink); + if (r) { + return r; + } + *name = flink.name; + return 0; +} + +int radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain) +{ + struct drm_radeon_gem_set_domain args; + int r; + + args.handle = bo->handle; + args.read_domains = read_domains; + args.write_domain = write_domain; + + r = drmCommandWriteRead(bo->bom->fd, + DRM_RADEON_GEM_SET_DOMAIN, + &args, + sizeof(args)); + return r; +} diff --git a/radeon/radeon_bo_gem.h b/radeon/radeon_bo_gem.h new file mode 100644 index 00000000..4a8df9ad --- /dev/null +++ b/radeon/radeon_bo_gem.h @@ -0,0 +1,43 @@ +/* + * Copyright © 2008 Dave Airlie + * 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: + * Dave Airlie + * Jérôme Glisse + */ +#ifndef RADEON_BO_GEM_H +#define RADEON_BO_GEM_H + +#include "radeon_bo.h" + +struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd); +void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom); + +uint32_t radeon_gem_name_bo(struct radeon_bo *bo); +int radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain); +int radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name); +#endif diff --git a/radeon/radeon_cs.h b/radeon/radeon_cs.h new file mode 100644 index 00000000..1117a850 --- /dev/null +++ b/radeon/radeon_cs.h @@ -0,0 +1,246 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * 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: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_H +#define RADEON_CS_H + +#include +#include +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_bo.h" + +struct radeon_cs_reloc { + struct radeon_bo *bo; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; +}; + + +#define RADEON_CS_SPACE_OK 0 +#define RADEON_CS_SPACE_OP_TO_BIG 1 +#define RADEON_CS_SPACE_FLUSH 2 + +struct radeon_cs_space_check { + struct radeon_bo *bo; + uint32_t read_domains; + uint32_t write_domain; + uint32_t new_accounted; +}; + +#define MAX_SPACE_BOS (32) + +struct radeon_cs_manager; + +struct radeon_cs { + struct radeon_cs_manager *csm; + void *relocs; + uint32_t *packets; + unsigned crelocs; + unsigned relocs_total_size; + unsigned cdw; + unsigned ndw; + int section; + unsigned section_ndw; + unsigned section_cdw; + const char *section_file; + const char *section_func; + int section_line; + struct radeon_cs_space_check bos[MAX_SPACE_BOS]; + int bo_count; + void (*space_flush_fn)(void *); + void *space_flush_data; +}; + +/* cs functions */ +struct radeon_cs_funcs { + struct radeon_cs *(*cs_create)(struct radeon_cs_manager *csm, + uint32_t ndw); + int (*cs_write_reloc)(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags); + int (*cs_begin)(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line); + int (*cs_end)(struct radeon_cs *cs, + const char *file, + const char *func, + int line); + int (*cs_emit)(struct radeon_cs *cs); + int (*cs_destroy)(struct radeon_cs *cs); + int (*cs_erase)(struct radeon_cs *cs); + int (*cs_need_flush)(struct radeon_cs *cs); + void (*cs_print)(struct radeon_cs *cs, FILE *file); +}; + +struct radeon_cs_manager { + struct radeon_cs_funcs *funcs; + int fd; + int32_t vram_limit, gart_limit; + int32_t vram_write_used, gart_write_used; + int32_t read_used; +}; + +static inline struct radeon_cs *radeon_cs_create(struct radeon_cs_manager *csm, + uint32_t ndw) +{ + return csm->funcs->cs_create(csm, ndw); +} + +static inline int radeon_cs_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags) +{ + return cs->csm->funcs->cs_write_reloc(cs, + bo, + read_domain, + write_domain, + flags); +} + +static inline int radeon_cs_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) +{ + return cs->csm->funcs->cs_begin(cs, ndw, file, func, line); +} + +static inline int radeon_cs_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line) +{ + return cs->csm->funcs->cs_end(cs, file, func, line); +} + +static inline int radeon_cs_emit(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_emit(cs); +} + +static inline int radeon_cs_destroy(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_destroy(cs); +} + +static inline int radeon_cs_erase(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_erase(cs); +} + +static inline int radeon_cs_need_flush(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_need_flush(cs); +} + +static inline void radeon_cs_print(struct radeon_cs *cs, FILE *file) +{ + cs->csm->funcs->cs_print(cs, file); +} + +static inline void radeon_cs_set_limit(struct radeon_cs *cs, uint32_t domain, uint32_t limit) +{ + + if (domain == RADEON_GEM_DOMAIN_VRAM) + cs->csm->vram_limit = limit; + else + cs->csm->gart_limit = limit; +} + +static inline void radeon_cs_write_dword(struct radeon_cs *cs, uint32_t dword) +{ + cs->packets[cs->cdw++] = dword; + if (cs->section) { + cs->section_cdw++; + } +} + +static inline void radeon_cs_write_qword(struct radeon_cs *cs, uint64_t qword) +{ + memcpy(cs->packets + cs->cdw, &qword, sizeof(uint64_t)); + cs->cdw += 2; + if (cs->section) { + cs->section_cdw += 2; + } +} + +static inline void radeon_cs_write_table(struct radeon_cs *cs, void *data, uint32_t size) +{ + memcpy(cs->packets + cs->cdw, data, size * 4); + cs->cdw += size; + if (cs->section) { + cs->section_cdw += size; + } +} + +static inline void radeon_cs_space_set_flush(struct radeon_cs *cs, void (*fn)(void *), void *data) +{ + cs->space_flush_fn = fn; + cs->space_flush_data = data; +} + + +/* + * add a persistent BO to the list + * a persistent BO is one that will be referenced across flushes, + * i.e. colorbuffer, textures etc. + * They get reset when a new "operation" happens, where an operation + * is a state emission with a color/textures etc followed by a bunch of vertices. + */ +void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domains, + uint32_t write_domain); + +/* reset the persistent BO list */ +void radeon_cs_space_reset_bos(struct radeon_cs *cs); + +/* do a space check with the current persistent BO list */ +int radeon_cs_space_check(struct radeon_cs *cs); + +/* do a space check with the current persistent BO list and a temporary BO + * a temporary BO is like a DMA buffer, which gets flushed with the + * command buffer */ +int radeon_cs_space_check_with_bo(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domains, + uint32_t write_domain); + +#endif diff --git a/radeon/radeon_cs_gem.c b/radeon/radeon_cs_gem.c new file mode 100644 index 00000000..232ea7f3 --- /dev/null +++ b/radeon/radeon_cs_gem.c @@ -0,0 +1,458 @@ +/* + * 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: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include "radeon_cs.h" +#include "radeon_cs_gem.h" +#include "radeon_bo_gem.h" +#include "drm.h" +#include "xf86drm.h" +#include "radeon_drm.h" + +#pragma pack(1) +struct cs_reloc_gem { + uint32_t handle; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; +}; + +#pragma pack() +#define RELOC_SIZE (sizeof(struct cs_reloc_gem) / sizeof(uint32_t)) + +struct cs_gem { + struct radeon_cs base; + struct drm_radeon_cs cs; + struct drm_radeon_cs_chunk chunks[2]; + unsigned nrelocs; + uint32_t *relocs; + struct radeon_bo **relocs_bo; +}; + +static struct radeon_cs *cs_gem_create(struct radeon_cs_manager *csm, + uint32_t ndw) +{ + struct cs_gem *csg; + + /* max cmd buffer size is 64Kb */ + if (ndw > (64 * 1024 / 4)) { + return NULL; + } + csg = (struct cs_gem*)calloc(1, sizeof(struct cs_gem)); + if (csg == NULL) { + return NULL; + } + csg->base.csm = csm; + csg->base.ndw = 64 * 1024 / 4; + csg->base.packets = (uint32_t*)calloc(1, 64 * 1024); + if (csg->base.packets == NULL) { + free(csg); + return NULL; + } + csg->base.relocs_total_size = 0; + csg->base.crelocs = 0; + csg->nrelocs = 4096 / (4 * 4) ; + csg->relocs_bo = (struct radeon_bo**)calloc(1, + csg->nrelocs*sizeof(void*)); + if (csg->relocs_bo == NULL) { + free(csg->base.packets); + free(csg); + return NULL; + } + csg->base.relocs = csg->relocs = (uint32_t*)calloc(1, 4096); + if (csg->relocs == NULL) { + free(csg->relocs_bo); + free(csg->base.packets); + free(csg); + return NULL; + } + csg->chunks[0].chunk_id = RADEON_CHUNK_ID_IB; + csg->chunks[0].length_dw = 0; + csg->chunks[0].chunk_data = (uint64_t)(uintptr_t)csg->base.packets; + csg->chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; + csg->chunks[1].length_dw = 0; + csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs; + return (struct radeon_cs*)csg; +} + +static int cs_gem_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + struct cs_reloc_gem *reloc; + uint32_t idx; + unsigned i; + + assert(bo->space_accounted); + + /* check domains */ + if ((read_domain && write_domain) || (!read_domain && !write_domain)) { + /* in one CS a bo can only be in read or write domain but not + * in read & write domain at the same sime + */ + return -EINVAL; + } + if (read_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } + if (write_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } + /* check if bo is already referenced */ + for(i = 0; i < cs->crelocs; i++) { + idx = i * RELOC_SIZE; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; + if (reloc->handle == bo->handle) { + /* Check domains must be in read or write. As we check already + * checked that in argument one of the read or write domain was + * set we only need to check that if previous reloc as the read + * domain set then the read_domain should also be set for this + * new relocation. + */ + /* the DDX expects to read and write from same pixmap */ + if (write_domain && (reloc->read_domain & write_domain)) { + reloc->read_domain = 0; + reloc->write_domain = write_domain; + } else if (read_domain & reloc->write_domain) { + reloc->read_domain = 0; + } else { + if (write_domain != reloc->write_domain) + return -EINVAL; + if (read_domain != reloc->read_domain) + return -EINVAL; + } + + reloc->read_domain |= read_domain; + reloc->write_domain |= write_domain; + /* update flags */ + reloc->flags |= (flags & reloc->flags); + /* write relocation packet */ + radeon_cs_write_dword(cs, 0xc0001000); + radeon_cs_write_dword(cs, idx); + return 0; + } + } + /* new relocation */ + if (csg->base.crelocs >= csg->nrelocs) { + /* allocate more memory (TODO: should use a slab allocatore maybe) */ + uint32_t *tmp, size; + size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*)); + tmp = (uint32_t*)realloc(csg->relocs_bo, size); + if (tmp == NULL) { + return -ENOMEM; + } + csg->relocs_bo = (struct radeon_bo**)tmp; + size = ((csg->nrelocs + 1) * RELOC_SIZE * 4); + tmp = (uint32_t*)realloc(csg->relocs, size); + if (tmp == NULL) { + return -ENOMEM; + } + cs->relocs = csg->relocs = tmp; + csg->nrelocs += 1; + csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs; + } + csg->relocs_bo[csg->base.crelocs] = bo; + idx = (csg->base.crelocs++) * RELOC_SIZE; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; + reloc->handle = bo->handle; + reloc->read_domain = read_domain; + reloc->write_domain = write_domain; + reloc->flags = flags; + csg->chunks[1].length_dw += RELOC_SIZE; + radeon_bo_ref(bo); + cs->relocs_total_size += bo->size; + radeon_cs_write_dword(cs, 0xc0001000); + radeon_cs_write_dword(cs, idx); + return 0; +} + +static int cs_gem_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) +{ + + if (cs->section) { + fprintf(stderr, "CS already in a section(%s,%s,%d)\n", + cs->section_file, cs->section_func, cs->section_line); + fprintf(stderr, "CS can't start section(%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + cs->section = 1; + cs->section_ndw = ndw; + cs->section_cdw = 0; + cs->section_file = file; + cs->section_func = func; + cs->section_line = line; + + + if (cs->cdw + ndw > cs->ndw) { + uint32_t tmp, *ptr; + + /* round up the required size to a multiple of 1024 */ + tmp = (cs->cdw + ndw + 0x3FF) & (~0x3FF); + ptr = (uint32_t*)realloc(cs->packets, 4 * tmp); + if (ptr == NULL) { + return -ENOMEM; + } + cs->packets = ptr; + cs->ndw = tmp; + } + + return 0; +} + +static int cs_gem_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line) + +{ + if (!cs->section) { + fprintf(stderr, "CS no section to end at (%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + cs->section = 0; + if (cs->section_ndw != cs->section_cdw) { + fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n", + cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw); + fprintf(stderr, "CS section end at (%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + return 0; +} + +static int cs_gem_emit(struct radeon_cs *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + uint64_t chunk_array[2]; + unsigned i; + int r; + + csg->chunks[0].length_dw = cs->cdw; + + chunk_array[0] = (uint64_t)(uintptr_t)&csg->chunks[0]; + chunk_array[1] = (uint64_t)(uintptr_t)&csg->chunks[1]; + + csg->cs.num_chunks = 2; + csg->cs.chunks = (uint64_t)(uintptr_t)chunk_array; + + r = drmCommandWriteRead(cs->csm->fd, DRM_RADEON_CS, + &csg->cs, sizeof(struct drm_radeon_cs)); + for (i = 0; i < csg->base.crelocs; i++) { + csg->relocs_bo[i]->space_accounted = 0; + radeon_bo_unref(csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; + } + + cs->csm->read_used = 0; + cs->csm->vram_write_used = 0; + cs->csm->gart_write_used = 0; + return r; +} + +static int cs_gem_destroy(struct radeon_cs *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + + free(csg->relocs_bo); + free(cs->relocs); + free(cs->packets); + free(cs); + return 0; +} + +static int cs_gem_erase(struct radeon_cs *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + unsigned i; + + if (csg->relocs_bo) { + for (i = 0; i < csg->base.crelocs; i++) { + if (csg->relocs_bo[i]) { + radeon_bo_unref(csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; + } + } + } + cs->relocs_total_size = 0; + cs->cdw = 0; + cs->section = 0; + cs->crelocs = 0; + csg->chunks[0].length_dw = 0; + csg->chunks[1].length_dw = 0; + return 0; +} + +static int cs_gem_need_flush(struct radeon_cs *cs) +{ + return 0; //(cs->relocs_total_size > (32*1024*1024)); +} + +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define PACKET3_NOP 0x10 +#define PACKET3_SET_SCISSORS 0x1E +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) (((h) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +static void cs_gem_print(struct radeon_cs *cs, FILE *file) +{ + unsigned opcode; + unsigned reg; + unsigned cnt; + unsigned int i, j; + + for (i = 0; i < cs->cdw;) { + cnt = CP_PACKET_GET_COUNT(cs->packets[i]) + 1; + switch (CP_PACKET_GET_TYPE(cs->packets[i])) { + case PACKET_TYPE0: + fprintf(file, "Pkt0 at %d (%d dwords):\n", i, cnt); + reg = CP_PACKET0_GET_REG(cs->packets[i]); + if (CP_PACKET0_GET_ONE_REG_WR(cs->packets[i++])) { + for (j = 0; j < cnt; j++) { + fprintf(file, " 0x%08X -> 0x%04X\n", + cs->packets[i++], reg); + } + } else { + for (j = 0; j < cnt; j++) { + fprintf(file, " 0x%08X -> 0x%04X\n", + cs->packets[i++], reg); + reg += 4; + } + } + break; + case PACKET_TYPE3: + fprintf(file, "Pkt3 at %d :\n", i); + opcode = CP_PACKET3_GET_OPCODE(cs->packets[i++]); + switch (opcode) { + case PACKET3_NOP: + fprintf(file, " PACKET3_NOP:\n"); + break; + case PACKET3_3D_DRAW_VBUF: + fprintf(file, " PACKET3_3D_DRAW_VBUF:\n"); + break; + case PACKET3_3D_DRAW_IMMD: + fprintf(file, " PACKET3_3D_DRAW_IMMD:\n"); + break; + case PACKET3_3D_DRAW_INDX: + fprintf(file, " PACKET3_3D_DRAW_INDX:\n"); + break; + case PACKET3_3D_LOAD_VBPNTR: + fprintf(file, " PACKET3_3D_LOAD_VBPNTR:\n"); + break; + case PACKET3_INDX_BUFFER: + fprintf(file, " PACKET3_INDX_BUFFER:\n"); + break; + case PACKET3_3D_DRAW_VBUF_2: + fprintf(file, " PACKET3_3D_DRAW_VBUF_2:\n"); + break; + case PACKET3_3D_DRAW_IMMD_2: + fprintf(file, " PACKET3_3D_DRAW_IMMD_2:\n"); + break; + case PACKET3_3D_DRAW_INDX_2: + fprintf(file, " PACKET3_3D_DRAW_INDX_2:\n"); + break; + default: + fprintf(file, "Unknow opcode 0x%02X at %d\n", opcode, i); + return; + } + for (j = 0; j < cnt; j++) { + fprintf(file, " 0x%08X\n", cs->packets[i++]); + } + break; + case PACKET_TYPE1: + case PACKET_TYPE2: + default: + fprintf(file, "Unknow packet 0x%08X at %d\n", cs->packets[i], i); + return; + } + } +} + + + +static struct radeon_cs_funcs radeon_cs_gem_funcs = { + cs_gem_create, + cs_gem_write_reloc, + cs_gem_begin, + cs_gem_end, + cs_gem_emit, + cs_gem_destroy, + cs_gem_erase, + cs_gem_need_flush, + cs_gem_print, +}; + +struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd) +{ + struct radeon_cs_manager *csm; + + csm = (struct radeon_cs_manager*)calloc(1, + sizeof(struct radeon_cs_manager)); + if (csm == NULL) { + return NULL; + } + csm->funcs = &radeon_cs_gem_funcs; + csm->fd = fd; + return csm; +} + +void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm) +{ + free(csm); +} diff --git a/radeon/radeon_cs_gem.h b/radeon/radeon_cs_gem.h new file mode 100644 index 00000000..5efd146f --- /dev/null +++ b/radeon/radeon_cs_gem.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * 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: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_GEM_H +#define RADEON_CS_GEM_H + +#include "radeon_cs.h" + +struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd); +void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm); + +#endif diff --git a/radeon/radeon_cs_space.c b/radeon/radeon_cs_space.c new file mode 100644 index 00000000..4c1ef93e --- /dev/null +++ b/radeon/radeon_cs_space.c @@ -0,0 +1,234 @@ +/* + * Copyright © 2009 Red Hat Inc. + * 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. + */ +/* + */ +#include +#include +#include +#include "radeon_cs.h" + +struct rad_sizes { + int32_t op_read; + int32_t op_gart_write; + int32_t op_vram_write; +}; + +static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes) +{ + uint32_t read_domains, write_domain; + struct radeon_bo *bo; + + bo = sc->bo; + sc->new_accounted = 0; + read_domains = sc->read_domains; + write_domain = sc->write_domain; + + /* legacy needs a static check */ + if (radeon_bo_is_static(bo)) { + bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain; + return 0; + } + + /* already accounted this bo */ + if (write_domain && (write_domain == bo->space_accounted)) { + sc->new_accounted = bo->space_accounted; + return 0; + } + if (read_domains && ((read_domains << 16) == bo->space_accounted)) { + sc->new_accounted = bo->space_accounted; + return 0; + } + + if (bo->space_accounted == 0) { + if (write_domain == RADEON_GEM_DOMAIN_VRAM) + sizes->op_vram_write += bo->size; + else if (write_domain == RADEON_GEM_DOMAIN_GTT) + sizes->op_gart_write += bo->size; + else + sizes->op_read += bo->size; + sc->new_accounted = (read_domains << 16) | write_domain; + } else { + uint16_t old_read, old_write; + + old_read = bo->space_accounted >> 16; + old_write = bo->space_accounted & 0xffff; + + if (write_domain && (old_read & write_domain)) { + sc->new_accounted = write_domain; + /* moving from read to a write domain */ + if (write_domain == RADEON_GEM_DOMAIN_VRAM) { + sizes->op_read -= bo->size; + sizes->op_vram_write += bo->size; + } else if (write_domain == RADEON_GEM_DOMAIN_GTT) { + sizes->op_read -= bo->size; + sizes->op_gart_write += bo->size; + } + } else if (read_domains & old_write) { + sc->new_accounted = bo->space_accounted & 0xffff; + } else { + /* rewrite the domains */ + if (write_domain != old_write) + fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write); + if (read_domains != old_read) + fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read); + return RADEON_CS_SPACE_FLUSH; + } + } + return 0; +} + +static int radeon_cs_do_space_check(struct radeon_cs *cs, struct radeon_cs_space_check *new_tmp) +{ + struct radeon_cs_manager *csm = cs->csm; + int i; + struct radeon_bo *bo; + struct rad_sizes sizes; + int ret; + + /* check the totals for this operation */ + + if (cs->bo_count == 0 && !new_tmp) + return 0; + + memset(&sizes, 0, sizeof(struct rad_sizes)); + + /* prepare */ + for (i = 0; i < cs->bo_count; i++) { + ret = radeon_cs_setup_bo(&cs->bos[i], &sizes); + if (ret) + return ret; + } + + if (new_tmp) { + ret = radeon_cs_setup_bo(new_tmp, &sizes); + if (ret) + return ret; + } + + if (sizes.op_read < 0) + sizes.op_read = 0; + + /* check sizes - operation first */ + if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) || + (sizes.op_vram_write > csm->vram_limit)) { + return RADEON_CS_SPACE_OP_TO_BIG; + } + + if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) || + ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) { + return RADEON_CS_SPACE_FLUSH; + } + + csm->gart_write_used += sizes.op_gart_write; + csm->vram_write_used += sizes.op_vram_write; + csm->read_used += sizes.op_read; + /* commit */ + for (i = 0; i < cs->bo_count; i++) { + bo = cs->bos[i].bo; + bo->space_accounted = cs->bos[i].new_accounted; + } + if (new_tmp) + new_tmp->bo->space_accounted = new_tmp->new_accounted; + + return RADEON_CS_SPACE_OK; +} + +void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain) +{ + int i; + for (i = 0; i < cs->bo_count; i++) { + if (cs->bos[i].bo == bo && + cs->bos[i].read_domains == read_domains && + cs->bos[i].write_domain == write_domain) + return; + } + radeon_bo_ref(bo); + i = cs->bo_count; + cs->bos[i].bo = bo; + cs->bos[i].read_domains = read_domains; + cs->bos[i].write_domain = write_domain; + cs->bos[i].new_accounted = 0; + cs->bo_count++; + + assert(cs->bo_count < MAX_SPACE_BOS); +} + +static int radeon_cs_check_space_internal(struct radeon_cs *cs, struct radeon_cs_space_check *tmp_bo) +{ + int ret; + int flushed = 0; + +again: + ret = radeon_cs_do_space_check(cs, tmp_bo); + if (ret == RADEON_CS_SPACE_OP_TO_BIG) + return -1; + if (ret == RADEON_CS_SPACE_FLUSH) { + (*cs->space_flush_fn)(cs->space_flush_data); + if (flushed) + return -1; + flushed = 1; + goto again; + } + return 0; +} + +int radeon_cs_space_check_with_bo(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domains, uint32_t write_domain) +{ + struct radeon_cs_space_check temp_bo; + int ret = 0; + + if (bo) { + temp_bo.bo = bo; + temp_bo.read_domains = read_domains; + temp_bo.write_domain = write_domain; + temp_bo.new_accounted = 0; + } + + ret = radeon_cs_check_space_internal(cs, bo ? &temp_bo : NULL); + return ret; +} + +int radeon_cs_space_check(struct radeon_cs *cs) +{ + return radeon_cs_check_space_internal(cs, NULL); +} + +void radeon_cs_space_reset_bos(struct radeon_cs *cs) +{ + int i; + for (i = 0; i < cs->bo_count; i++) { + radeon_bo_unref(cs->bos[i].bo); + cs->bos[i].bo = NULL; + cs->bos[i].read_domains = 0; + cs->bos[i].write_domain = 0; + cs->bos[i].new_accounted = 0; + } + cs->bo_count = 0; +} + + diff --git a/radeon/radeon_track.c b/radeon/radeon_track.c new file mode 100644 index 00000000..9ab09275 --- /dev/null +++ b/radeon/radeon_track.c @@ -0,0 +1,141 @@ +/* + * 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 + */ +#include +#include +#include +#include "radeon_track.h" + +void radeon_track_add_event(struct radeon_track *track, + const char *file, + const char *func, + const char *op, + unsigned line) +{ + struct radeon_track_event *event; + + if (track == NULL) { + return; + } + event = (void*)calloc(1,sizeof(struct radeon_track_event)); + if (event == NULL) { + return; + } + event->line = line; + event->file = strdup(file); + event->func = strdup(func); + event->op = strdup(op); + if (event->file == NULL || event->func == NULL || event->op == NULL) { + free(event->file); + free(event->func); + free(event->op); + free(event); + return; + } + event->next = track->events; + track->events = event; +} + +struct radeon_track *radeon_tracker_add_track(struct radeon_tracker *tracker, + unsigned key) +{ + struct radeon_track *track; + + track = (struct radeon_track*)calloc(1, sizeof(struct radeon_track)); + if (track) { + track->next = tracker->tracks.next; + track->prev = &tracker->tracks; + tracker->tracks.next = track; + if (track->next) { + track->next->prev = track; + } + track->key = key; + track->events = NULL; + } + return track; +} + +void radeon_tracker_remove_track(struct radeon_tracker *tracker, + struct radeon_track *track) +{ + struct radeon_track_event *event; + void *tmp; + + if (track == NULL) { + return; + } + track->prev->next = track->next; + if (track->next) { + track->next->prev = track->prev; + } + track->next = track->prev = NULL; + event = track->events; + while (event) { + tmp = event; + free(event->file); + free(event->func); + free(event->op); + event = event->next; + free(tmp); + } + track->events = NULL; + free(track); +} + +void radeon_tracker_print(struct radeon_tracker *tracker, FILE *file) +{ + struct radeon_track *track; + struct radeon_track_event *event; + void *tmp; + + track = tracker->tracks.next; + while (track) { + event = track->events; + fprintf(file, "[0x%08X] :\n", track->key); + while (event) { + tmp = event; + fprintf(file, " [0x%08X:%s](%s:%s:%d)\n", + track->key, event->op, event->file, + event->func, event->line); + free(event->file); + free(event->func); + free(event->op); + event->file = NULL; + event->func = NULL; + event->op = NULL; + event = event->next; + free(tmp); + } + track->events = NULL; + tmp = track; + track = track->next; + free(tmp); + } + tracker->tracks.next = NULL; +} diff --git a/radeon/radeon_track.h b/radeon/radeon_track.h new file mode 100644 index 00000000..838d1f38 --- /dev/null +++ b/radeon/radeon_track.h @@ -0,0 +1,64 @@ +/* + * 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 + */ +#ifndef RADEON_TRACK_H +#define RADEON_TRACK_H + +struct radeon_track_event { + struct radeon_track_event *next; + char *file; + char *func; + char *op; + unsigned line; +}; + +struct radeon_track { + struct radeon_track *next; + struct radeon_track *prev; + unsigned key; + struct radeon_track_event *events; +}; + +struct radeon_tracker { + struct radeon_track tracks; +}; + +void radeon_track_add_event(struct radeon_track *track, + const char *file, + const char *func, + const char *op, + unsigned line); +struct radeon_track *radeon_tracker_add_track(struct radeon_tracker *tracker, + unsigned key); +void radeon_tracker_remove_track(struct radeon_tracker *tracker, + struct radeon_track *track); +void radeon_tracker_print(struct radeon_tracker *tracker, + FILE *file); + +#endif -- cgit v1.2.3