summaryrefslogtreecommitdiff
path: root/src/gallium/winsys/radeon
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/winsys/radeon')
-rw-r--r--src/gallium/winsys/radeon/drm/Makefile6
-rw-r--r--src/gallium/winsys/radeon/drm/SConscript11
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_bo.c602
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_bo.h (renamed from src/gallium/winsys/radeon/drm/radeon_drm_buffer.h)54
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_buffer.c564
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_common.c129
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_cs.c446
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_cs.h102
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_r300.c266
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_winsys.h40
10 files changed, 1283 insertions, 937 deletions
diff --git a/src/gallium/winsys/radeon/drm/Makefile b/src/gallium/winsys/radeon/drm/Makefile
index aa73edde34..e63ae6f500 100644
--- a/src/gallium/winsys/radeon/drm/Makefile
+++ b/src/gallium/winsys/radeon/drm/Makefile
@@ -5,9 +5,9 @@ include $(TOP)/configs/current
LIBNAME = radeonwinsys
C_SOURCES = \
- radeon_drm_buffer.c \
- radeon_drm_common.c \
- radeon_r300.c
+ radeon_drm_bo.c \
+ radeon_drm_cs.c \
+ radeon_drm_common.c
LIBRARY_INCLUDES = -I$(TOP)/src/gallium/drivers/r300 \
$(shell pkg-config libdrm --cflags-only-I)
diff --git a/src/gallium/winsys/radeon/drm/SConscript b/src/gallium/winsys/radeon/drm/SConscript
index 2dbf61a7ba..b16e03556d 100644
--- a/src/gallium/winsys/radeon/drm/SConscript
+++ b/src/gallium/winsys/radeon/drm/SConscript
@@ -3,12 +3,17 @@ Import('*')
env = env.Clone()
radeon_sources = [
- 'radeon_drm_buffer.c',
+ 'radeon_drm_bo.c',
+ 'radeon_drm_cs.c',
'radeon_drm_common.c',
- 'radeon_r300.c',
]
-env.ParseConfig('pkg-config --cflags libdrm_radeon')
+try:
+ env.ParseConfig('pkg-config --cflags libdrm_radeon')
+except:
+ print 'warning: not building r300g'
+ Return()
+
env.Append(CPPPATH = '#/src/gallium/drivers/r300')
radeonwinsys = env.ConvenienceLibrary(
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c
new file mode 100644
index 0000000000..9eb833454d
--- /dev/null
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
+ * 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.
+ */
+
+#define _FILE_OFFSET_BITS 64
+#include "radeon_drm_cs.h"
+
+#include "util/u_hash_table.h"
+#include "util/u_memory.h"
+#include "util/u_simple_list.h"
+#include "os/os_thread.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <xf86drm.h>
+#include <errno.h>
+
+#define RADEON_BO_FLAGS_MACRO_TILE 1
+#define RADEON_BO_FLAGS_MICRO_TILE 2
+#define RADEON_BO_FLAGS_MICRO_TILE_SQUARE 0x20
+
+extern const struct pb_vtbl radeon_bo_vtbl;
+
+
+static INLINE struct radeon_bo *radeon_bo(struct pb_buffer *bo)
+{
+ assert(bo->vtbl == &radeon_bo_vtbl);
+ return (struct radeon_bo *)bo;
+}
+
+struct radeon_bomgr {
+ /* Base class. */
+ struct pb_manager base;
+
+ /* Winsys. */
+ struct radeon_drm_winsys *rws;
+
+ /* List of buffer handles and its mutex. */
+ struct util_hash_table *bo_handles;
+ pipe_mutex bo_handles_mutex;
+};
+
+static INLINE struct radeon_bomgr *radeon_bomgr(struct pb_manager *mgr)
+{
+ return (struct radeon_bomgr *)mgr;
+}
+
+static struct radeon_bo *get_radeon_bo(struct pb_buffer *_buf)
+{
+ struct radeon_bo *bo = NULL;
+
+ if (_buf->vtbl == &radeon_bo_vtbl) {
+ bo = radeon_bo(_buf);
+ } else {
+ struct pb_buffer *base_buf;
+ pb_size offset;
+ pb_get_base_buffer(_buf, &base_buf, &offset);
+
+ if (base_buf->vtbl == &radeon_bo_vtbl)
+ bo = radeon_bo(base_buf);
+ }
+
+ return bo;
+}
+
+void radeon_bo_unref(struct radeon_bo *bo)
+{
+ struct drm_gem_close args = {};
+
+ if (!p_atomic_dec_zero(&bo->ref_count))
+ return;
+
+ if (bo->name) {
+ pipe_mutex_lock(bo->mgr->bo_handles_mutex);
+ util_hash_table_remove(bo->mgr->bo_handles,
+ (void*)(uintptr_t)bo->name);
+ pipe_mutex_unlock(bo->mgr->bo_handles_mutex);
+ }
+
+ if (bo->ptr)
+ munmap(bo->ptr, bo->size);
+
+ /* Close object. */
+ args.handle = bo->handle;
+ drmIoctl(bo->rws->fd, DRM_IOCTL_GEM_CLOSE, &args);
+ pipe_mutex_destroy(bo->map_mutex);
+ FREE(bo);
+}
+
+static void radeon_bo_wait(struct r300_winsys_bo *_buf)
+{
+ struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
+ struct drm_radeon_gem_wait_idle args = {};
+
+ while (p_atomic_read(&bo->num_active_ioctls)) {
+ sched_yield();
+ }
+
+ args.handle = bo->handle;
+ while (drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_WAIT_IDLE,
+ &args, sizeof(args)) == -EBUSY);
+}
+
+static boolean radeon_bo_is_busy(struct r300_winsys_bo *_buf)
+{
+ struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
+ struct drm_radeon_gem_busy args = {};
+
+ if (p_atomic_read(&bo->num_active_ioctls)) {
+ return TRUE;
+ }
+
+ args.handle = bo->handle;
+ return drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_BUSY,
+ &args, sizeof(args)) != 0;
+}
+
+static void radeon_bo_destroy(struct pb_buffer *_buf)
+{
+ struct radeon_bo *bo = radeon_bo(_buf);
+
+ radeon_bo_unref(bo);
+}
+
+static unsigned get_pb_usage_from_transfer_flags(enum pipe_transfer_usage usage)
+{
+ unsigned res = 0;
+
+ if (usage & PIPE_TRANSFER_DONTBLOCK)
+ res |= PB_USAGE_DONTBLOCK;
+
+ if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
+ res |= PB_USAGE_UNSYNCHRONIZED;
+
+ return res;
+}
+
+static void *radeon_bo_map_internal(struct pb_buffer *_buf,
+ unsigned flags, void *flush_ctx)
+{
+ struct radeon_bo *bo = radeon_bo(_buf);
+ struct radeon_drm_cs *cs = flush_ctx;
+ struct drm_radeon_gem_mmap args = {};
+ void *ptr;
+
+ /* If it's not unsynchronized bo_map, flush CS if needed and then wait. */
+ if (!(flags & PB_USAGE_UNSYNCHRONIZED)) {
+ /* DONTBLOCK doesn't make sense with UNSYNCHRONIZED. */
+ if (flags & PB_USAGE_DONTBLOCK) {
+ if (radeon_bo_is_referenced_by_cs(cs, bo)) {
+ cs->flush_cs(cs->flush_data, R300_FLUSH_ASYNC);
+ return NULL;
+ }
+
+ if (radeon_bo_is_busy((struct r300_winsys_bo*)bo)) {
+ return NULL;
+ }
+ } else {
+ if (radeon_bo_is_referenced_by_cs(cs, bo)) {
+ cs->flush_cs(cs->flush_data, 0);
+ } else {
+ /* Try to avoid busy-waiting in radeon_bo_wait. */
+ if (p_atomic_read(&bo->num_active_ioctls))
+ radeon_drm_cs_sync_flush(cs);
+ }
+
+ radeon_bo_wait((struct r300_winsys_bo*)bo);
+ }
+ }
+
+ /* Return the pointer if it's already mapped. */
+ if (bo->ptr)
+ return bo->ptr;
+
+ /* Map the buffer. */
+ pipe_mutex_lock(bo->map_mutex);
+ args.handle = bo->handle;
+ args.offset = 0;
+ args.size = (uint64_t)bo->size;
+ if (drmCommandWriteRead(bo->rws->fd,
+ DRM_RADEON_GEM_MMAP,
+ &args,
+ sizeof(args))) {
+ pipe_mutex_unlock(bo->map_mutex);
+ fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
+ bo, bo->handle);
+ return NULL;
+ }
+
+ ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ bo->rws->fd, args.addr_ptr);
+ if (ptr == MAP_FAILED) {
+ pipe_mutex_unlock(bo->map_mutex);
+ fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
+ return NULL;
+ }
+ bo->ptr = ptr;
+ pipe_mutex_unlock(bo->map_mutex);
+
+ return bo->ptr;
+}
+
+static void radeon_bo_unmap_internal(struct pb_buffer *_buf)
+{
+ /* NOP */
+}
+
+static void radeon_bo_get_base_buffer(struct pb_buffer *buf,
+ struct pb_buffer **base_buf,
+ unsigned *offset)
+{
+ *base_buf = buf;
+ *offset = 0;
+}
+
+static enum pipe_error radeon_bo_validate(struct pb_buffer *_buf,
+ struct pb_validate *vl,
+ unsigned flags)
+{
+ /* Always pinned */
+ return PIPE_OK;
+}
+
+static void radeon_bo_fence(struct pb_buffer *buf,
+ struct pipe_fence_handle *fence)
+{
+}
+
+const struct pb_vtbl radeon_bo_vtbl = {
+ radeon_bo_destroy,
+ radeon_bo_map_internal,
+ radeon_bo_unmap_internal,
+ radeon_bo_validate,
+ radeon_bo_fence,
+ radeon_bo_get_base_buffer,
+};
+
+static struct pb_buffer *radeon_bomgr_create_bo(struct pb_manager *_mgr,
+ pb_size size,
+ const struct pb_desc *desc)
+{
+ struct radeon_bomgr *mgr = radeon_bomgr(_mgr);
+ struct radeon_drm_winsys *rws = mgr->rws;
+ struct radeon_bo *bo;
+ struct drm_radeon_gem_create args = {};
+
+ args.size = size;
+ args.alignment = desc->alignment;
+ args.initial_domain =
+ (desc->usage & RADEON_PB_USAGE_DOMAIN_GTT ?
+ RADEON_GEM_DOMAIN_GTT : 0) |
+ (desc->usage & RADEON_PB_USAGE_DOMAIN_VRAM ?
+ RADEON_GEM_DOMAIN_VRAM : 0);
+
+ if (drmCommandWriteRead(rws->fd, DRM_RADEON_GEM_CREATE,
+ &args, sizeof(args))) {
+ fprintf(stderr, "Failed to allocate :\n");
+ fprintf(stderr, " size : %d bytes\n", size);
+ fprintf(stderr, " alignment : %d bytes\n", desc->alignment);
+ fprintf(stderr, " domains : %d\n", args.initial_domain);
+ return NULL;
+ }
+
+ bo = CALLOC_STRUCT(radeon_bo);
+ if (!bo)
+ return NULL;
+
+ pipe_reference_init(&bo->base.base.reference, 1);
+ bo->base.base.alignment = desc->alignment;
+ bo->base.base.usage = desc->usage;
+ bo->base.base.size = size;
+ bo->base.vtbl = &radeon_bo_vtbl;
+ bo->mgr = mgr;
+ bo->rws = mgr->rws;
+ bo->handle = args.handle;
+ bo->size = size;
+ pipe_mutex_init(bo->map_mutex);
+
+ radeon_bo_ref(bo);
+ return &bo->base;
+}
+
+static void radeon_bomgr_flush(struct pb_manager *mgr)
+{
+ /* NOP */
+}
+
+/* This is for the cache bufmgr. */
+static boolean radeon_bomgr_is_buffer_busy(struct pb_manager *_mgr,
+ struct pb_buffer *_buf)
+{
+ struct radeon_bo *bo = radeon_bo(_buf);
+
+ if (radeon_bo_is_referenced_by_any_cs(bo)) {
+ return TRUE;
+ }
+
+ if (radeon_bo_is_busy((struct r300_winsys_bo*)bo)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void radeon_bomgr_destroy(struct pb_manager *_mgr)
+{
+ struct radeon_bomgr *mgr = radeon_bomgr(_mgr);
+ util_hash_table_destroy(mgr->bo_handles);
+ pipe_mutex_destroy(mgr->bo_handles_mutex);
+ FREE(mgr);
+}
+
+#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
+
+static unsigned handle_hash(void *key)
+{
+ return PTR_TO_UINT(key);
+}
+
+static int handle_compare(void *key1, void *key2)
+{
+ return PTR_TO_UINT(key1) != PTR_TO_UINT(key2);
+}
+
+struct pb_manager *radeon_bomgr_create(struct radeon_drm_winsys *rws)
+{
+ struct radeon_bomgr *mgr;
+
+ mgr = CALLOC_STRUCT(radeon_bomgr);
+ if (!mgr)
+ return NULL;
+
+ mgr->base.destroy = radeon_bomgr_destroy;
+ mgr->base.create_buffer = radeon_bomgr_create_bo;
+ mgr->base.flush = radeon_bomgr_flush;
+ mgr->base.is_buffer_busy = radeon_bomgr_is_buffer_busy;
+
+ mgr->rws = rws;
+ mgr->bo_handles = util_hash_table_create(handle_hash, handle_compare);
+ pipe_mutex_init(mgr->bo_handles_mutex);
+ return &mgr->base;
+}
+
+static void *radeon_bo_map(struct r300_winsys_bo *buf,
+ struct r300_winsys_cs *cs,
+ enum pipe_transfer_usage usage)
+{
+ struct pb_buffer *_buf = pb_buffer(buf);
+
+ return pb_map(_buf, get_pb_usage_from_transfer_flags(usage), cs);
+}
+
+static void radeon_bo_get_tiling(struct r300_winsys_bo *_buf,
+ enum r300_buffer_tiling *microtiled,
+ enum r300_buffer_tiling *macrotiled)
+{
+ struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
+ struct drm_radeon_gem_set_tiling args = {};
+
+ args.handle = bo->handle;
+
+ drmCommandWriteRead(bo->rws->fd,
+ DRM_RADEON_GEM_GET_TILING,
+ &args,
+ sizeof(args));
+
+ *microtiled = R300_BUFFER_LINEAR;
+ *macrotiled = R300_BUFFER_LINEAR;
+ if (args.tiling_flags & RADEON_BO_FLAGS_MICRO_TILE)
+ *microtiled = R300_BUFFER_TILED;
+
+ if (args.tiling_flags & RADEON_BO_FLAGS_MACRO_TILE)
+ *macrotiled = R300_BUFFER_TILED;
+}
+
+static void radeon_bo_set_tiling(struct r300_winsys_bo *_buf,
+ struct r300_winsys_cs *rcs,
+ enum r300_buffer_tiling microtiled,
+ enum r300_buffer_tiling macrotiled,
+ uint32_t pitch)
+{
+ struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ struct drm_radeon_gem_set_tiling args = {};
+
+ /* Tiling determines how DRM treats the buffer data.
+ * We must flush CS when changing it if the buffer is referenced. */
+ if (cs && radeon_bo_is_referenced_by_cs(cs, bo)) {
+ cs->flush_cs(cs->flush_data, 0);
+ }
+
+ while (p_atomic_read(&bo->num_active_ioctls)) {
+ sched_yield();
+ }
+
+ if (microtiled == R300_BUFFER_TILED)
+ args.tiling_flags |= RADEON_BO_FLAGS_MICRO_TILE;
+ else if (microtiled == R300_BUFFER_SQUARETILED)
+ args.tiling_flags |= RADEON_BO_FLAGS_MICRO_TILE_SQUARE;
+
+ if (macrotiled == R300_BUFFER_TILED)
+ args.tiling_flags |= RADEON_BO_FLAGS_MACRO_TILE;
+
+ args.handle = bo->handle;
+ args.pitch = pitch;
+
+ drmCommandWriteRead(bo->rws->fd,
+ DRM_RADEON_GEM_SET_TILING,
+ &args,
+ sizeof(args));
+}
+
+static struct r300_winsys_cs_handle *radeon_drm_get_cs_handle(
+ struct r300_winsys_bo *_buf)
+{
+ /* return radeon_bo. */
+ return (struct r300_winsys_cs_handle*)
+ get_radeon_bo(pb_buffer(_buf));
+}
+
+static unsigned get_pb_usage_from_create_flags(unsigned bind, unsigned usage,
+ enum r300_buffer_domain domain)
+{
+ unsigned res = 0;
+
+ if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
+ res |= RADEON_PB_USAGE_CACHE;
+
+ if (domain & R300_DOMAIN_GTT)
+ res |= RADEON_PB_USAGE_DOMAIN_GTT;
+
+ if (domain & R300_DOMAIN_VRAM)
+ res |= RADEON_PB_USAGE_DOMAIN_VRAM;
+
+ return res;
+}
+
+static struct r300_winsys_bo *
+radeon_winsys_bo_create(struct r300_winsys_screen *rws,
+ unsigned size,
+ unsigned alignment,
+ unsigned bind,
+ unsigned usage,
+ enum r300_buffer_domain domain)
+{
+ struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
+ struct pb_desc desc;
+ struct pb_manager *provider;
+ struct pb_buffer *buffer;
+
+ memset(&desc, 0, sizeof(desc));
+ desc.alignment = alignment;
+ desc.usage = get_pb_usage_from_create_flags(bind, usage, domain);
+
+ /* Assign a buffer manager. */
+ if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
+ provider = ws->cman;
+ else
+ provider = ws->kman;
+
+ buffer = provider->create_buffer(provider, size, &desc);
+ if (!buffer)
+ return NULL;
+
+ return (struct r300_winsys_bo*)buffer;
+}
+
+static struct r300_winsys_bo *radeon_winsys_bo_from_handle(struct r300_winsys_screen *rws,
+ struct winsys_handle *whandle,
+ unsigned *stride,
+ unsigned *size)
+{
+ struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
+ struct radeon_bo *bo;
+ struct radeon_bomgr *mgr = radeon_bomgr(ws->kman);
+ struct drm_gem_open open_arg = {};
+
+ /* We must maintain a list of pairs <handle, bo>, so that we always return
+ * the same BO for one particular handle. If we didn't do that and created
+ * more than one BO for the same handle and then relocated them in a CS,
+ * we would hit a deadlock in the kernel.
+ *
+ * The list of pairs is guarded by a mutex, of course. */
+ pipe_mutex_lock(mgr->bo_handles_mutex);
+
+ /* First check if there already is an existing bo for the handle. */
+ bo = util_hash_table_get(mgr->bo_handles, (void*)(uintptr_t)whandle->handle);
+ if (bo) {
+ /* Increase the refcount. */
+ struct pb_buffer *b = NULL;
+ pb_reference(&b, &bo->base);
+ goto done;
+ }
+
+ /* There isn't, create a new one. */
+ bo = CALLOC_STRUCT(radeon_bo);
+ if (!bo) {
+ goto fail;
+ }
+
+ /* Open the BO. */
+ open_arg.name = whandle->handle;
+ if (drmIoctl(ws->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) {
+ FREE(bo);
+ goto fail;
+ }
+ bo->handle = open_arg.handle;
+ bo->size = open_arg.size;
+ bo->name = whandle->handle;
+ radeon_bo_ref(bo);
+
+ /* Initialize it. */
+ pipe_reference_init(&bo->base.base.reference, 1);
+ bo->base.base.alignment = 0;
+ bo->base.base.usage = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
+ bo->base.base.size = bo->size;
+ bo->base.vtbl = &radeon_bo_vtbl;
+ bo->mgr = mgr;
+ bo->rws = mgr->rws;
+ pipe_mutex_init(bo->map_mutex);
+
+ util_hash_table_set(mgr->bo_handles, (void*)(uintptr_t)whandle->handle, bo);
+
+done:
+ pipe_mutex_unlock(mgr->bo_handles_mutex);
+
+ if (stride)
+ *stride = whandle->stride;
+ if (size)
+ *size = bo->base.base.size;
+
+ return (struct r300_winsys_bo*)bo;
+
+fail:
+ pipe_mutex_unlock(mgr->bo_handles_mutex);
+ return NULL;
+}
+
+static boolean radeon_winsys_bo_get_handle(struct r300_winsys_bo *buffer,
+ unsigned stride,
+ struct winsys_handle *whandle)
+{
+ struct drm_gem_flink flink = {};
+ struct radeon_bo *bo = get_radeon_bo(pb_buffer(buffer));
+
+ if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
+ if (!bo->flinked) {
+ flink.handle = bo->handle;
+
+ if (ioctl(bo->rws->fd, DRM_IOCTL_GEM_FLINK, &flink)) {
+ return FALSE;
+ }
+
+ bo->flinked = TRUE;
+ bo->flink = flink.name;
+ }
+ whandle->handle = bo->flink;
+ } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
+ whandle->handle = bo->handle;
+ }
+
+ whandle->stride = stride;
+ return TRUE;
+}
+
+void radeon_bomgr_init_functions(struct radeon_drm_winsys *ws)
+{
+ ws->base.buffer_get_cs_handle = radeon_drm_get_cs_handle;
+ ws->base.buffer_set_tiling = radeon_bo_set_tiling;
+ ws->base.buffer_get_tiling = radeon_bo_get_tiling;
+ ws->base.buffer_map = radeon_bo_map;
+ ws->base.buffer_unmap = pb_unmap;
+ ws->base.buffer_wait = radeon_bo_wait;
+ ws->base.buffer_is_busy = radeon_bo_is_busy;
+ ws->base.buffer_create = radeon_winsys_bo_create;
+ ws->base.buffer_from_handle = radeon_winsys_bo_from_handle;
+ ws->base.buffer_get_handle = radeon_winsys_bo_get_handle;
+}
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_buffer.h b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h
index 494abdc0b4..a26866b7e7 100644
--- a/src/gallium/winsys/radeon/drm/radeon_drm_buffer.h
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h
@@ -1,5 +1,6 @@
/*
* Copyright © 2008 Jérôme Glisse
+ * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -26,28 +27,61 @@
/*
* Authors:
* Jérôme Glisse <glisse@freedesktop.org>
+ * Marek Olšák <maraeo@gmail.com>
*/
#ifndef RADEON_DRM_BUFFER_H
#define RADEON_DRM_BUFFER_H
#include "radeon_winsys.h"
+#include "pipebuffer/pb_bufmgr.h"
+#include "os/os_thread.h"
-#define RADEON_PB_USAGE_VERTEX (1 << 28)
+#define RADEON_PB_USAGE_CACHE (1 << 28)
#define RADEON_PB_USAGE_DOMAIN_GTT (1 << 29)
#define RADEON_PB_USAGE_DOMAIN_VRAM (1 << 30)
+struct radeon_bomgr;
+
+struct radeon_bo {
+ struct pb_buffer base;
+ struct radeon_bomgr *mgr;
+ struct radeon_drm_winsys *rws;
+
+ void *ptr;
+ pipe_mutex map_mutex;
+
+ uint32_t size;
+ uint32_t handle;
+ uint32_t name;
+
+ int ref_count;
+
+ /* how many command streams is this bo referenced in? */
+ int num_cs_references;
+
+ /* how many command streams, which are being emitted in a separate
+ * thread, is this bo referenced in? */
+ int num_active_ioctls;
+
+ boolean flinked;
+ uint32_t flink;
+};
+
+struct pb_manager *radeon_bomgr_create(struct radeon_drm_winsys *rws);
+void radeon_bomgr_init_functions(struct radeon_drm_winsys *ws);
+
+void radeon_bo_unref(struct radeon_bo *buf);
+
+
+static INLINE void radeon_bo_ref(struct radeon_bo *bo)
+{
+ p_atomic_inc(&bo->ref_count);
+}
+
static INLINE struct pb_buffer *
-radeon_pb_buffer(struct r300_winsys_buffer *buffer)
+pb_buffer(struct r300_winsys_bo *buffer)
{
return (struct pb_buffer *)buffer;
}
-struct pb_manager *radeon_drm_bufmgr_create(struct radeon_drm_winsys *rws);
-struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr,
- uint32_t handle);
-void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr);
-boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf,
- struct winsys_handle *whandle);
-void radeon_drm_bufmgr_init_functions(struct radeon_drm_winsys *ws);
-
#endif
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c b/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c
deleted file mode 100644
index dc4b51747f..0000000000
--- a/src/gallium/winsys/radeon/drm/radeon_drm_buffer.c
+++ /dev/null
@@ -1,564 +0,0 @@
-#include "radeon_cs_gem.h"
-#include "radeon_drm_buffer.h"
-
-#include "util/u_hash_table.h"
-#include "util/u_memory.h"
-#include "util/u_simple_list.h"
-#include "pipebuffer/pb_bufmgr.h"
-#include "os/os_thread.h"
-
-#include "state_tracker/drm_driver.h"
-
-#include <radeon_drm.h>
-#include <radeon_bo_gem.h>
-#include <sys/ioctl.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 {
- /* Base class. */
- struct pb_manager base;
-
- /* Winsys. */
- struct radeon_drm_winsys *rws;
-
- /* List of mapped buffers and its mutex. */
- struct radeon_drm_buffer buffer_map_list;
- pipe_mutex buffer_map_list_mutex;
-
- /* List of buffer handles and its mutex. */
- struct util_hash_table *buffer_handles;
- pipe_mutex buffer_handles_mutex;
-};
-
-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);
- int name;
-
- if (buf->bo->ptr != NULL) {
- pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
- /* Now test it again inside the mutex. */
- if (buf->bo->ptr != NULL) {
- remove_from_list(buf);
- radeon_bo_unmap(buf->bo);
- buf->bo->ptr = NULL;
- }
- pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
- }
- name = radeon_gem_name_bo(buf->bo);
- if (name) {
- pipe_mutex_lock(buf->mgr->buffer_handles_mutex);
- util_hash_table_remove(buf->mgr->buffer_handles,
- (void*)(uintptr_t)name);
- pipe_mutex_unlock(buf->mgr->buffer_handles_mutex);
- }
- radeon_bo_unref(buf->bo);
-
- FREE(buf);
-}
-
-static unsigned get_pb_usage_from_transfer_flags(enum pipe_transfer_usage usage)
-{
- unsigned res = 0;
-
- if (usage & PIPE_TRANSFER_READ)
- res |= PB_USAGE_CPU_READ;
-
- if (usage & PIPE_TRANSFER_WRITE)
- res |= PB_USAGE_CPU_WRITE;
-
- if (usage & PIPE_TRANSFER_DONTBLOCK)
- res |= PB_USAGE_DONTBLOCK;
-
- if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
- res |= PB_USAGE_UNSYNCHRONIZED;
-
- return res;
-}
-
-static void *
-radeon_drm_buffer_map_internal(struct pb_buffer *_buf,
- unsigned flags, void *flush_ctx)
-{
- struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf);
- struct radeon_drm_cs *cs = flush_ctx;
- int write = 0;
-
- /* Note how we use radeon_bo_is_referenced_by_cs here. There are
- * basically two places this map function can be called from:
- * - pb_map
- * - create_buffer (in the buffer reuse case)
- *
- * Since pb managers are per-winsys managers, not per-context managers,
- * and we shouldn't reuse buffers if they are in-use in any context,
- * we simply ask: is this buffer referenced by *any* CS?
- *
- * The problem with buffer_create is that it comes from pipe_screen,
- * so we have no CS to look at, though luckily the following code
- * is sufficient to tell whether the buffer is in use. */
- if (flags & PB_USAGE_DONTBLOCK) {
- if (_buf->base.usage & RADEON_PB_USAGE_VERTEX)
- if (radeon_bo_is_referenced_by_cs(buf->bo, NULL))
- return NULL;
- }
-
- if (buf->bo->ptr != NULL) {
- pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
- /* Now test ptr again inside the mutex. We might have gotten a race
- * during the first test. */
- if (buf->bo->ptr != NULL) {
- remove_from_list(buf);
- }
- pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
- return buf->bo->ptr;
- }
-
- if (flags & PB_USAGE_DONTBLOCK) {
- uint32_t domain;
- if (radeon_bo_is_busy(buf->bo, &domain))
- return NULL;
- }
-
- /* If we don't have any CS and the buffer is referenced,
- * we cannot flush. */
- assert(cs || !radeon_bo_is_referenced_by_cs(buf->bo, NULL));
-
- if (cs && radeon_bo_is_referenced_by_cs(buf->bo, cs->cs)) {
- cs->flush_cs(cs->flush_data);
- }
-
- if (flags & PB_USAGE_CPU_WRITE) {
- write = 1;
- }
-
- if (radeon_bo_map(buf->bo, write)) {
- return NULL;
- }
-
- pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
- remove_from_list(buf);
- pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
- return buf->bo->ptr;
-}
-
-static void
-radeon_drm_buffer_unmap_internal(struct pb_buffer *_buf)
-{
- struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf);
- pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
- if (is_empty_list(buf)) { /* = is not inserted... */
- insert_at_tail(&buf->mgr->buffer_map_list, buf);
- }
- pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
-}
-
-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_internal,
- radeon_drm_buffer_unmap_internal,
- radeon_drm_buffer_validate,
- radeon_drm_buffer_fence,
- radeon_drm_buffer_get_base_buffer,
-};
-
-static struct pb_buffer *
-radeon_drm_bufmgr_create_buffer_from_handle_unsafe(struct pb_manager *_mgr,
- uint32_t handle)
-{
- struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
- struct radeon_drm_winsys *rws = mgr->rws;
- struct radeon_drm_buffer *buf;
- struct radeon_bo *bo;
-
- buf = util_hash_table_get(mgr->buffer_handles, (void*)(uintptr_t)handle);
-
- if (buf) {
- struct pb_buffer *b = NULL;
- pb_reference(&b, &buf->base);
- return b;
- }
-
- 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 = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
- buf->base.base.size = bo->size;
- buf->base.vtbl = &radeon_drm_buffer_vtbl;
- buf->mgr = mgr;
-
- buf->bo = bo;
-
- util_hash_table_set(mgr->buffer_handles, (void*)(uintptr_t)handle, buf);
-
- return &buf->base;
-}
-
-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 pb_buffer *pb;
-
- pipe_mutex_lock(mgr->buffer_handles_mutex);
- pb = radeon_drm_bufmgr_create_buffer_from_handle_unsafe(_mgr, handle);
- pipe_mutex_unlock(mgr->buffer_handles_mutex);
-
- return pb;
-}
-
-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_drm_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 =
- (desc->usage & RADEON_PB_USAGE_DOMAIN_GTT ? RADEON_GEM_DOMAIN_GTT : 0) |
- (desc->usage & RADEON_PB_USAGE_DOMAIN_VRAM ? RADEON_GEM_DOMAIN_VRAM : 0);
-
- 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);
- util_hash_table_destroy(mgr->buffer_handles);
- pipe_mutex_destroy(mgr->buffer_map_list_mutex);
- pipe_mutex_destroy(mgr->buffer_handles_mutex);
- FREE(mgr);
-}
-
-static unsigned handle_hash(void *key)
-{
- return (unsigned)key;
-}
-
-static int handle_compare(void *key1, void *key2)
-{
- return !((int)key1 == (int)key2);
-}
-
-struct pb_manager *
-radeon_drm_bufmgr_create(struct radeon_drm_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);
- mgr->buffer_handles = util_hash_table_create(handle_hash, handle_compare);
- pipe_mutex_init(mgr->buffer_map_list_mutex);
- pipe_mutex_init(mgr->buffer_handles_mutex);
- return &mgr->base;
-}
-
-static struct radeon_drm_buffer *get_drm_buffer(struct pb_buffer *_buf)
-{
- struct radeon_drm_buffer *buf = NULL;
-
- 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);
-
- if (base_buf->vtbl == &radeon_drm_buffer_vtbl)
- buf = radeon_drm_buffer(base_buf);
- }
-
- return buf;
-}
-
-static void *radeon_drm_buffer_map(struct r300_winsys_screen *ws,
- struct r300_winsys_buffer *buf,
- struct r300_winsys_cs *cs,
- enum pipe_transfer_usage usage)
-{
- struct pb_buffer *_buf = radeon_pb_buffer(buf);
-
- return pb_map(_buf, get_pb_usage_from_transfer_flags(usage), radeon_drm_cs(cs));
-}
-
-static void radeon_drm_buffer_unmap(struct r300_winsys_screen *ws,
- struct r300_winsys_buffer *buf)
-{
- struct pb_buffer *_buf = radeon_pb_buffer(buf);
-
- pb_unmap(_buf);
-}
-
-boolean radeon_drm_bufmgr_get_handle(struct pb_buffer *_buf,
- struct winsys_handle *whandle)
-{
- 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) {
- flink.handle = buf->bo->handle;
-
- if (ioctl(buf->mgr->rws->fd, DRM_IOCTL_GEM_FLINK, &flink)) {
- 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;
-}
-
-static void radeon_drm_buffer_get_tiling(struct r300_winsys_screen *ws,
- struct r300_winsys_buffer *_buf,
- enum r300_buffer_tiling *microtiled,
- enum r300_buffer_tiling *macrotiled)
-{
- struct radeon_drm_buffer *buf = get_drm_buffer(radeon_pb_buffer(_buf));
- uint32_t flags = 0, pitch;
-
- radeon_bo_get_tiling(buf->bo, &flags, &pitch);
-
- *microtiled = R300_BUFFER_LINEAR;
- *macrotiled = R300_BUFFER_LINEAR;
- if (flags & RADEON_BO_FLAGS_MICRO_TILE)
- *microtiled = R300_BUFFER_TILED;
-
- if (flags & RADEON_BO_FLAGS_MACRO_TILE)
- *macrotiled = R300_BUFFER_TILED;
-}
-
-static void radeon_drm_buffer_set_tiling(struct r300_winsys_screen *ws,
- struct r300_winsys_buffer *_buf,
- enum r300_buffer_tiling microtiled,
- enum r300_buffer_tiling macrotiled,
- uint32_t pitch)
-{
- struct radeon_drm_buffer *buf = get_drm_buffer(radeon_pb_buffer(_buf));
- uint32_t flags = 0;
- 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_set_tiling(buf->bo, flags, pitch);
-}
-
-static void radeon_drm_bufmgr_add_buffer(struct r300_winsys_cs *rcs,
- struct r300_winsys_cs_buffer *_buf,
- enum r300_buffer_domain rd,
- enum r300_buffer_domain wd)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- struct radeon_bo *bo = (struct radeon_bo*)_buf;
-
- radeon_cs_space_add_persistent_bo(cs->cs, bo, rd, wd);
-}
-
-static void radeon_drm_bufmgr_write_reloc(struct r300_winsys_cs *rcs,
- struct r300_winsys_cs_buffer *_buf,
- enum r300_buffer_domain rd,
- enum r300_buffer_domain wd)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- struct radeon_bo *bo = (struct radeon_bo*)_buf;
- int retval;
-
- cs->cs->cdw = cs->base.cdw;
- retval = radeon_cs_write_reloc(cs->cs, bo, rd, wd, 0);
- cs->base.cdw = cs->cs->cdw;
- if (retval) {
- fprintf(stderr, "radeon: Relocation of %p (%d, %d, %d) failed!\n",
- bo, rd, wd, 0);
- }
-}
-
-static struct r300_winsys_cs_buffer *radeon_drm_get_cs_handle(
- struct r300_winsys_screen *rws,
- struct r300_winsys_buffer *_buf)
-{
- /* return pure radeon_bo. */
- return (struct r300_winsys_cs_buffer*)
- get_drm_buffer(radeon_pb_buffer(_buf))->bo;
-}
-
-static boolean radeon_drm_is_buffer_referenced(struct r300_winsys_cs *rcs,
- struct r300_winsys_cs_buffer *_buf,
- enum r300_reference_domain domain)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- struct radeon_bo *bo = (struct radeon_bo*)_buf;
- uint32_t tmp;
-
- if (domain & R300_REF_CS) {
- if (radeon_bo_is_referenced_by_cs(bo, cs->cs)) {
- return TRUE;
- }
- }
-
- if (domain & R300_REF_HW) {
- if (radeon_bo_is_busy(bo, &tmp)) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-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;
-
- pipe_mutex_lock(mgr->buffer_map_list_mutex);
-
- 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);
-
- pipe_mutex_unlock(mgr->buffer_map_list_mutex);
-}
-
-static void radeon_drm_buffer_wait(struct r300_winsys_screen *ws,
- struct r300_winsys_buffer *_buf)
-{
- struct radeon_drm_buffer *buf = get_drm_buffer(radeon_pb_buffer(_buf));
-
- radeon_bo_wait(buf->bo);
-}
-
-void radeon_drm_bufmgr_init_functions(struct radeon_drm_winsys *ws)
-{
- ws->base.buffer_get_cs_handle = radeon_drm_get_cs_handle;
- ws->base.buffer_set_tiling = radeon_drm_buffer_set_tiling;
- ws->base.buffer_get_tiling = radeon_drm_buffer_get_tiling;
- ws->base.buffer_map = radeon_drm_buffer_map;
- ws->base.buffer_unmap = radeon_drm_buffer_unmap;
- ws->base.buffer_wait = radeon_drm_buffer_wait;
- ws->base.cs_is_buffer_referenced = radeon_drm_is_buffer_referenced;
- ws->base.cs_add_buffer = radeon_drm_bufmgr_add_buffer;
- ws->base.cs_write_reloc = radeon_drm_bufmgr_write_reloc;
-}
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_common.c b/src/gallium/winsys/radeon/drm/radeon_drm_common.c
index 6bc6244115..72c2ff1112 100644
--- a/src/gallium/winsys/radeon/drm/radeon_drm_common.c
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_common.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Corbin Simpson
+ * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -27,39 +28,35 @@
* Authors:
* Corbin Simpson <MostAwesomeDude@gmail.com>
* Joakim Sindholt <opensource@zhasha.com>
+ * Marek Olšák <maraeo@gmail.com>
*/
#include "radeon_winsys.h"
-#include "radeon_drm_buffer.h"
+#include "radeon_drm_bo.h"
+#include "radeon_drm_cs.h"
#include "radeon_drm_public.h"
#include "pipebuffer/pb_bufmgr.h"
#include "util/u_memory.h"
-#include "state_tracker/drm_driver.h"
-
-#include <radeon_drm.h>
-#include <radeon_bo_gem.h>
-#include <radeon_cs_gem.h>
#include <xf86drm.h>
#include <stdio.h>
-
-/* Enable/disable Hyper-Z access. Return TRUE on success. */
-static boolean radeon_set_hyperz_access(int fd, boolean enable)
-{
#ifndef RADEON_INFO_WANT_HYPERZ
#define RADEON_INFO_WANT_HYPERZ 7
#endif
+#ifndef RADEON_INFO_WANT_CMASK
+#define RADEON_INFO_WANT_CMASK 8
+#endif
+/* Enable/disable feature access. Return TRUE on success. */
+static boolean radeon_set_fd_access(int fd, unsigned request, boolean enable)
+{
struct drm_radeon_info info = {0};
unsigned value = enable ? 1 : 0;
- if (!debug_get_bool_option("RADEON_HYPERZ", FALSE))
- return FALSE;
-
info.value = (unsigned long)&value;
- info.request = RADEON_INFO_WANT_HYPERZ;
+ info.request = request;
if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0)
return FALSE;
@@ -99,28 +96,21 @@ static void do_ioctls(struct radeon_drm_winsys *winsys)
* we don't actually use the info for anything yet. */
version = drmGetVersion(winsys->fd);
- if (version->version_major != 2) {
+ if (version->version_major != 2 ||
+ version->version_minor < 3) {
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,
+ "only compatible with 2.3.x (kernel 2.6.34) and later.\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
-
- winsys->drm_2_3_0 = version->version_major > 2 ||
- version->version_minor >= 3;
-
- winsys->drm_2_6_0 = version->version_major > 2 ||
- (version->version_major == 2 &&
- version->version_minor >= 6);
+ winsys->drm_major = version->version_major;
+ winsys->drm_minor = version->version_minor;
+ winsys->drm_patchlevel = version->version_patchlevel;
info.request = RADEON_INFO_DEVICE_ID;
retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_INFO, &info, sizeof(info));
@@ -149,7 +139,15 @@ static void do_ioctls(struct radeon_drm_winsys *winsys)
}
winsys->z_pipes = target;
- winsys->hyperz = radeon_set_hyperz_access(winsys->fd, TRUE);
+ if (debug_get_bool_option("RADEON_HYPERZ", FALSE)) {
+ winsys->hyperz = radeon_set_fd_access(winsys->fd,
+ RADEON_INFO_WANT_HYPERZ, TRUE);
+ }
+
+ if (debug_get_bool_option("RADEON_CMASK", FALSE)) {
+ winsys->aacompress = radeon_set_fd_access(winsys->fd,
+ RADEON_INFO_WANT_CMASK, TRUE);
+ }
retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_GEM_INFO,
&gem_info, sizeof(gem_info));
@@ -161,18 +159,9 @@ static void do_ioctls(struct radeon_drm_winsys *winsys)
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"
- "radeon: HyperZ: %s\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,
- winsys->hyperz ? "YES" : "NO");
-
drmFreeVersion(version);
+
+ winsys->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
}
static void radeon_winsys_destroy(struct r300_winsys_screen *rws)
@@ -181,12 +170,43 @@ static void radeon_winsys_destroy(struct r300_winsys_screen *rws)
ws->cman->destroy(ws->cman);
ws->kman->destroy(ws->kman);
-
- radeon_bo_manager_gem_dtor(ws->bom);
- radeon_cs_manager_gem_dtor(ws->csm);
FREE(rws);
}
+static uint32_t radeon_get_value(struct r300_winsys_screen *rws,
+ enum r300_value_id id)
+{
+ struct radeon_drm_winsys *ws = (struct radeon_drm_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_GART_SIZE:
+ return ws->gart_size;
+ case R300_VID_VRAM_SIZE:
+ return ws->vram_size;
+ case R300_VID_DRM_MAJOR:
+ return ws->drm_major;
+ case R300_VID_DRM_MINOR:
+ return ws->drm_minor;
+ case R300_VID_DRM_PATCHLEVEL:
+ return ws->drm_patchlevel;
+ case R300_VID_DRM_2_6_0:
+ return ws->drm_major*100 + ws->drm_minor >= 206;
+ case R300_VID_DRM_2_8_0:
+ return ws->drm_major*100 + ws->drm_minor >= 208;
+ case R300_CAN_HYPERZ:
+ return ws->hyperz;
+ case R300_CAN_AACOMPRESS:
+ return ws->aacompress;
+ }
+ return 0;
+}
+
struct r300_winsys_screen *r300_drm_winsys_screen_create(int fd)
{
struct radeon_drm_winsys *ws = CALLOC_STRUCT(radeon_drm_winsys);
@@ -202,13 +222,7 @@ struct r300_winsys_screen *r300_drm_winsys_screen_create(int fd)
}
/* Create managers. */
- ws->bom = radeon_bo_manager_gem_ctor(fd);
- if (!ws->bom)
- goto fail;
- ws->csm = radeon_cs_manager_gem_ctor(fd);
- if (!ws->csm)
- goto fail;
- ws->kman = radeon_drm_bufmgr_create(ws);
+ ws->kman = radeon_bomgr_create(ws);
if (!ws->kman)
goto fail;
ws->cman = pb_cache_manager_create(ws->kman, 1000000);
@@ -217,23 +231,18 @@ struct r300_winsys_screen *r300_drm_winsys_screen_create(int fd)
/* Set functions. */
ws->base.destroy = radeon_winsys_destroy;
+ ws->base.get_value = radeon_get_value;
- radeon_drm_bufmgr_init_functions(ws);
- radeon_winsys_init_functions(ws);
+ radeon_bomgr_init_functions(ws);
+ radeon_drm_cs_init_functions(ws);
return &ws->base;
fail:
- if (ws->bom)
- radeon_bo_manager_gem_dtor(ws->bom);
- if (ws->csm)
- radeon_cs_manager_gem_dtor(ws->csm);
-
if (ws->cman)
ws->cman->destroy(ws->cman);
if (ws->kman)
ws->kman->destroy(ws->kman);
-
FREE(ws);
return NULL;
}
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c
new file mode 100644
index 0000000000..951791a172
--- /dev/null
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright © 2008 Jérôme Glisse
+ * Copyright © 2010 Marek Olšák <maraeo@gmail.com>
+ * 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:
+ * Marek Olšák <maraeo@gmail.com>
+ *
+ * Based on work from libdrm_radeon by:
+ * Aapo Tahkola <aet@rasterburn.org>
+ * Nicolai Haehnle <prefect_@gmx.net>
+ * Jérôme Glisse <glisse@freedesktop.org>
+ */
+
+/*
+ This file replaces libdrm's radeon_cs_gem with our own implemention.
+ It's optimized specifically for r300g, but r600g could use it as well.
+ Reloc writes and space checking are faster and simpler than their
+ counterparts in libdrm (the time complexity of all the functions
+ is O(1) in nearly all scenarios, thanks to hashing).
+
+ It works like this:
+
+ cs_add_reloc(cs, buf, read_domain, write_domain) adds a new relocation and
+ also adds the size of 'buf' to the used_gart and used_vram winsys variables
+ based on the domains, which are simply or'd for the accounting purposes.
+ The adding is skipped if the reloc is already present in the list, but it
+ accounts any newly-referenced domains.
+
+ cs_validate is then called, which just checks:
+ used_vram/gart < vram/gart_size * 0.8
+ The 0.8 number allows for some memory fragmentation. If the validation
+ fails, the pipe driver flushes CS and tries do the validation again,
+ i.e. it validates only that one operation. If it fails again, it drops
+ the operation on the floor and prints some nasty message to stderr.
+ (done in the pipe driver)
+
+ cs_write_reloc(cs, buf) just writes a reloc that has been added using
+ cs_add_reloc. The read_domain and write_domain parameters have been removed,
+ because we already specify them in cs_add_reloc.
+*/
+
+#include "radeon_drm_cs.h"
+
+#include "util/u_memory.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <xf86drm.h>
+
+#define RELOC_DWORDS (sizeof(struct drm_radeon_cs_reloc) / sizeof(uint32_t))
+
+static boolean radeon_init_cs_context(struct radeon_cs_context *csc, int fd)
+{
+ csc->fd = fd;
+ csc->nrelocs = 512;
+ csc->relocs_bo = (struct radeon_bo**)
+ CALLOC(1, csc->nrelocs * sizeof(struct radeon_bo*));
+ if (!csc->relocs_bo) {
+ return FALSE;
+ }
+
+ csc->relocs = (struct drm_radeon_cs_reloc*)
+ CALLOC(1, csc->nrelocs * sizeof(struct drm_radeon_cs_reloc));
+ if (!csc->relocs) {
+ FREE(csc->relocs_bo);
+ return FALSE;
+ }
+
+ csc->chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
+ csc->chunks[0].length_dw = 0;
+ csc->chunks[0].chunk_data = (uint64_t)(uintptr_t)csc->buf;
+ csc->chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
+ csc->chunks[1].length_dw = 0;
+ csc->chunks[1].chunk_data = (uint64_t)(uintptr_t)csc->relocs;
+
+ csc->chunk_array[0] = (uint64_t)(uintptr_t)&csc->chunks[0];
+ csc->chunk_array[1] = (uint64_t)(uintptr_t)&csc->chunks[1];
+
+ csc->cs.num_chunks = 2;
+ csc->cs.chunks = (uint64_t)(uintptr_t)csc->chunk_array;
+ return TRUE;
+}
+
+static void radeon_cs_context_cleanup(struct radeon_cs_context *csc)
+{
+ unsigned i;
+
+ for (i = 0; i < csc->crelocs; i++) {
+ p_atomic_dec(&csc->relocs_bo[i]->num_cs_references);
+ radeon_bo_unref(csc->relocs_bo[i]);
+ csc->relocs_bo[i] = NULL;
+ }
+
+ csc->crelocs = 0;
+ csc->chunks[0].length_dw = 0;
+ csc->chunks[1].length_dw = 0;
+ csc->used_gart = 0;
+ csc->used_vram = 0;
+ memset(csc->is_handle_added, 0, sizeof(csc->is_handle_added));
+}
+
+static void radeon_destroy_cs_context(struct radeon_cs_context *csc)
+{
+ radeon_cs_context_cleanup(csc);
+ FREE(csc->relocs_bo);
+ FREE(csc->relocs);
+}
+
+static struct r300_winsys_cs *radeon_drm_cs_create(struct r300_winsys_screen *rws)
+{
+ struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
+ struct radeon_drm_cs *cs;
+
+ cs = CALLOC_STRUCT(radeon_drm_cs);
+ if (!cs) {
+ return NULL;
+ }
+
+ cs->ws = ws;
+
+ if (!radeon_init_cs_context(&cs->csc1, cs->ws->fd)) {
+ FREE(cs);
+ return NULL;
+ }
+ if (!radeon_init_cs_context(&cs->csc2, cs->ws->fd)) {
+ radeon_destroy_cs_context(&cs->csc1);
+ FREE(cs);
+ return NULL;
+ }
+
+ /* Set the first command buffer as current. */
+ cs->csc = &cs->csc1;
+ cs->cst = &cs->csc2;
+ cs->base.buf = cs->csc->buf;
+
+ p_atomic_inc(&ws->num_cs);
+ return &cs->base;
+}
+
+#define OUT_CS(cs, value) (cs)->buf[(cs)->cdw++] = (value)
+
+static INLINE void update_domains(struct drm_radeon_cs_reloc *reloc,
+ enum r300_buffer_domain rd,
+ enum r300_buffer_domain wd,
+ enum r300_buffer_domain *added_domains)
+{
+ *added_domains = (rd | wd) & ~(reloc->read_domains | reloc->write_domain);
+
+ if (reloc->read_domains & wd) {
+ reloc->read_domains = rd;
+ reloc->write_domain = wd;
+ } else if (rd & reloc->write_domain) {
+ reloc->read_domains = rd;
+ reloc->write_domain |= wd;
+ } else {
+ reloc->read_domains |= rd;
+ reloc->write_domain |= wd;
+ }
+}
+
+int radeon_get_reloc(struct radeon_cs_context *csc, struct radeon_bo *bo)
+{
+ struct drm_radeon_cs_reloc *reloc;
+ unsigned i;
+ unsigned hash = bo->handle & (sizeof(csc->is_handle_added)-1);
+
+ if (csc->is_handle_added[hash]) {
+ reloc = csc->relocs_hashlist[hash];
+ if (reloc->handle == bo->handle) {
+ return csc->reloc_indices_hashlist[hash];
+ }
+
+ /* Hash collision, look for the BO in the list of relocs linearly. */
+ for (i = csc->crelocs; i != 0;) {
+ --i;
+ reloc = &csc->relocs[i];
+ if (reloc->handle == bo->handle) {
+ /* Put this reloc in the hash list.
+ * This will prevent additional hash collisions if there are
+ * several subsequent get_reloc calls of the same buffer.
+ *
+ * Example: Assuming buffers A,B,C collide in the hash list,
+ * the following sequence of relocs:
+ * AAAAAAAAAAABBBBBBBBBBBBBBCCCCCCCC
+ * will collide here: ^ and here: ^,
+ * meaning that we should get very few collisions in the end. */
+ csc->relocs_hashlist[hash] = reloc;
+ csc->reloc_indices_hashlist[hash] = i;
+ /*printf("write_reloc collision, hash: %i, handle: %i\n", hash, bo->handle);*/
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static void radeon_add_reloc(struct radeon_cs_context *csc,
+ struct radeon_bo *bo,
+ enum r300_buffer_domain rd,
+ enum r300_buffer_domain wd,
+ enum r300_buffer_domain *added_domains)
+{
+ struct drm_radeon_cs_reloc *reloc;
+ unsigned i;
+ unsigned hash = bo->handle & (sizeof(csc->is_handle_added)-1);
+
+ if (csc->is_handle_added[hash]) {
+ reloc = csc->relocs_hashlist[hash];
+ if (reloc->handle == bo->handle) {
+ update_domains(reloc, rd, wd, added_domains);
+ return;
+ }
+
+ /* Hash collision, look for the BO in the list of relocs linearly. */
+ for (i = csc->crelocs; i != 0;) {
+ --i;
+ reloc = &csc->relocs[i];
+ if (reloc->handle == bo->handle) {
+ update_domains(reloc, rd, wd, added_domains);
+
+ csc->relocs_hashlist[hash] = reloc;
+ csc->reloc_indices_hashlist[hash] = i;
+ /*printf("write_reloc collision, hash: %i, handle: %i\n", hash, bo->handle);*/
+ return;
+ }
+ }
+ }
+
+ /* New relocation, check if the backing array is large enough. */
+ if (csc->crelocs >= csc->nrelocs) {
+ uint32_t size;
+ csc->nrelocs += 10;
+
+ size = csc->nrelocs * sizeof(struct radeon_bo*);
+ csc->relocs_bo = (struct radeon_bo**)realloc(csc->relocs_bo, size);
+
+ size = csc->nrelocs * sizeof(struct drm_radeon_cs_reloc);
+ csc->relocs = (struct drm_radeon_cs_reloc*)realloc(csc->relocs, size);
+
+ csc->chunks[1].chunk_data = (uint64_t)(uintptr_t)csc->relocs;
+ }
+
+ /* Initialize the new relocation. */
+ radeon_bo_ref(bo);
+ p_atomic_inc(&bo->num_cs_references);
+ csc->relocs_bo[csc->crelocs] = bo;
+ reloc = &csc->relocs[csc->crelocs];
+ reloc->handle = bo->handle;
+ reloc->read_domains = rd;
+ reloc->write_domain = wd;
+ reloc->flags = 0;
+
+ csc->is_handle_added[hash] = TRUE;
+ csc->relocs_hashlist[hash] = reloc;
+ csc->reloc_indices_hashlist[hash] = csc->crelocs;
+
+ csc->chunks[1].length_dw += RELOC_DWORDS;
+ csc->crelocs++;
+
+ *added_domains = rd | wd;
+}
+
+static void radeon_drm_cs_add_reloc(struct r300_winsys_cs *rcs,
+ struct r300_winsys_cs_handle *buf,
+ enum r300_buffer_domain rd,
+ enum r300_buffer_domain wd)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ struct radeon_bo *bo = (struct radeon_bo*)buf;
+ enum r300_buffer_domain added_domains;
+
+ radeon_add_reloc(cs->csc, bo, rd, wd, &added_domains);
+
+ if (!added_domains)
+ return;
+
+ if (added_domains & R300_DOMAIN_GTT)
+ cs->csc->used_gart += bo->size;
+ if (added_domains & R300_DOMAIN_VRAM)
+ cs->csc->used_vram += bo->size;
+}
+
+static boolean radeon_drm_cs_validate(struct r300_winsys_cs *rcs)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+
+ return cs->csc->used_gart < cs->ws->gart_size * 0.8 &&
+ cs->csc->used_vram < cs->ws->vram_size * 0.8;
+}
+
+static void radeon_drm_cs_write_reloc(struct r300_winsys_cs *rcs,
+ struct r300_winsys_cs_handle *buf)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ struct radeon_bo *bo = (struct radeon_bo*)buf;
+
+ unsigned index = radeon_get_reloc(cs->csc, bo);
+
+ if (index == -1) {
+ fprintf(stderr, "r300: Cannot get a relocation in %s.\n", __func__);
+ return;
+ }
+
+ OUT_CS(&cs->base, 0xc0001000);
+ OUT_CS(&cs->base, index * RELOC_DWORDS);
+}
+
+static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
+{
+ struct radeon_cs_context *csc = (struct radeon_cs_context*)param;
+ unsigned i;
+
+ if (drmCommandWriteRead(csc->fd, DRM_RADEON_CS,
+ &csc->cs, sizeof(struct drm_radeon_cs))) {
+ if (debug_get_bool_option("RADEON_DUMP_CS", FALSE)) {
+ unsigned i;
+
+ fprintf(stderr, "radeon: The kernel rejected CS, dumping...\n");
+ for (i = 0; i < csc->chunks[0].length_dw; i++) {
+ fprintf(stderr, "0x%08X\n", csc->buf[i]);
+ }
+ } else {
+ fprintf(stderr, "radeon: The kernel rejected CS, "
+ "see dmesg for more information.\n");
+ }
+ }
+
+ for (i = 0; i < csc->crelocs; i++)
+ p_atomic_dec(&csc->relocs_bo[i]->num_active_ioctls);
+ return NULL;
+}
+
+void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs)
+{
+ /* Wait for any pending ioctl to complete. */
+ if (cs->thread) {
+ pipe_thread_wait(cs->thread);
+ cs->thread = 0;
+ }
+}
+
+DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
+
+static void radeon_drm_cs_flush(struct r300_winsys_cs *rcs, unsigned flags)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ struct radeon_cs_context *tmp;
+
+ radeon_drm_cs_sync_flush(cs);
+
+ /* If the CS is not empty, emit it in a newly-spawned thread. */
+ if (cs->base.cdw) {
+ unsigned i, crelocs = cs->csc->crelocs;
+
+ cs->csc->chunks[0].length_dw = cs->base.cdw;
+
+ for (i = 0; i < crelocs; i++)
+ p_atomic_inc(&cs->csc->relocs_bo[i]->num_active_ioctls);
+
+ if (cs->ws->num_cpus > 1 && debug_get_option_thread() &&
+ (flags & R300_FLUSH_ASYNC)) {
+ cs->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, cs->csc);
+ assert(cs->thread);
+ } else {
+ radeon_drm_cs_emit_ioctl(cs->csc);
+ }
+ }
+
+ /* Flip command streams. */
+ tmp = cs->csc;
+ cs->csc = cs->cst;
+ cs->cst = tmp;
+
+ /* Prepare a new CS. */
+ radeon_cs_context_cleanup(cs->csc);
+
+ cs->base.buf = cs->csc->buf;
+ cs->base.cdw = 0;
+}
+
+static void radeon_drm_cs_destroy(struct r300_winsys_cs *rcs)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ radeon_drm_cs_sync_flush(cs);
+ radeon_cs_context_cleanup(&cs->csc1);
+ radeon_cs_context_cleanup(&cs->csc2);
+ p_atomic_dec(&cs->ws->num_cs);
+ radeon_destroy_cs_context(&cs->csc1);
+ radeon_destroy_cs_context(&cs->csc2);
+ FREE(cs);
+}
+
+static void radeon_drm_cs_set_flush(struct r300_winsys_cs *rcs,
+ void (*flush)(void *ctx, unsigned flags),
+ void *user)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ cs->flush_cs = flush;
+ cs->flush_data = user;
+}
+
+static boolean radeon_bo_is_referenced(struct r300_winsys_cs *rcs,
+ struct r300_winsys_cs_handle *_buf)
+{
+ struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
+ struct radeon_bo *bo = (struct radeon_bo*)_buf;
+
+ return radeon_bo_is_referenced_by_cs(cs, bo);
+}
+
+void radeon_drm_cs_init_functions(struct radeon_drm_winsys *ws)
+{
+ ws->base.cs_create = radeon_drm_cs_create;
+ ws->base.cs_destroy = radeon_drm_cs_destroy;
+ ws->base.cs_add_reloc = radeon_drm_cs_add_reloc;
+ ws->base.cs_validate = radeon_drm_cs_validate;
+ ws->base.cs_write_reloc = radeon_drm_cs_write_reloc;
+ ws->base.cs_flush = radeon_drm_cs_flush;
+ ws->base.cs_set_flush = radeon_drm_cs_set_flush;
+ ws->base.cs_is_buffer_referenced = radeon_bo_is_referenced;
+}
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.h b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h
new file mode 100644
index 0000000000..dfaa161c31
--- /dev/null
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
+ * 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.
+ */
+
+#ifndef RADEON_DRM_CS_H
+#define RADEON_DRM_CS_H
+
+#include "radeon_drm_bo.h"
+#include <radeon_drm.h>
+
+struct radeon_cs_context {
+ uint32_t buf[R300_MAX_CMDBUF_DWORDS];
+
+ int fd;
+ struct drm_radeon_cs cs;
+ struct drm_radeon_cs_chunk chunks[2];
+ uint64_t chunk_array[2];
+
+ /* Relocs. */
+ unsigned nrelocs;
+ unsigned crelocs;
+ struct radeon_bo **relocs_bo;
+ struct drm_radeon_cs_reloc *relocs;
+
+ /* 0 = BO not added, 1 = BO added */
+ char is_handle_added[256];
+ struct drm_radeon_cs_reloc *relocs_hashlist[256];
+ unsigned reloc_indices_hashlist[256];
+
+ unsigned used_vram;
+ unsigned used_gart;
+};
+
+struct radeon_drm_cs {
+ struct r300_winsys_cs base;
+
+ /* We flip between these two CS. While one is being consumed
+ * by the kernel in another thread, the other one is being filled
+ * by the pipe driver. */
+ struct radeon_cs_context csc1;
+ struct radeon_cs_context csc2;
+ /* The currently-used CS. */
+ struct radeon_cs_context *csc;
+ /* The CS being currently-owned by the other thread. */
+ struct radeon_cs_context *cst;
+
+ /* The winsys. */
+ struct radeon_drm_winsys *ws;
+
+ /* Flush CS. */
+ void (*flush_cs)(void *ctx, unsigned flags);
+ void *flush_data;
+
+ pipe_thread thread;
+};
+
+int radeon_get_reloc(struct radeon_cs_context *csc, struct radeon_bo *bo);
+
+static INLINE struct radeon_drm_cs *
+radeon_drm_cs(struct r300_winsys_cs *base)
+{
+ return (struct radeon_drm_cs*)base;
+}
+
+static INLINE boolean radeon_bo_is_referenced_by_cs(struct radeon_drm_cs *cs,
+ struct radeon_bo *bo)
+{
+ return bo->num_cs_references == bo->rws->num_cs ||
+ (bo->num_cs_references && radeon_get_reloc(cs->csc, bo) != -1);
+}
+
+static INLINE boolean radeon_bo_is_referenced_by_any_cs(struct radeon_bo *bo)
+{
+ return bo->num_cs_references;
+}
+
+void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs);
+void radeon_drm_cs_init_functions(struct radeon_drm_winsys *ws);
+
+#endif
diff --git a/src/gallium/winsys/radeon/drm/radeon_r300.c b/src/gallium/winsys/radeon/drm/radeon_r300.c
deleted file mode 100644
index 9f59b3de46..0000000000
--- a/src/gallium/winsys/radeon/drm/radeon_r300.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
- *
- * 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_drm_buffer.h"
-
-#include "util/u_memory.h"
-#include "pipebuffer/pb_bufmgr.h"
-
-#include "radeon_cs_gem.h"
-#include "state_tracker/drm_driver.h"
-
-static unsigned get_pb_usage_from_create_flags(unsigned bind, unsigned usage,
- enum r300_buffer_domain domain)
-{
- unsigned res = 0;
-
- if (bind & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET |
- PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT))
- res |= PB_USAGE_GPU_WRITE;
-
- if (bind & PIPE_BIND_SAMPLER_VIEW)
- res |= PB_USAGE_GPU_READ | PB_USAGE_GPU_WRITE;
-
- if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
- res |= PB_USAGE_GPU_READ;
-
- if (bind & PIPE_BIND_TRANSFER_WRITE)
- res |= PB_USAGE_CPU_WRITE;
-
- if (bind & PIPE_BIND_TRANSFER_READ)
- res |= PB_USAGE_CPU_READ;
-
- /* Is usage of any use for us? Probably not. */
-
- /* Now add driver-specific usage flags. */
- if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
- res |= RADEON_PB_USAGE_VERTEX;
-
- if (domain & R300_DOMAIN_GTT)
- res |= RADEON_PB_USAGE_DOMAIN_GTT;
-
- if (domain & R300_DOMAIN_VRAM)
- res |= RADEON_PB_USAGE_DOMAIN_VRAM;
-
- return res;
-}
-
-static struct r300_winsys_buffer *
-radeon_r300_winsys_buffer_create(struct r300_winsys_screen *rws,
- unsigned size,
- unsigned alignment,
- unsigned bind,
- unsigned usage,
- enum r300_buffer_domain domain)
-{
- struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
- struct pb_desc desc;
- struct pb_manager *provider;
- struct pb_buffer *buffer;
-
- memset(&desc, 0, sizeof(desc));
- desc.alignment = alignment;
- desc.usage = get_pb_usage_from_create_flags(bind, usage, domain);
-
- /* Assign a buffer manager. */
- if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
- provider = ws->cman;
- else
- provider = ws->kman;
-
- buffer = provider->create_buffer(provider, size, &desc);
- if (!buffer)
- return NULL;
-
- return (struct r300_winsys_buffer*)buffer;
-}
-
-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 = (struct r300_winsys_buffer*)_dst;
-}
-
-static struct r300_winsys_buffer *radeon_r300_winsys_buffer_from_handle(struct r300_winsys_screen *rws,
- struct winsys_handle *whandle,
- unsigned *stride,
- unsigned *size)
-{
- struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
- struct pb_buffer *_buf;
-
- _buf = radeon_drm_bufmgr_create_buffer_from_handle(ws->kman, whandle->handle);
-
- if (stride)
- *stride = whandle->stride;
- if (size)
- *size = _buf->base.size;
-
- return (struct r300_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);
- whandle->stride = stride;
- return radeon_drm_bufmgr_get_handle(_buf, whandle);
-}
-
-static void radeon_r300_winsys_cs_set_flush(struct r300_winsys_cs *rcs,
- void (*flush)(void *),
- void *user)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- cs->flush_cs = flush;
- cs->flush_data = user;
- radeon_cs_space_set_flush(cs->cs, flush, user);
-}
-
-static boolean radeon_r300_winsys_cs_validate(struct r300_winsys_cs *rcs)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
-
- return radeon_cs_space_check(cs->cs) >= 0;
-}
-
-static void radeon_r300_winsys_cs_reset_buffers(struct r300_winsys_cs *rcs)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- radeon_cs_space_reset_bos(cs->cs);
-}
-
-static void radeon_r300_winsys_cs_flush(struct r300_winsys_cs *rcs)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- int retval;
-
- /* Don't flush a zero-sized CS. */
- if (!cs->base.cdw) {
- return;
- }
-
- cs->cs->cdw = cs->base.cdw;
-
- radeon_drm_bufmgr_flush_maps(cs->ws->kman);
-
- /* Emit the CS. */
- retval = radeon_cs_emit(cs->cs);
- if (retval) {
- if (debug_get_bool_option("RADEON_DUMP_CS", FALSE)) {
- fprintf(stderr, "radeon: The kernel rejected CS, dumping...\n");
- radeon_cs_print(cs->cs, stderr);
- } else {
- fprintf(stderr, "radeon: The kernel rejected CS, "
- "see dmesg for more information.\n");
- }
- }
-
- /* 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(cs->cs);
-
- cs->base.buf = cs->cs->packets;
- cs->base.cdw = cs->cs->cdw;
-}
-
-static uint32_t radeon_get_value(struct r300_winsys_screen *rws,
- enum r300_value_id id)
-{
- struct radeon_drm_winsys *ws = (struct radeon_drm_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;
- case R300_VID_DRM_2_3_0:
- return ws->drm_2_3_0;
- case R300_VID_DRM_2_6_0:
- return ws->drm_2_6_0;
- case R300_CAN_HYPERZ:
- return ws->hyperz;
- }
- return 0;
-}
-
-static struct r300_winsys_cs *radeon_r300_winsys_cs_create(struct r300_winsys_screen *rws)
-{
- struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
- struct radeon_drm_cs *cs = CALLOC_STRUCT(radeon_drm_cs);
-
- if (!cs)
- return NULL;
-
- /* Size limit on IBs is 64 kibibytes. */
- cs->cs = radeon_cs_create(ws->csm, 1024 * 64 / 4);
- if (!cs->cs) {
- FREE(cs);
- return NULL;
- }
-
- radeon_cs_set_limit(cs->cs,
- RADEON_GEM_DOMAIN_GTT, ws->gart_size);
- radeon_cs_set_limit(cs->cs,
- RADEON_GEM_DOMAIN_VRAM, ws->vram_size);
-
- cs->ws = ws;
- cs->base.buf = cs->cs->packets;
- cs->base.cdw = cs->cs->cdw;
- return &cs->base;
-}
-
-static void radeon_r300_winsys_cs_destroy(struct r300_winsys_cs *rcs)
-{
- struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
- radeon_cs_destroy(cs->cs);
- FREE(cs);
-}
-
-void radeon_winsys_init_functions(struct radeon_drm_winsys *ws)
-{
- ws->base.get_value = radeon_get_value;
- ws->base.buffer_create = radeon_r300_winsys_buffer_create;
- 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.cs_create = radeon_r300_winsys_cs_create;
- ws->base.cs_destroy = radeon_r300_winsys_cs_destroy;
- ws->base.cs_validate = radeon_r300_winsys_cs_validate;
- ws->base.cs_flush = radeon_r300_winsys_cs_flush;
- ws->base.cs_reset_buffers = radeon_r300_winsys_cs_reset_buffers;
- ws->base.cs_set_flush = radeon_r300_winsys_cs_set_flush;
-}
diff --git a/src/gallium/winsys/radeon/drm/radeon_winsys.h b/src/gallium/winsys/radeon/drm/radeon_winsys.h
index 81da1a25e0..9ecbb07457 100644
--- a/src/gallium/winsys/radeon/drm/radeon_winsys.h
+++ b/src/gallium/winsys/radeon/drm/radeon_winsys.h
@@ -36,8 +36,8 @@ struct radeon_drm_winsys {
struct r300_winsys_screen base;
int fd; /* DRM file descriptor */
+ int num_cs; /* The number of command streams created. */
- struct radeon_bo_manager *bom; /* Radeon BO manager. */
struct pb_manager *kman;
struct pb_manager *cman;
@@ -46,44 +46,22 @@ struct radeon_drm_winsys {
uint32_t z_pipes; /* Z pipe count (rv530 only) */
uint32_t gart_size; /* GART size. */
uint32_t vram_size; /* VRAM size. */
- boolean squaretiling; /* Square tiling support. */
- /* DRM 2.3.0 (R500 VAP regs, MSPOS regs, fixed tex3D size checking) */
- boolean drm_2_3_0;
- /* DRM 2.6.0 (Hyper-Z, GB_Z_PEQ_CONFIG allowed on rv350->r4xx) */
- boolean drm_2_6_0;
- /* Hyper-Z user */
- boolean hyperz;
-
- /* Radeon CS manager. */
- struct radeon_cs_manager *csm;
-};
-
-struct radeon_drm_cs {
- struct r300_winsys_cs base;
-
- /* The winsys. */
- struct radeon_drm_winsys *ws;
+ uint32_t num_cpus; /* Number of CPUs. */
- /* The libdrm command stream. */
- struct radeon_cs *cs;
+ unsigned drm_major;
+ unsigned drm_minor;
+ unsigned drm_patchlevel;
- /* Flush CS. */
- void (*flush_cs)(void *);
- void *flush_data;
+ /* Hyper-Z user */
+ boolean hyperz;
+ /* AA compression (CMask) */
+ boolean aacompress;
};
-static INLINE struct radeon_drm_cs *
-radeon_drm_cs(struct r300_winsys_cs *base)
-{
- return (struct radeon_drm_cs*)base;
-}
-
static INLINE struct radeon_drm_winsys *
radeon_drm_winsys(struct r300_winsys_screen *base)
{
return (struct radeon_drm_winsys*)base;
}
-void radeon_winsys_init_functions(struct radeon_drm_winsys *ws);
-
#endif