/************************************************************************** * * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * 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: Thomas Hellström * Keith Whitwell */ #include #include #include "glthread.h" #include "errno.h" #include "dri_bufmgr.h" #include "string.h" #include "imports.h" #include "dri_bufpool.h" _glthread_DECLARE_STATIC_MUTEX(bmMutex); /* * TODO: Introduce fence pools in the same way as * buffer object pools. */ typedef struct _DriFenceObject { int fd; _glthread_Mutex mutex; int refCount; const char *name; drmFence fence; } DriFenceObject; typedef struct _DriBufferObject { DriBufferPool *pool; _glthread_Mutex mutex; int refCount; const char *name; unsigned flags; unsigned hint; unsigned alignment; void *private; /* user-space buffer: */ unsigned userBuffer; void *userData; unsigned userSize; } DriBufferObject; void bmError(int val, const char *file, const char *function, int line) { _mesa_printf("Fatal video memory manager error \"%s\".\n" "Check kernel logs or set the LIBGL_DEBUG\n" "environment variable to \"verbose\" for more info.\n" "Detected in file %s, line %d, function %s.\n", strerror(-val), file, line, function); #ifndef NDEBUG abort(); #else abort(); #endif } DriFenceObject * driFenceBuffers(int fd, char *name, unsigned flags) { DriFenceObject *fence = (DriFenceObject *) malloc(sizeof(*fence)); int ret; if (!fence) BM_CKFATAL(-EINVAL); _glthread_LOCK_MUTEX(bmMutex); fence->refCount = 1; fence->name = name; fence->fd = fd; _glthread_INIT_MUTEX(fence->mutex); ret = drmFenceBuffers(fd, flags, &fence->fence); _glthread_UNLOCK_MUTEX(bmMutex); if (ret) { free(fence); BM_CKFATAL(ret); } return fence; } unsigned driFenceType(DriFenceObject * fence) { unsigned ret; _glthread_LOCK_MUTEX(bmMutex); ret = fence->fence.flags; _glthread_UNLOCK_MUTEX(bmMutex); return ret; } DriFenceObject * driFenceReference(DriFenceObject * fence) { _glthread_LOCK_MUTEX(bmMutex); ++fence->refCount; _glthread_UNLOCK_MUTEX(bmMutex); return fence; } void driFenceUnReference(DriFenceObject * fence) { if (!fence) return; _glthread_LOCK_MUTEX(bmMutex); if (--fence->refCount == 0) { drmFenceDestroy(fence->fd, &fence->fence); free(fence); } _glthread_UNLOCK_MUTEX(bmMutex); } void driFenceFinish(DriFenceObject * fence, unsigned type, int lazy) { int ret; unsigned flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; _glthread_LOCK_MUTEX(fence->mutex); ret = drmFenceWait(fence->fd, flags, &fence->fence, type); _glthread_UNLOCK_MUTEX(fence->mutex); BM_CKFATAL(ret); } int driFenceSignaled(DriFenceObject * fence, unsigned type) { int signaled; int ret; if (fence == NULL) return GL_TRUE; _glthread_LOCK_MUTEX(fence->mutex); ret = drmFenceSignaled(fence->fd, &fence->fence, type, &signaled); _glthread_UNLOCK_MUTEX(fence->mutex); BM_CKFATAL(ret); return signaled; } extern drmBO * driBOKernel(struct _DriBufferObject *buf) { drmBO *ret; assert(buf->private != NULL); ret = buf->pool->kernel(buf->pool, buf->private); if (!ret) BM_CKFATAL(-EINVAL); return ret; } void driBOWaitIdle(struct _DriBufferObject *buf, int lazy) { struct _DriBufferPool *pool; void *priv; _glthread_LOCK_MUTEX(buf->mutex); pool = buf->pool; priv = buf->private; _glthread_UNLOCK_MUTEX(buf->mutex); assert(priv != NULL); BM_CKFATAL(buf->pool->waitIdle(pool, priv, lazy)); } void * driBOMap(struct _DriBufferObject *buf, unsigned flags, unsigned hint) { if (buf->userBuffer) { return buf->userData; } else { void *virtual; assert(buf->private != NULL); _glthread_LOCK_MUTEX(buf->mutex); BM_CKFATAL(buf->pool->map(buf->pool, buf->private, flags, hint, &virtual)); _glthread_UNLOCK_MUTEX(buf->mutex); return virtual; } } void driBOUnmap(struct _DriBufferObject *buf) { if (!buf->userBuffer) { assert(buf->private != NULL); buf->pool->unmap(buf->pool, buf->private); } } unsigned long driBOOffset(struct _DriBufferObject *buf) { unsigned long ret; assert(buf->private != NULL); _glthread_LOCK_MUTEX(buf->mutex); ret = buf->pool->offset(buf->pool, buf->private); _glthread_UNLOCK_MUTEX(buf->mutex); return ret; } unsigned driBOFlags(struct _DriBufferObject *buf) { unsigned ret; assert(buf->private != NULL); _glthread_LOCK_MUTEX(buf->mutex); ret = buf->pool->flags(buf->pool, buf->private); _glthread_UNLOCK_MUTEX(buf->mutex); return ret; } struct _DriBufferObject * driBOReference(struct _DriBufferObject *buf) { _glthread_LOCK_MUTEX(bmMutex); if (++buf->refCount == 1) { BM_CKFATAL(-EINVAL); } _glthread_UNLOCK_MUTEX(bmMutex); return buf; } void driBOUnReference(struct _DriBufferObject *buf) { int tmp; if (!buf) return; _glthread_LOCK_MUTEX(bmMutex); tmp = --buf->refCount; _glthread_UNLOCK_MUTEX(bmMutex); if (!tmp) { if (buf->private) buf->pool->destroy(buf->pool, buf->private); free(buf); } } void driBOData(struct _DriBufferObject *buf, unsigned size, const void *data, unsigned flags) { void *virtual; int newBuffer; struct _DriBufferPool *pool; assert(!buf->userBuffer); /* XXX just do a memcpy? */ _glthread_LOCK_MUTEX(buf->mutex); pool = buf->pool; if (!pool->create) { _mesa_error(NULL, GL_INVALID_OPERATION, "driBOData called on invalid buffer\n"); BM_CKFATAL(-EINVAL); } newBuffer = !buf->private || (pool->size(pool, buf->private) < size) || pool->map(pool, buf->private, DRM_BO_FLAG_WRITE, DRM_BO_HINT_DONT_BLOCK, &virtual); if (newBuffer) { if (buf->private) pool->destroy(pool, buf->private); if (!flags) flags = buf->flags; buf->private = pool->create(pool, size, flags, DRM_BO_HINT_DONT_FENCE, buf->alignment); if (!buf->private) BM_CKFATAL(-ENOMEM); BM_CKFATAL(pool->map(pool, buf->private, DRM_BO_FLAG_WRITE, DRM_BO_HINT_DONT_BLOCK, &virtual)); } if (data != NULL) memcpy(virtual, data, size); BM_CKFATAL(pool->unmap(pool, buf->private)); _glthread_UNLOCK_MUTEX(buf->mutex); } void driBOSubData(struct _DriBufferObject *buf, unsigned long offset, unsigned long size, const void *data) { void *virtual; assert(!buf->userBuffer); /* XXX just do a memcpy? */ _glthread_LOCK_MUTEX(buf->mutex); if (size && data) { BM_CKFATAL(buf->pool->map(buf->pool, buf->private, DRM_BO_FLAG_WRITE, 0, &virtual)); memcpy((unsigned char *) virtual + offset, data, size); BM_CKFATAL(buf->pool->unmap(buf->pool, buf->private)); } _glthread_UNLOCK_MUTEX(buf->mutex); } void driBOGetSubData(struct _DriBufferObject *buf, unsigned long offset, unsigned long size, void *data) { void *virtual; assert(!buf->userBuffer); /* XXX just do a memcpy? */ _glthread_LOCK_MUTEX(buf->mutex); if (size && data) { BM_CKFATAL(buf->pool->map(buf->pool, buf->private, DRM_BO_FLAG_READ, 0, &virtual)); memcpy(data, (unsigned char *) virtual + offset, size); BM_CKFATAL(buf->pool->unmap(buf->pool, buf->private)); } _glthread_UNLOCK_MUTEX(buf->mutex); } void driBOSetStatic(struct _DriBufferObject *buf, unsigned long offset, unsigned long size, void *virtual, unsigned flags) { assert(!buf->userBuffer); /* XXX what to do? */ _glthread_LOCK_MUTEX(buf->mutex); if (buf->private != NULL) { _mesa_error(NULL, GL_INVALID_OPERATION, "Invalid buffer for setStatic\n"); BM_CKFATAL(-EINVAL); } if (buf->pool->setstatic == NULL) { _mesa_error(NULL, GL_INVALID_OPERATION, "Invalid buffer pool for setStatic\n"); BM_CKFATAL(-EINVAL); } if (!flags) flags = buf->flags; buf->private = buf->pool->setstatic(buf->pool, offset, size, virtual, flags); if (!buf->private) { _mesa_error(NULL, GL_OUT_OF_MEMORY, "Invalid buffer pool for setStatic\n"); BM_CKFATAL(-ENOMEM); } _glthread_UNLOCK_MUTEX(buf->mutex); } void driGenBuffers(struct _DriBufferPool *pool, const char *name, unsigned n, struct _DriBufferObject *buffers[], unsigned alignment, unsigned flags, unsigned hint) { struct _DriBufferObject *buf; int i; flags = (flags) ? flags : DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE; for (i = 0; i < n; ++i) { buf = (struct _DriBufferObject *) calloc(1, sizeof(*buf)); if (!buf) BM_CKFATAL(-ENOMEM); _glthread_INIT_MUTEX(buf->mutex); _glthread_LOCK_MUTEX(buf->mutex); _glthread_LOCK_MUTEX(bmMutex); buf->refCount = 1; _glthread_UNLOCK_MUTEX(bmMutex); buf->flags = flags; buf->hint = hint; buf->name = name; buf->alignment = alignment; buf->pool = pool; _glthread_UNLOCK_MUTEX(buf->mutex); buffers[i] = buf; } } void driGenUserBuffer(struct _DriBufferPool *pool, const char *name, struct _DriBufferObject **buffers, void *ptr, unsigned bytes) { const unsigned alignment = 1, flags = 0, hint = 0; driGenBuffers(pool, name, 1, buffers, alignment, flags, hint); (*buffers)->userBuffer = 1; (*buffers)->userData = ptr; (*buffers)->userSize = bytes; } void driDeleteBuffers(unsigned n, struct _DriBufferObject *buffers[]) { int i; for (i = 0; i < n; ++i) { driBOUnReference(buffers[i]); } } void driInitBufMgr(int fd) { ; } void driBOCreateList(int target, drmBOList * list) { _glthread_LOCK_MUTEX(bmMutex); BM_CKFATAL(drmBOCreateList(target, list)); _glthread_UNLOCK_MUTEX(bmMutex); } void driBOResetList(drmBOList * list) { _glthread_LOCK_MUTEX(bmMutex); BM_CKFATAL(drmBOResetList(list)); _glthread_UNLOCK_MUTEX(bmMutex); } void driBOAddListItem(drmBOList * list, struct _DriBufferObject *buf, unsigned flags, unsigned mask) { int newItem; _glthread_LOCK_MUTEX(buf->mutex); _glthread_LOCK_MUTEX(bmMutex); BM_CKFATAL(drmAddValidateItem(list, driBOKernel(buf), flags, mask, &newItem)); _glthread_UNLOCK_MUTEX(bmMutex); /* * Tell userspace pools to validate the buffer. This should be a * noop if the pool is already validated. * FIXME: We should have a list for this as well. */ if (buf->pool->validate) { BM_CKFATAL(buf->pool->validate(buf->pool, buf->private)); } _glthread_UNLOCK_MUTEX(buf->mutex); } void driBOFence(struct _DriBufferObject *buf, struct _DriFenceObject *fence) { _glthread_LOCK_MUTEX(buf->mutex); BM_CKFATAL(buf->pool->fence(buf->pool, buf->private, fence)); _glthread_UNLOCK_MUTEX(buf->mutex); } void driBOValidateList(int fd, drmBOList * list) { _glthread_LOCK_MUTEX(bmMutex); BM_CKFATAL(drmBOValidateList(fd, list)); _glthread_UNLOCK_MUTEX(bmMutex); } void driPoolTakeDown(struct _DriBufferPool *pool) { pool->takeDown(pool); }