From: Keith Whitwell Date: Wed, 1 Nov 2006 14:21:57 +0000 (+0000) Subject: Merge texmem-0-3-branch. X-Git-Tag: 062012170305~20245 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5ac93f86210eb5c2a8dee74ec19b0ecd54376863;p=profile%2Fivi%2Fmesa.git Merge texmem-0-3-branch. --- diff --git a/src/mesa/drivers/dri/Makefile.template b/src/mesa/drivers/dri/Makefile.template index 1040194..5261a4b 100644 --- a/src/mesa/drivers/dri/Makefile.template +++ b/src/mesa/drivers/dri/Makefile.template @@ -9,7 +9,12 @@ COMMON_SOURCES = \ ../common/vblank.c \ ../common/dri_util.c \ ../common/xmlconfig.c \ - ../common/drirenderbuffer.c + ../common/drirenderbuffer.c + +COMMON_BM_SOURCES = \ + ../common/dri_bufmgr.c \ + ../common/dri_drmpool.c + ifeq ($(WINDOW_SYSTEM),dri) WINOBJ= diff --git a/src/mesa/drivers/dri/common/dri_bufmgr.c b/src/mesa/drivers/dri/common/dri_bufmgr.c new file mode 100644 index 0000000..370b56c --- /dev/null +++ b/src/mesa/drivers/dri/common/dri_bufmgr.c @@ -0,0 +1,493 @@ +/************************************************************************** + * + * 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; +} 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) +{ + assert(buf->private != NULL); + + _glthread_LOCK_MUTEX(buf->mutex); + BM_CKFATAL(buf->pool->waitIdle(buf->pool, buf->private, lazy)); + _glthread_UNLOCK_MUTEX(buf->mutex); +} + +void * +driBOMap(struct _DriBufferObject *buf, unsigned flags, unsigned hint) +{ + 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) +{ + 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) { + 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; + + _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, 0, 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; + + _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; + + _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) +{ + _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 +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(20, 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); + +} diff --git a/src/mesa/drivers/dri/common/dri_bufmgr.h b/src/mesa/drivers/dri/common/dri_bufmgr.h new file mode 100644 index 0000000..01f149a --- /dev/null +++ b/src/mesa/drivers/dri/common/dri_bufmgr.h @@ -0,0 +1,99 @@ +/************************************************************************** + * + * 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 + */ + +#ifndef _DRI_BUFMGR_H_ +#define _DRI_BUFMGR_H_ +#include + + +struct _DriFenceObject; +struct _DriBufferObject; +struct _DriBufferPool; + +extern struct _DriFenceObject *driFenceBuffers(int fd, char *name, + unsigned flags); + +extern struct _DriFenceObject *driFenceReference(struct _DriFenceObject *fence); + +extern void driFenceUnReference(struct _DriFenceObject *fence); + +extern void +driFenceFinish(struct _DriFenceObject *fence, unsigned type, int lazy); + +extern int driFenceSignaled(struct _DriFenceObject *fence, unsigned type); +extern unsigned driFenceType(struct _DriFenceObject *fence); + +/* + * Return a pointer to the libdrm buffer object this DriBufferObject + * uses. + */ + +extern drmBO *driBOKernel(struct _DriBufferObject *buf); +extern void *driBOMap(struct _DriBufferObject *buf, unsigned flags, + unsigned hint); +extern void driBOUnmap(struct _DriBufferObject *buf); +extern unsigned long driBOOffset(struct _DriBufferObject *buf); +extern unsigned driBOFlags(struct _DriBufferObject *buf); +extern struct _DriBufferObject *driBOReference(struct _DriBufferObject *buf); +extern void driBOUnReference(struct _DriBufferObject *buf); +extern void driBOData(struct _DriBufferObject *r_buf, + unsigned size, const void *data, unsigned flags); +extern void driBOSubData(struct _DriBufferObject *buf, + unsigned long offset, unsigned long size, + const void *data); +extern void driBOGetSubData(struct _DriBufferObject *buf, + unsigned long offset, unsigned long size, + void *data); +extern void driGenBuffers(struct _DriBufferPool *pool, + const char *name, + unsigned n, + struct _DriBufferObject *buffers[], + unsigned alignment, unsigned flags, unsigned hint); +extern void driDeleteBuffers(unsigned n, struct _DriBufferObject *buffers[]); +extern void driInitBufMgr(int fd); +extern void driBOCreateList(int target, drmBOList * list); +extern void driBOResetList(drmBOList * list); +extern void driBOAddListItem(drmBOList * list, struct _DriBufferObject *buf, + unsigned flags, unsigned mask); +extern void driBOValidateList(int fd, drmBOList * list); + +extern void driBOFence(struct _DriBufferObject *buf, + struct _DriFenceObject *fence); + +extern void driPoolTakeDown(struct _DriBufferPool *pool); +extern void driBOSetStatic(struct _DriBufferObject *buf, + unsigned long offset, + unsigned long size, void *virtual, unsigned flags); +extern void driBOWaitIdle(struct _DriBufferObject *buf, int lazy); +extern void driPoolTakeDown(struct _DriBufferPool *pool); + +#endif diff --git a/src/mesa/drivers/dri/common/dri_bufpool.h b/src/mesa/drivers/dri/common/dri_bufpool.h new file mode 100644 index 0000000..c6fb2c3 --- /dev/null +++ b/src/mesa/drivers/dri/common/dri_bufpool.h @@ -0,0 +1,86 @@ +/************************************************************************** + * + * 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 + */ + +#ifndef _DRI_BUFPOOL_H_ +#define _DRI_BUFPOOL_H_ + +#include +struct _DriFenceObject; + +typedef struct _DriBufferPool +{ + int fd; + int (*map) (struct _DriBufferPool * pool, void *private, + unsigned flags, int hint, void **virtual); + int (*unmap) (struct _DriBufferPool * pool, void *private); + int (*destroy) (struct _DriBufferPool * pool, void *private); + unsigned long (*offset) (struct _DriBufferPool * pool, void *private); + unsigned (*flags) (struct _DriBufferPool * pool, void *private); + unsigned long (*size) (struct _DriBufferPool * pool, void *private); + void *(*create) (struct _DriBufferPool * pool, unsigned long size, + unsigned flags, unsigned hint, unsigned alignment); + int (*fence) (struct _DriBufferPool * pool, void *private, + struct _DriFenceObject * fence); + drmBO *(*kernel) (struct _DriBufferPool * pool, void *private); + int (*validate) (struct _DriBufferPool * pool, void *private); + void *(*setstatic) (struct _DriBufferPool * pool, unsigned long offset, + unsigned long size, void *virtual, unsigned flags); + int (*waitIdle) (struct _DriBufferPool *pool, void *private, + int lazy); + void (*takeDown) (struct _DriBufferPool * pool); + void *data; +} DriBufferPool; + +extern void bmError(int val, const char *file, const char *function, + int line); +#define BM_CKFATAL(val) \ + do{ \ + int tstVal = (val); \ + if (tstVal) \ + bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \ + } while(0); + + + + + +/* + * Builtin pools. + */ + +/* + * Kernel buffer objects. Size in multiples of page size. Page size aligned. + */ + +extern struct _DriBufferPool *driDRMPoolInit(int fd); +extern struct _DriBufferPool *driDRMStaticPoolInit(int fd); + +#endif diff --git a/src/mesa/drivers/dri/common/dri_drmpool.c b/src/mesa/drivers/dri/common/dri_drmpool.c new file mode 100644 index 0000000..b5b324b --- /dev/null +++ b/src/mesa/drivers/dri/common/dri_drmpool.c @@ -0,0 +1,227 @@ +/************************************************************************** + * + * 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 + */ + +#include +#include +#include +#include "dri_bufpool.h" + +/* + * Buffer pool implementation using DRM buffer objects as DRI buffer objects. + */ + +static void * +pool_create(struct _DriBufferPool *pool, + unsigned long size, unsigned flags, unsigned hint, + unsigned alignment) +{ + drmBO *buf = (drmBO *) malloc(sizeof(*buf)); + int ret; + unsigned pageSize = getpagesize(); + + if (!buf) + return NULL; + + if ((alignment > pageSize) && (alignment % pageSize)) { + return NULL; + } + + ret = drmBOCreate(pool->fd, 0, size, alignment / pageSize, + NULL, drm_bo_type_dc, + flags, hint, buf); + if (ret) { + free(buf); + return NULL; + } + + return (void *) buf; +} + +static int +pool_destroy(struct _DriBufferPool *pool, void *private) +{ + int ret; + drmBO *buf = (drmBO *) private; + ret = drmBODestroy(pool->fd, buf); + free(buf); + return ret; +} + +static int +pool_map(struct _DriBufferPool *pool, void *private, unsigned flags, + int hint, void **virtual) +{ + drmBO *buf = (drmBO *) private; + + return drmBOMap(pool->fd, buf, flags, hint, virtual); +} + +static int +pool_unmap(struct _DriBufferPool *pool, void *private) +{ + drmBO *buf = (drmBO *) private; + return drmBOUnmap(pool->fd, buf); +} + +static unsigned long +pool_offset(struct _DriBufferPool *pool, void *private) +{ + drmBO *buf = (drmBO *) private; + return buf->offset; +} + +static unsigned +pool_flags(struct _DriBufferPool *pool, void *private) +{ + drmBO *buf = (drmBO *) private; + return buf->flags; +} + + +static unsigned long +pool_size(struct _DriBufferPool *pool, void *private) +{ + drmBO *buf = (drmBO *) private; + return buf->size; +} + +static int +pool_fence(struct _DriBufferPool *pool, void *private, + struct _DriFenceObject *fence) +{ + /* + * Noop. The kernel handles all fencing. + */ + + return 0; +} + +static drmBO * +pool_kernel(struct _DriBufferPool *pool, void *private) +{ + return (drmBO *) private; +} + +static int +pool_waitIdle(struct _DriBufferPool *pool, void *private, int lazy) +{ + drmBO *buf = (drmBO *) private; + return drmBOWaitIdle(pool->fd, buf, (lazy) ? DRM_BO_HINT_WAIT_LAZY:0); +} + + +static void +pool_takedown(struct _DriBufferPool *pool) +{ + free(pool); +} + + +struct _DriBufferPool * +driDRMPoolInit(int fd) +{ + struct _DriBufferPool *pool; + + pool = (struct _DriBufferPool *) malloc(sizeof(*pool)); + + if (!pool) + return NULL; + + pool->fd = fd; + pool->map = &pool_map; + pool->unmap = &pool_unmap; + pool->destroy = &pool_destroy; + pool->offset = &pool_offset; + pool->flags = &pool_flags; + pool->size = &pool_size; + pool->create = &pool_create; + pool->fence = &pool_fence; + pool->kernel = &pool_kernel; + pool->validate = NULL; + pool->setstatic = NULL; + pool->waitIdle = &pool_waitIdle; + pool->takeDown = &pool_takedown; + pool->data = NULL; + return pool; +} + + +static void * +pool_setstatic(struct _DriBufferPool *pool, unsigned long offset, + unsigned long size, void *virtual, unsigned flags) +{ + drmBO *buf = (drmBO *) malloc(sizeof(*buf)); + int ret; + + if (!buf) + return NULL; + + ret = drmBOCreate(pool->fd, offset, size, 0, NULL, drm_bo_type_fake, + flags, 0, buf); + + if (ret) { + free(buf); + return NULL; + } + + buf->virtual = virtual; + + return (void *) buf; +} + + +struct _DriBufferPool * +driDRMStaticPoolInit(int fd) +{ + struct _DriBufferPool *pool; + + pool = (struct _DriBufferPool *) malloc(sizeof(*pool)); + + if (!pool) + return NULL; + + pool->fd = fd; + pool->map = &pool_map; + pool->unmap = &pool_unmap; + pool->destroy = &pool_destroy; + pool->offset = &pool_offset; + pool->flags = &pool_flags; + pool->size = &pool_size; + pool->create = NULL; + pool->fence = &pool_fence; + pool->kernel = &pool_kernel; + pool->validate = NULL; + pool->setstatic = &pool_setstatic; + pool->waitIdle = &pool_waitIdle; + pool->takeDown = &pool_takedown; + pool->data = NULL; + return pool; +} diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index 1ca2756..e7f0756 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -849,7 +849,7 @@ static void driDestroyScreen(__DRInativeDisplay *dpy, int scrn, void *screenPriv (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); _mesa_free(psp->pDevPriv); - (void)drmClose(psp->fd); + (void)drmCloseOnce(psp->fd); if ( psp->modes != NULL ) { (*dri_interface->destroyContextModes)( psp->modes ); } diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h index 885d589..e43e653 100644 --- a/src/mesa/drivers/dri/common/dri_util.h +++ b/src/mesa/drivers/dri/common/dri_util.h @@ -87,15 +87,15 @@ typedef struct __DRIutilversionRec2 __DRIutilversion2; #define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \ do { \ while (*(pdp->pStamp) != pdp->lastStamp) { \ - DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, \ - pdp->driContextPriv->hHWContext); \ + register unsigned int hwContext = psp->pSAREA->lock.lock & \ + ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ + DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ \ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ \ - DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, \ - pdp->driContextPriv->hHWContext); \ + DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ } \ } while (0) diff --git a/src/mesa/drivers/dri/i915tex/Makefile b/src/mesa/drivers/dri/i915tex/Makefile index d57a651..94879d2 100644 --- a/src/mesa/drivers/dri/i915tex/Makefile +++ b/src/mesa/drivers/dri/i915tex/Makefile @@ -54,6 +54,7 @@ DRIVER_SOURCES = \ C_SOURCES = \ $(COMMON_SOURCES) \ + $(COMMON_BM_SOURCES) \ $(DRIVER_SOURCES) ASM_SOURCES = diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c index ef970ad..e22edc1 100644 --- a/src/mesa/main/attrib.c +++ b/src/mesa/main/attrib.c @@ -337,6 +337,8 @@ _mesa_PushAttrib(GLbitfield mask) if (mask & GL_TEXTURE_BIT) { struct gl_texture_attrib *attr; GLuint u; + + _mesa_lock_context_textures(ctx); /* Bump the texture object reference counts so that they don't * inadvertantly get deleted. */ @@ -362,6 +364,9 @@ _mesa_PushAttrib(GLbitfield mask) _mesa_copy_texture_object(&attr->Unit[u].SavedRect, attr->Unit[u].CurrentRect); } + + _mesa_unlock_context_textures(ctx); + newnode = new_attrib_node( GL_TEXTURE_BIT ); newnode->data = attr; newnode->next = head; diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 8aa6828..c8acc6b 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -735,6 +735,10 @@ alloc_shared_state( GLcontext *ctx ) ss->DefaultCubeMap->RefCount += MAX_TEXTURE_IMAGE_UNITS; ss->DefaultRect->RefCount += MAX_TEXTURE_IMAGE_UNITS; + _glthread_INIT_MUTEX(ss->TexMutex); + ss->TextureStateStamp = 0; + + #if FEATURE_EXT_framebuffer_object ss->FrameBuffers = _mesa_NewHashTable(); if (!ss->FrameBuffers) diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 2ca1014..cf8de1e 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -979,7 +979,9 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) } FLUSH_VERTICES(ctx, _NEW_BUFFERS); - + if (ctx->Driver.Flush) { + ctx->Driver.Flush(ctx); + } if (framebuffer) { /* Binding a user-created framebuffer object */ newFb = _mesa_lookup_framebuffer(ctx, framebuffer); @@ -1548,7 +1550,9 @@ _mesa_GenerateMipmapEXT(GLenum target) texObj = _mesa_select_tex_object(ctx, texUnit, target); /* XXX this might not handle cube maps correctly */ + _mesa_lock_texture(ctx, texObj); _mesa_generate_mipmap(ctx, target, texUnit, texObj); + _mesa_unlock_texture(ctx, texObj); } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 4803d0c..1399ddd 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2063,6 +2063,19 @@ struct gl_shared_state /*@}*/ /** + * \name Thread safety and statechange notification for texture + * objects. + * + * \todo Improve the granularity of locking. + */ + /*@{*/ + _glthread_Mutex TexMutex; /**< texobj thread safety */ + GLuint TextureStateStamp; /**< state notification for shared tex */ + /*@}*/ + + + + /** * \name Vertex/fragment programs */ /*@{*/ @@ -2931,6 +2944,8 @@ struct __GLcontextRec GLboolean _ForceEyeCoords; GLenum _CurrentProgram; /* currently executing program */ + GLuint TextureStateTimestamp; /* detect changes to shared state */ + struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */ struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */ /**@}*/ diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 7dbcf8a..8bc4036 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -1003,7 +1003,7 @@ update_color(GLcontext *ctx) * _mesa_update_lighting() and _mesa_update_tnl_spaces(). */ void -_mesa_update_state( GLcontext *ctx ) +_mesa_update_state_locked( GLcontext *ctx ) { GLbitfield new_state = ctx->NewState; @@ -1084,4 +1084,17 @@ _mesa_update_state( GLcontext *ctx ) ctx->Array.NewState = 0; } + +/* This is the usual entrypoint for state updates: + */ +void +_mesa_update_state( GLcontext *ctx ) +{ + _mesa_lock_context_textures(ctx); + _mesa_update_state_locked(ctx); + _mesa_unlock_context_textures(ctx); +} + + + /*@}*/ diff --git a/src/mesa/main/state.h b/src/mesa/main/state.h index 58cfcc4..5240d4b 100644 --- a/src/mesa/main/state.h +++ b/src/mesa/main/state.h @@ -39,5 +39,11 @@ _mesa_init_exec_table(struct _glapi_table *exec); extern void _mesa_update_state( GLcontext *ctx ); +/* As above but can only be called between _mesa_lock_context_textures() and + * _mesa_unlock_context_textures(). + */ +extern void +_mesa_update_state_locked( GLcontext *ctx ); + #endif diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index c2ba450..662f697 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -706,9 +706,12 @@ _mesa_free_texture_image_data(GLcontext *ctx, void _mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage ) { - if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } + /* Free texImage->Data and/or any other driver-specific texture + * image storage. + */ + ASSERT(ctx->Driver.FreeTexImageData); + ctx->Driver.FreeTexImageData( ctx, texImage ); + ASSERT(texImage->Data == NULL); if (texImage->ImageOffsets) _mesa_free(texImage->ImageOffsets); @@ -801,24 +804,23 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit, * \sa gl_texture_unit. */ struct gl_texture_image * -_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, - GLenum target, GLint level) +_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj, + GLenum target, GLint level) { - ASSERT(texUnit); - ASSERT(level < MAX_TEXTURE_LEVELS); + ASSERT(texObj); + + if (level < 0 || level >= MAX_TEXTURE_LEVELS) + return NULL; + switch (target) { case GL_TEXTURE_1D: - return texUnit->Current1D->Image[0][level]; case GL_PROXY_TEXTURE_1D: - return ctx->Texture.Proxy1D->Image[0][level]; case GL_TEXTURE_2D: - return texUnit->Current2D->Image[0][level]; case GL_PROXY_TEXTURE_2D: - return ctx->Texture.Proxy2D->Image[0][level]; case GL_TEXTURE_3D: - return texUnit->Current3D->Image[0][level]; case GL_PROXY_TEXTURE_3D: - return ctx->Texture.Proxy3D->Image[0][level]; + return texObj->Image[0][level]; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: @@ -828,33 +830,25 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, if (ctx->Extensions.ARB_texture_cube_map) { GLuint face = ((GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X); - return texUnit->CurrentCubeMap->Image[face][level]; + return texObj->Image[face][level]; } else return NULL; + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: if (ctx->Extensions.ARB_texture_cube_map) - return ctx->Texture.ProxyCubeMap->Image[0][level]; + return texObj->Image[0][level]; else return NULL; + case GL_TEXTURE_RECTANGLE_NV: - if (ctx->Extensions.NV_texture_rectangle) { - ASSERT(level == 0); - return texUnit->CurrentRect->Image[0][level]; - } - else { - return NULL; - } case GL_PROXY_TEXTURE_RECTANGLE_NV: - if (ctx->Extensions.NV_texture_rectangle) { - ASSERT(level == 0); - return ctx->Texture.ProxyRect->Image[0][level]; - } - else { + if (ctx->Extensions.NV_texture_rectangle && level == 0) + return texObj->Image[0][level]; + else return NULL; - } + default: - _mesa_problem(ctx, "bad target in _mesa_select_tex_image()"); return NULL; } } @@ -866,22 +860,25 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, * out of memory. */ struct gl_texture_image * -_mesa_get_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, +_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj, GLenum target, GLint level) { struct gl_texture_image *texImage; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + + if (!texObj) + return NULL; + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { - struct gl_texture_object *texObj; texImage = ctx->Driver.NewTextureImage(ctx); if (!texImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation"); return NULL; } - texObj = _mesa_select_tex_object(ctx, texUnit, target); - ASSERT(texObj); + _mesa_set_tex_image(texObj, target, level, texImage); } + return texImage; } @@ -1584,9 +1581,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, GLint width, GLint height, GLint depth, GLenum format, GLenum type ) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - struct gl_texture_image *destTex; - /* Check target */ if (dimensions == 1) { if (target != GL_TEXTURE_1D) { @@ -1602,8 +1596,7 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } } - else if (ctx->Extensions.NV_texture_rectangle && - target == GL_TEXTURE_RECTANGLE_NV) { + else if (target == GL_TEXTURE_RECTANGLE_NV) { if (!ctx->Extensions.NV_texture_rectangle) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" ); return GL_TRUE; @@ -1647,8 +1640,23 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - destTex = _mesa_select_tex_image(ctx, texUnit, target, level); + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexSubImage%dD(format or type)", dimensions); + return GL_TRUE; + } + + return GL_FALSE; +} +static GLboolean +subtexture_error_check2( GLcontext *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, + const struct gl_texture_image *destTex ) +{ if (!destTex) { /* undefined image level */ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions); @@ -1688,12 +1696,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } } - if (!_mesa_is_legal_format_and_type(ctx, format, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexSubImage%dD(format or type)", dimensions); - return GL_TRUE; - } - #if FEATURE_EXT_texture_sRGB if (destTex->InternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT || destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT || @@ -1709,11 +1711,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, #endif if (destTex->IsCompressed) { - const struct gl_texture_unit *texUnit; - const struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) { /* OK */ } @@ -1735,12 +1732,12 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } /* size must be multiple of 4 or equal to whole texture size */ - if ((width & 3) && (GLuint) width != texImage->Width) { + if ((width & 3) && (GLuint) width != destTex->Width) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%D(width)", dimensions); return GL_TRUE; } - if ((height & 3) && (GLuint) height != texImage->Height) { + if ((height & 3) && (GLuint) height != destTex->Height) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%D(width)", dimensions); return GL_TRUE; @@ -1781,6 +1778,11 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(level=%d)", dimensions, level); + return GL_TRUE; + } + /* Check that the source buffer is complete */ if (ctx->ReadBuffer->Name) { _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); @@ -1791,11 +1793,6 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, } } - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(level=%d)", dimensions, level); - return GL_TRUE; - } - /* Check border */ if (border < 0 || border > 1 || ((target == GL_TEXTURE_RECTANGLE_NV || @@ -1945,11 +1942,8 @@ static GLboolean copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height ) + GLsizei width, GLsizei height) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - struct gl_texture_image *teximage; - /* Check target */ /* Check that the source buffer is complete */ if (ctx->ReadBuffer->Name) { @@ -2012,7 +2006,16 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - teximage = _mesa_select_tex_image(ctx, texUnit, target, level); + return GL_FALSE; +} + +static GLboolean +copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + const struct gl_texture_image *teximage ) +{ if (!teximage) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage%dD(undefined texture level: %d)", @@ -2186,59 +2189,66 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, if (!pixels) return; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (!texImage) { - /* invalid mipmap level, not an error */ - return; - } + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + /* invalid mipmap level, not an error */ + goto out; + } - /* Make sure the requested image format is compatible with the - * texture's format. Note that a color index texture can be converted - * to RGBA so that combo is allowed. - */ - if (is_color_format(format) - && !is_color_format(texImage->TexFormat->BaseFormat) - && !is_index_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_index_format(format) - && !is_index_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_depth_format(format) - && !is_depth_format(texImage->TexFormat->BaseFormat) - && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_ycbcr_format(format) - && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_depthstencil_format(format) - && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - if (ctx->Pack.BufferObj->Name) { - /* packing texture image into a PBO */ - const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; - if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, - texImage->Height, texImage->Depth, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetTexImage(invalid PBO access)"); - return; + /* Make sure the requested image format is compatible with the + * texture's format. Note that a color index texture can be converted + * to RGBA so that combo is allowed. + */ + if (is_color_format(format) + && !is_color_format(texImage->TexFormat->BaseFormat) + && !is_index_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_index_format(format) + && !is_index_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_depth_format(format) + && !is_depth_format(texImage->TexFormat->BaseFormat) + && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_ycbcr_format(format) + && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_depthstencil_format(format) + && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + + if (ctx->Pack.BufferObj->Name) { + /* packing texture image into a PBO */ + const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; + if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, + texImage->Height, texImage->Depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(invalid PBO access)"); + goto out; + } } - } - /* typically, this will call _mesa_get_teximage() */ - ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, - texObj, texImage); + /* typically, this will call _mesa_get_teximage() */ + ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, + texObj, texImage); + + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2301,40 +2311,47 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, return; /* error was recorded */ } - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, 1, 1, - border, internalFormat); - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_update_state(ctx); - ASSERT(ctx->Driver.TexImage1D); + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, - width, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); + ASSERT(texImage->Data == NULL); - ASSERT(texImage->TexFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, 1, 1, + border, internalFormat); + + ASSERT(ctx->Driver.TexImage1D); - update_fbo_texture(ctx, texObj, face, level); + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, + width, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + ASSERT(texImage->TexFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ @@ -2396,39 +2413,46 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, return; /* error was recorded */ } - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, postConvHeight, 1, - border, internalFormat); - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_update_state(ctx); - ASSERT(ctx->Driver.TexImage2D); - - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, - width, height, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); - - ASSERT(texImage->TexFormat); - - update_fbo_texture(ctx, texObj, face, level); - - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, postConvHeight, 1, + border, internalFormat); + + ASSERT(ctx->Driver.TexImage2D); + + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + ASSERT(texImage->TexFormat); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_2D || (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB && @@ -2486,39 +2510,46 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, return; /* error was recorded */ } + if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - width, height, depth, - border, internalFormat); - - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat); - ASSERT(ctx->Driver.TexImage3D); + ASSERT(ctx->Driver.TexImage3D); - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat, - width, height, depth, border, format, type, - pixels, &ctx->Unpack, texObj, texImage); + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat, + width, height, depth, border, format, type, + pixels, &ctx->Unpack, texObj, texImage); - ASSERT(texImage->TexFormat); + ASSERT(texImage->TexFormat); - update_fbo_texture(ctx, texObj, face, level); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ @@ -2566,7 +2597,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level, GLsizei postConvWidth = width; struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; - struct gl_texture_image *texImage; + struct gl_texture_image *texImage = NULL; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2579,26 +2610,38 @@ _mesa_TexSubImage1D( GLenum target, GLint level, } if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0, - postConvWidth, 1, 1, format, type)) { + postConvWidth, 1, 1, format, type)) { return; /* error was detected */ } + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + assert(texObj); - if (width == 0) - return; /* no-op, not an error */ + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; + if (subtexture_error_check2(ctx, 1, target, level, xoffset, 0, 0, + postConvWidth, 1, 1, format, type, texImage)) { + goto out; /* error was detected */ + } + + if (width == 0) + goto out; /* no-op, not an error */ + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; - ASSERT(ctx->Driver.TexSubImage1D); - (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width, - format, type, pixels, &ctx->Unpack, - texObj, texImage); - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.TexSubImage1D); + (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width, + format, type, pixels, &ctx->Unpack, + texObj, texImage); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2626,27 +2669,37 @@ _mesa_TexSubImage2D( GLenum target, GLint level, } if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0, - postConvWidth, postConvHeight, 1, format, type)) { + postConvWidth, postConvHeight, 1, format, type)) { return; /* error was detected */ } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - if (width == 0 || height == 0) - return; /* no-op, not an error */ + if (subtexture_error_check2(ctx, 2, target, level, xoffset, yoffset, 0, + postConvWidth, postConvHeight, 1, format, type, + texImage)) { + goto out; /* error was detected */ + } - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; + if (width == 0 || height == 0) + goto out; /* no-op, not an error */ - ASSERT(ctx->Driver.TexSubImage2D); - (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset, - width, height, format, type, pixels, - &ctx->Unpack, texObj, texImage); - ctx->NewState |= _NEW_TEXTURE; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + + ASSERT(ctx->Driver.TexSubImage2D); + (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset, + width, height, format, type, pixels, + &ctx->Unpack, texObj, texImage); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2674,24 +2727,34 @@ _mesa_TexSubImage3D( GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); - - if (width == 0 || height == 0 || height == 0) - return; /* no-op, not an error */ - - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; - zoffset += texImage->Border; - - ASSERT(ctx->Driver.TexSubImage3D); - (*ctx->Driver.TexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, type, pixels, - &ctx->Unpack, texObj, texImage ); - ctx->NewState |= _NEW_TEXTURE; + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (subtexture_error_check2(ctx, 3, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, texImage)) { + goto out; /* error was detected */ + } + + if (width == 0 || height == 0 || height == 0) + goto out; /* no-op, not an error */ + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + zoffset += texImage->Border; + + ASSERT(ctx->Driver.TexSubImage3D); + (*ctx->Driver.TexSubImage3D)(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2723,32 +2786,39 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1, - border, internalFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1, + border, internalFormat); - ASSERT(ctx->Driver.CopyTexImage1D); - (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, - x, y, width, border); + ASSERT(ctx->Driver.CopyTexImage1D); + (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, + x, y, width, border); - ASSERT(texImage->TexFormat); + ASSERT(texImage->TexFormat); - update_fbo_texture(ctx, texObj, face, level); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2780,41 +2850,50 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, postConvHeight, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); - ASSERT(ctx->Driver.CopyTexImage2D); - (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat, - x, y, width, height, border); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); - ASSERT(texImage->TexFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, postConvHeight, 1, + border, internalFormat); + + ASSERT(ctx->Driver.CopyTexImage2D); + (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat, + x, y, width, height, border); + + ASSERT(texImage->TexFormat); - update_fbo_texture(ctx, texObj, face, level); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } - void GLAPIENTRY _mesa_CopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width; GET_CURRENT_CONTEXT(ctx); @@ -2831,15 +2910,27 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (copytexsubimage_error_check2(ctx, 1, target, level, + xoffset, 0, 0, postConvWidth, 1, + texImage)) + goto out; + - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; - ASSERT(ctx->Driver.CopyTexSubImage1D); - (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width); - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.CopyTexSubImage1D); + (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2850,6 +2941,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; GET_CURRENT_CONTEXT(ctx); @@ -2866,17 +2958,27 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; + if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0, + postConvWidth, postConvHeight, texImage)) + goto out; - ASSERT(ctx->Driver.CopyTexSubImage2D); - (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level, - xoffset, yoffset, x, y, width, height); - ctx->NewState |= _NEW_TEXTURE; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + + ASSERT(ctx->Driver.CopyTexSubImage2D); + (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level, + xoffset, yoffset, x, y, width, height); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2887,6 +2989,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; GET_CURRENT_CONTEXT(ctx); @@ -2903,19 +3006,30 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; - zoffset += texImage->Border; + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - ASSERT(ctx->Driver.CopyTexSubImage3D); - (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - x, y, width, height); - ctx->NewState |= _NEW_TEXTURE; + if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset, + zoffset, postConvWidth, postConvHeight, + texImage)) + goto out; + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + zoffset += texImage->Border; + + ASSERT(ctx->Driver.CopyTexSubImage3D); + (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level, + xoffset, yoffset, zoffset, + x, y, width, height); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3136,28 +3250,35 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); + + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); - ASSERT(ctx->Driver.CompressedTexImage1D); - (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, - internalFormat, width, border, - imageSize, data, - texObj, texImage); + ASSERT(ctx->Driver.CompressedTexImage1D); + (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, + internalFormat, width, border, + imageSize, data, + texObj, texImage); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ @@ -3179,11 +3300,18 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, - border, internalFormat); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -3219,28 +3347,35 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); - ASSERT(ctx->Driver.CompressedTexImage2D); - (*ctx->Driver.CompressedTexImage2D)(ctx, target, level, - internalFormat, width, height, - border, imageSize, data, - texObj, texImage); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.CompressedTexImage2D); + (*ctx->Driver.CompressedTexImage2D)(ctx, target, level, + internalFormat, width, height, + border, imageSize, data, + texObj, texImage); + + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_2D || (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB && @@ -3264,11 +3399,18 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -3301,29 +3443,35 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - - _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); - ASSERT(ctx->Driver.CompressedTexImage3D); - (*ctx->Driver.CompressedTexImage3D)(ctx, target, level, - internalFormat, - width, height, depth, - border, imageSize, data, - texObj, texImage); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, + border, internalFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.CompressedTexImage3D); + (*ctx->Driver.CompressedTexImage3D)(ctx, target, level, + internalFormat, + width, height, depth, + border, imageSize, data, + texObj, texImage); + + /* state update */ + texObj->Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ @@ -3345,11 +3493,17 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, - depth, border, internalFormat); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -3382,30 +3536,35 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->InternalFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage1D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage1D(format)"); + goto out; + } - if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)"); - return; - } + if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)"); + goto out; + } - if (width == 0) - return; /* no-op, not an error */ + if (width == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage1D) { - (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level, - xoffset, width, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage1D) { + (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level, + xoffset, width, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3434,31 +3593,36 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->InternalFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage2D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage2D(format)"); + goto out; + } - if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || - ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)"); - return; - } + if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || + ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)"); + goto out; + } - if (width == 0 || height == 0) - return; /* no-op, not an error */ + if (width == 0 || height == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage2D) { - (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level, - xoffset, yoffset, width, height, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage2D) { + (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level, + xoffset, yoffset, width, height, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3486,33 +3650,38 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->InternalFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage3D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage3D(format)"); + goto out; + } - if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || - ((height == 1 || height == 2) && (GLuint) height != texImage->Height) || - ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)"); - return; - } + if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || + ((height == 1 || height == 2) && (GLuint) height != texImage->Height) || + ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)"); + goto out; + } - if (width == 0 || height == 0 || depth == 0) - return; /* no-op, not an error */ + if (width == 0 || height == 0 || depth == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage3D) { - (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage3D) { + (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3520,12 +3689,13 @@ void GLAPIENTRY _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) { const struct gl_texture_unit *texUnit; - const struct gl_texture_object *texObj; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLint maxLevels; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); if (!texObj) { @@ -3546,18 +3716,24 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) return; } - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (!texImage) { - /* probably invalid mipmap level */ - _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); - return; - } - if (!texImage->IsCompressed) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB"); - return; - } + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + /* probably invalid mipmap level */ + _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); + goto out; + } + + if (!texImage->IsCompressed) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB"); + goto out; + } - /* this typically calls _mesa_get_compressed_teximage() */ - ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage); + /* this typically calls _mesa_get_compressed_teximage() */ + ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage); + } + out: + _mesa_unlock_texture(ctx, texObj); } diff --git a/src/mesa/main/teximage.h b/src/mesa/main/teximage.h index 410789f..68457f4 100644 --- a/src/mesa/main/teximage.h +++ b/src/mesa/main/teximage.h @@ -84,12 +84,12 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit, extern struct gl_texture_image * -_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, +_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj, GLenum target, GLint level); extern struct gl_texture_image * -_mesa_get_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, +_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj, GLenum target, GLint level); @@ -106,6 +106,23 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, GLint internalFormat, GLenum format, GLenum type, GLint width, GLint height, GLint depth, GLint border); + +/* Lock a texture for updating. See also _mesa_lock_context_textures(). + */ +static INLINE void _mesa_lock_texture(GLcontext *ctx, + struct gl_texture_object *texObj) +{ + _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); + ctx->Shared->TextureStateStamp++; + (void) texObj; +} + +static INLINE void _mesa_unlock_texture(GLcontext *ctx, + struct gl_texture_object *texObj) +{ + _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); +} + /*@}*/ diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index 8b42c2a..1d27cd3 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -697,7 +697,11 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures) if (textures[i] > 0) { struct gl_texture_object *delObj = _mesa_lookup_texture(ctx, textures[i]); + if (delObj) { + GLboolean delete; + + _mesa_lock_texture(ctx, delObj); /* Check if texture is bound to any framebuffer objects. * If so, unbind. @@ -724,7 +728,14 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures) * XXX all RefCount accesses should be protected by a mutex. */ delObj->RefCount--; - if (delObj->RefCount == 0) { + delete = (delObj->RefCount == 0); + _mesa_unlock_texture(ctx, delObj); + + /* We know that refcount went to zero above, so this is + * the only pointer left to delObj, so we don't have to + * worry about locking any more: + */ + if (delete) { ASSERT(delObj->Name != 0); /* Never delete default tex objs */ ASSERT(ctx->Driver.DeleteTexture); (*ctx->Driver.DeleteTexture)(ctx, delObj); @@ -1052,4 +1063,30 @@ _mesa_IsTexture( GLuint texture ) return t && t->Target; } +/* Simplest implementation of texture locking: Grab the a new mutex in + * the shared context. Examine the shared context state timestamp and + * if there has been a change, set the appropriate bits in + * ctx->NewState. + * + * See also _mesa_lock/unlock_texture in texobj.h + */ +void _mesa_lock_context_textures( GLcontext *ctx ) +{ + _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); + + if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { + ctx->NewState |= _NEW_TEXTURE; + ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; + } +} + + +void _mesa_unlock_context_textures( GLcontext *ctx ) +{ + assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); + _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); +} + /*@}*/ + + diff --git a/src/mesa/main/texobj.h b/src/mesa/main/texobj.h index ac66ac6..ec7cf8c 100644 --- a/src/mesa/main/texobj.h +++ b/src/mesa/main/texobj.h @@ -61,6 +61,9 @@ extern void _mesa_test_texobj_completeness( const GLcontext *ctx, struct gl_texture_object *obj ); +extern void _mesa_unlock_context_textures( GLcontext *ctx ); +extern void _mesa_lock_context_textures( GLcontext *ctx ); + /*@}*/ @@ -95,4 +98,5 @@ _mesa_IsTexture( GLuint texture ); /*@}*/ + #endif diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index 0687e57..bcedcaf 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -144,6 +144,8 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst ) dst->Texture.Unit[i].Combine.ScaleShiftA = src->Texture.Unit[i].Combine.ScaleShiftA; /* copy texture object bindings, not contents of texture objects */ + _mesa_lock_context_textures(dst); + copy_texture_binding(src, &dst->Texture.Unit[i].Current1D, src->Texture.Unit[i].Current1D); copy_texture_binding(src, &dst->Texture.Unit[i].Current2D, @@ -154,6 +156,8 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst ) src->Texture.Unit[i].CurrentCubeMap); copy_texture_binding(src, &dst->Texture.Unit[i].CurrentRect, src->Texture.Unit[i].CurrentRect); + + _mesa_unlock_context_textures(dst); } } @@ -1700,6 +1704,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, GLenum pname, GLint *params ) { const struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; const struct gl_texture_image *img = NULL; GLuint dimensions; GLboolean isProxy; @@ -1734,14 +1739,17 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, return; } - img = _mesa_select_tex_image(ctx, texUnit, target, level); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + + img = _mesa_select_tex_image(ctx, texObj, target, level); if (!img || !img->TexFormat) { /* undefined texture image */ if (pname == GL_TEXTURE_COMPONENTS) *params = 1; else *params = 0; - return; + goto out; } isProxy = _mesa_is_proxy_texture(target); @@ -1749,37 +1757,37 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, switch (pname) { case GL_TEXTURE_WIDTH: *params = img->Width; - return; + break; case GL_TEXTURE_HEIGHT: *params = img->Height; - return; + break; case GL_TEXTURE_DEPTH: *params = img->Depth; - return; + break; case GL_TEXTURE_INTERNAL_FORMAT: *params = img->InternalFormat; - return; + break; case GL_TEXTURE_BORDER: *params = img->Border; - return; + break; case GL_TEXTURE_RED_SIZE: if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA) *params = img->TexFormat->RedBits; else *params = 0; - return; + break; case GL_TEXTURE_GREEN_SIZE: if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA) *params = img->TexFormat->GreenBits; else *params = 0; - return; + break; case GL_TEXTURE_BLUE_SIZE: if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA) *params = img->TexFormat->BlueBits; else *params = 0; - return; + break; case GL_TEXTURE_ALPHA_SIZE: if (img->_BaseFormat == GL_ALPHA || img->_BaseFormat == GL_LUMINANCE_ALPHA || @@ -1787,7 +1795,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, *params = img->TexFormat->AlphaBits; else *params = 0; - return; + break; case GL_TEXTURE_INTENSITY_SIZE: if (img->_BaseFormat != GL_INTENSITY) *params = 0; @@ -1795,7 +1803,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, *params = img->TexFormat->IntensityBits; else /* intensity probably stored as rgb texture */ *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits); - return; + break; case GL_TEXTURE_LUMINANCE_SIZE: if (img->_BaseFormat != GL_LUMINANCE && img->_BaseFormat != GL_LUMINANCE_ALPHA) @@ -1804,13 +1812,13 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, *params = img->TexFormat->LuminanceBits; else /* luminance probably stored as rgb texture */ *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits); - return; + break; case GL_TEXTURE_INDEX_SIZE_EXT: if (img->_BaseFormat == GL_COLOR_INDEX) *params = img->TexFormat->IndexBits; else *params = 0; - return; + break; case GL_TEXTURE_DEPTH_SIZE_ARB: if (ctx->Extensions.SGIX_depth_texture || ctx->Extensions.ARB_depth_texture) @@ -1818,7 +1826,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, else _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); - return; + break; case GL_TEXTURE_STENCIL_SIZE_EXT: if (ctx->Extensions.EXT_packed_depth_stencil) { *params = img->TexFormat->StencilBits; @@ -1827,7 +1835,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; /* GL_ARB_texture_compression */ case GL_TEXTURE_COMPRESSED_IMAGE_SIZE: @@ -1849,7 +1857,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_COMPRESSED: if (ctx->Extensions.ARB_texture_compression) { *params = (GLint) img->IsCompressed; @@ -1858,7 +1866,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; /* GL_ARB_texture_float */ case GL_TEXTURE_RED_TYPE_ARB: @@ -1869,7 +1877,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_GREEN_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->GreenBits ? img->TexFormat->DataType : GL_NONE; @@ -1878,7 +1886,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_BLUE_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->BlueBits ? img->TexFormat->DataType : GL_NONE; @@ -1887,7 +1895,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_ALPHA_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->AlphaBits ? img->TexFormat->DataType : GL_NONE; @@ -1896,7 +1904,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_LUMINANCE_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->LuminanceBits ? img->TexFormat->DataType : GL_NONE; @@ -1905,7 +1913,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_INTENSITY_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->IntensityBits ? img->TexFormat->DataType : GL_NONE; @@ -1914,7 +1922,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; case GL_TEXTURE_DEPTH_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = img->TexFormat->DepthBits ? img->TexFormat->DataType : GL_NONE; @@ -1923,12 +1931,15 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } - return; + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname)"); } + + out: + _mesa_unlock_texture(ctx, texObj); } @@ -1938,6 +1949,7 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) { struct gl_texture_unit *texUnit; struct gl_texture_object *obj; + GLboolean error = GL_FALSE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1955,28 +1967,29 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) return; } + _mesa_lock_texture(ctx, obj); switch (pname) { case GL_TEXTURE_MAG_FILTER: *params = ENUM_TO_FLOAT(obj->MagFilter); - return; + break; case GL_TEXTURE_MIN_FILTER: *params = ENUM_TO_FLOAT(obj->MinFilter); - return; + break; case GL_TEXTURE_WRAP_S: *params = ENUM_TO_FLOAT(obj->WrapS); - return; + break; case GL_TEXTURE_WRAP_T: *params = ENUM_TO_FLOAT(obj->WrapT); - return; + break; case GL_TEXTURE_WRAP_R: *params = ENUM_TO_FLOAT(obj->WrapR); - return; + break; case GL_TEXTURE_BORDER_COLOR: params[0] = CLAMP(obj->BorderColor[0], 0.0F, 1.0F); params[1] = CLAMP(obj->BorderColor[1], 0.0F, 1.0F); params[2] = CLAMP(obj->BorderColor[2], 0.0F, 1.0F); params[3] = CLAMP(obj->BorderColor[3], 0.0F, 1.0F); - return; + break; case GL_TEXTURE_RESIDENT: { GLboolean resident; @@ -1986,82 +1999,94 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) resident = GL_TRUE; *params = ENUM_TO_FLOAT(resident); } - return; + break; case GL_TEXTURE_PRIORITY: *params = obj->Priority; - return; + break; case GL_TEXTURE_MIN_LOD: *params = obj->MinLod; - return; + break; case GL_TEXTURE_MAX_LOD: *params = obj->MaxLod; - return; + break; case GL_TEXTURE_BASE_LEVEL: *params = (GLfloat) obj->BaseLevel; - return; + break; case GL_TEXTURE_MAX_LEVEL: *params = (GLfloat) obj->MaxLevel; - return; + break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: if (ctx->Extensions.EXT_texture_filter_anisotropic) { *params = obj->MaxAnisotropy; - return; } + else + error = 1; break; case GL_TEXTURE_COMPARE_SGIX: if (ctx->Extensions.SGIX_shadow) { *params = (GLfloat) obj->CompareFlag; - return; } + else + error = 1; break; case GL_TEXTURE_COMPARE_OPERATOR_SGIX: if (ctx->Extensions.SGIX_shadow) { *params = (GLfloat) obj->CompareOperator; - return; } + else + error = 1; break; case GL_SHADOW_AMBIENT_SGIX: /* aka GL_TEXTURE_COMPARE_FAIL_VALUE_ARB */ if (ctx->Extensions.SGIX_shadow_ambient) { *params = obj->ShadowAmbient; - return; } + else + error = 1; break; case GL_GENERATE_MIPMAP_SGIS: if (ctx->Extensions.SGIS_generate_mipmap) { *params = (GLfloat) obj->GenerateMipmap; - return; } + else + error = 1; break; case GL_TEXTURE_COMPARE_MODE_ARB: if (ctx->Extensions.ARB_shadow) { *params = (GLfloat) obj->CompareMode; - return; } + else + error = 1; break; case GL_TEXTURE_COMPARE_FUNC_ARB: if (ctx->Extensions.ARB_shadow) { *params = (GLfloat) obj->CompareFunc; - return; } + else + error = 1; break; case GL_DEPTH_TEXTURE_MODE_ARB: if (ctx->Extensions.ARB_depth_texture) { *params = (GLfloat) obj->DepthMode; - return; } + else + error = 1; break; case GL_TEXTURE_LOD_BIAS: if (ctx->Extensions.EXT_texture_lod_bias) { *params = obj->LodBias; - return; } + else + error = 1; break; default: - ; /* silence warnings */ + error = 1; + break; } - /* If we get here, pname was an unrecognized enum */ - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)", - pname); + if (error) + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)", + pname); + + _mesa_unlock_texture(ctx, obj); } diff --git a/src/mesa/swrast/s_texstore.c b/src/mesa/swrast/s_texstore.c index ddaf747..3f49b40 100644 --- a/src/mesa/swrast/s_texstore.c +++ b/src/mesa/swrast/s_texstore.c @@ -254,7 +254,7 @@ _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage1D); @@ -331,7 +331,7 @@ _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage2D); @@ -400,7 +400,7 @@ _swrast_copy_texsubimage1d( GLcontext *ctx, GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage1D); @@ -474,7 +474,7 @@ _swrast_copy_texsubimage2d( GLcontext *ctx, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage2D); @@ -547,7 +547,7 @@ _swrast_copy_texsubimage3d( GLcontext *ctx, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage3D);