diff options
Diffstat (limited to 'mesalib/src/mesa/main')
22 files changed, 1876 insertions, 1165 deletions
diff --git a/mesalib/src/mesa/main/api_exec.h b/mesalib/src/mesa/main/api_exec.h index 1e4a9d61a..12249fec2 100644 --- a/mesalib/src/mesa/main/api_exec.h +++ b/mesalib/src/mesa/main/api_exec.h @@ -30,12 +30,8 @@ extern "C" { #endif -struct _glapi_table; struct gl_context; -extern struct _glapi_table * -_mesa_alloc_dispatch_table(void); - extern void _mesa_initialize_exec_table(struct gl_context *ctx); diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 008d1aa5f..25110c33b 100755 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -232,67 +232,62 @@ bufferobj_range_mapped(const struct gl_buffer_object *obj, * \c glClearBufferSubData. * * \param ctx GL context. - * \param target Buffer object target on which to operate. + * \param bufObj The buffer object. * \param offset Offset of the first byte of the subdata range. * \param size Size, in bytes, of the subdata range. * \param mappedRange If true, checks if an overlapping range is mapped. * If false, checks if buffer is mapped. - * \param errorNoBuffer Error code if no buffer is bound to target. * \param caller Name of calling function for recording errors. - * \return A pointer to the buffer object bound to \c target in the - * specified context or \c NULL if any of the parameter or state - * conditions are invalid. + * \return false if error, true otherwise * * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData */ -static struct gl_buffer_object * -buffer_object_subdata_range_good(struct gl_context * ctx, GLenum target, - GLintptrARB offset, GLsizeiptrARB size, - bool mappedRange, GLenum errorNoBuffer, - const char *caller) +static bool +buffer_object_subdata_range_good(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr size, + bool mappedRange, const char *caller) { - struct gl_buffer_object *bufObj; - if (size < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); - return NULL; + return false; } if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); - return NULL; + return false; } - bufObj = get_buffer(ctx, caller, target, errorNoBuffer); - if (!bufObj) - return NULL; - if (offset + size > bufObj->Size) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset %lu + size %lu > buffer size %lu)", caller, (unsigned long) offset, (unsigned long) size, (unsigned long) bufObj->Size); - return NULL; + return false; } if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) - return bufObj; + return true; if (mappedRange) { if (bufferobj_range_mapped(bufObj, offset, size)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(range is mapped without persistent bit)", + caller); + return false; } } else { if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffer is mapped without persistent bit)", + caller); + return false; } } - return bufObj; + return true; } @@ -561,9 +556,9 @@ _mesa_total_buffer_object_memory(struct gl_context *ctx) * \sa glBufferDataARB, dd_function_table::BufferData. */ GLboolean -_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage, GLenum storageFlags, - struct gl_buffer_object * bufObj ) +buffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptr size, + const GLvoid *data, GLenum usage, GLenum storageFlags, + struct gl_buffer_object *bufObj) { void * new_data; @@ -607,9 +602,9 @@ _mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, * \sa glBufferSubDataARB, dd_function_table::BufferSubData. */ void -_mesa_buffer_subdata( struct gl_context *ctx, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data, - struct gl_buffer_object * bufObj ) +buffer_sub_data_fallback(struct gl_context *ctx, GLintptr offset, + GLsizeiptr size, const GLvoid *data, + struct gl_buffer_object *bufObj) { (void) ctx; @@ -670,11 +665,11 @@ _mesa_buffer_get_subdata( struct gl_context *ctx, GLintptrARB offset, * dd_function_table::ClearBufferSubData. */ void -_mesa_buffer_clear_subdata(struct gl_context *ctx, - GLintptr offset, GLsizeiptr size, - const GLvoid *clearValue, - GLsizeiptr clearValueSize, - struct gl_buffer_object *bufObj) +_mesa_ClearBufferSubData_sw(struct gl_context *ctx, + GLintptr offset, GLsizeiptr size, + const GLvoid *clearValue, + GLsizeiptr clearValueSize, + struct gl_buffer_object *bufObj) { GLsizeiptr i; GLubyte *dest; @@ -711,10 +706,10 @@ _mesa_buffer_clear_subdata(struct gl_context *ctx, * Called via glMapBufferRange(). */ static void * -_mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset, - GLsizeiptr length, GLbitfield access, - struct gl_buffer_object *bufObj, - gl_map_buffer_index index) +map_buffer_range_fallback(struct gl_context *ctx, GLintptr offset, + GLsizeiptr length, GLbitfield access, + struct gl_buffer_object *bufObj, + gl_map_buffer_index index) { (void) ctx; assert(!_mesa_bufferobj_mapped(bufObj, index)); @@ -732,10 +727,10 @@ _mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset, * Called via glFlushMappedBufferRange(). */ static void -_mesa_buffer_flush_mapped_range( struct gl_context *ctx, - GLintptr offset, GLsizeiptr length, - struct gl_buffer_object *obj, - gl_map_buffer_index index) +flush_mapped_buffer_range_fallback(struct gl_context *ctx, + GLintptr offset, GLsizeiptr length, + struct gl_buffer_object *obj, + gl_map_buffer_index index) { (void) ctx; (void) offset; @@ -746,15 +741,15 @@ _mesa_buffer_flush_mapped_range( struct gl_context *ctx, /** - * Default callback for \c dd_function_table::MapBuffer(). + * Default callback for \c dd_function_table::UnmapBuffer(). * * The input parameters will have been already tested for errors. * * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer */ GLboolean -_mesa_buffer_unmap(struct gl_context *ctx, struct gl_buffer_object *bufObj, - gl_map_buffer_index index) +unmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj, + gl_map_buffer_index index) { (void) ctx; /* XXX we might assert here that bufObj->Pointer is non-null */ @@ -771,11 +766,11 @@ _mesa_buffer_unmap(struct gl_context *ctx, struct gl_buffer_object *bufObj, * Called via glCopyBufferSubData(). */ static void -_mesa_copy_buffer_subdata(struct gl_context *ctx, - struct gl_buffer_object *src, - struct gl_buffer_object *dst, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) +copy_buffer_sub_data_fallback(struct gl_context *ctx, + struct gl_buffer_object *src, + struct gl_buffer_object *dst, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) { GLubyte *srcPtr, *dstPtr; @@ -1006,6 +1001,27 @@ _mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer) _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer); } +/** + * A convenience function for direct state access functions that throws + * GL_INVALID_OPERATION if buffer is not the name of an existing + * buffer object. + */ +struct gl_buffer_object * +_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer, + const char *caller) +{ + struct gl_buffer_object *bufObj; + + bufObj = _mesa_lookup_bufferobj(ctx, buffer); + if (!bufObj || bufObj == &DummyBufferObject) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(non-existent buffer object %u)", caller, buffer); + return NULL; + } + + return bufObj; +} + void _mesa_begin_bufferobj_lookups(struct gl_context *ctx) @@ -1098,20 +1114,20 @@ _mesa_init_buffer_object_functions(struct dd_function_table *driver) /* GL_ARB_vertex/pixel_buffer_object */ driver->NewBufferObject = _mesa_new_buffer_object; driver->DeleteBuffer = _mesa_delete_buffer_object; - driver->BufferData = _mesa_buffer_data; - driver->BufferSubData = _mesa_buffer_subdata; + driver->BufferData = buffer_data_fallback; + driver->BufferSubData = buffer_sub_data_fallback; driver->GetBufferSubData = _mesa_buffer_get_subdata; - driver->UnmapBuffer = _mesa_buffer_unmap; + driver->UnmapBuffer = unmap_buffer_fallback; /* GL_ARB_clear_buffer_object */ - driver->ClearBufferSubData = _mesa_buffer_clear_subdata; + driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw; /* GL_ARB_map_buffer_range */ - driver->MapBufferRange = _mesa_buffer_map_range; - driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; + driver->MapBufferRange = map_buffer_range_fallback; + driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback; /* GL_ARB_copy_buffer */ - driver->CopyBufferSubData = _mesa_copy_buffer_subdata; + driver->CopyBufferSubData = copy_buffer_sub_data_fallback; } @@ -1273,27 +1289,29 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids) /** - * Generate a set of unique buffer object IDs and store them in \c buffer. - * - * \param n Number of IDs to generate. - * \param buffer Array of \c n locations to store the IDs. + * This is the implementation for glGenBuffers and glCreateBuffers. It is not + * exposed to the rest of Mesa to encourage the use of nameless buffers in + * driver internals. */ -void GLAPIENTRY -_mesa_GenBuffers(GLsizei n, GLuint *buffer) +static void +create_buffers(GLsizei n, GLuint *buffers, bool dsa) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; + struct gl_buffer_object *buf; + + const char *func = dsa ? "glCreateBuffers" : "glGenBuffers"; if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glGenBuffers(%d)\n", n); + _mesa_debug(ctx, "%s(%d)\n", func, n); if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n); return; } - if (!buffer) { + if (!buffers) { return; } @@ -1304,16 +1322,53 @@ _mesa_GenBuffers(GLsizei n, GLuint *buffer) first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); - /* Insert the ID and pointer to dummy buffer object into hash table */ + /* Insert the ID and pointer into the hash table. If non-DSA, insert a + * DummyBufferObject. Otherwise, create a new buffer object and insert + * it. + */ for (i = 0; i < n; i++) { - _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, - &DummyBufferObject); - buffer[i] = first + i; + buffers[i] = first + i; + if (dsa) { + assert(ctx->Driver.NewBufferObject); + buf = ctx->Driver.NewBufferObject(ctx, buffers[i]); + if (!buf) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); + return; + } + } + else + buf = &DummyBufferObject; + + _mesa_HashInsert(ctx->Shared->BufferObjects, buffers[i], buf); } mtx_unlock(&ctx->Shared->Mutex); } +/** + * Generate a set of unique buffer object IDs and store them in \c buffers. + * + * \param n Number of IDs to generate. + * \param buffers Array of \c n locations to store the IDs. + */ +void GLAPIENTRY +_mesa_GenBuffers(GLsizei n, GLuint *buffers) +{ + create_buffers(n, buffers, false); +} + +/** + * Create a set of buffer objects and store their unique IDs in \c buffers. + * + * \param n Number of IDs to generate. + * \param buffers Array of \c n locations to store the IDs. + */ +void GLAPIENTRY +_mesa_CreateBuffers(GLsizei n, GLuint *buffers) +{ + create_buffers(n, buffers, true); +} + /** * Determine if ID is the name of a buffer object. @@ -1337,15 +1392,13 @@ _mesa_IsBuffer(GLuint id) } -void GLAPIENTRY -_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, - GLbitfield flags) +void +_mesa_buffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLenum target, GLsizeiptr size, const GLvoid *data, + GLbitfield flags, const char *func) { - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - if (size <= 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(size <= 0)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func); return; } @@ -1355,27 +1408,25 @@ _mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GL_MAP_COHERENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func); return; } if (flags & GL_MAP_PERSISTENT_BIT && !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags!=READ/WRITE)"); + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(PERSISTENT and flags!=READ/WRITE)", func); return; } if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags!=PERSISTENT)"); + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(COHERENT and flags!=PERSISTENT)", func); return; } - bufObj = get_buffer(ctx, "glBufferStorage", target, GL_INVALID_OPERATION); - if (!bufObj) - return; - if (bufObj->Immutable) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferStorage(immutable)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); return; } @@ -1395,31 +1446,65 @@ _mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, * glBufferStorage is not described in the spec, Graham Sellers * said that it should behave the same as glBufferData. */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferStorage()"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); } else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferStorage()"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); } } } +void GLAPIENTRY +_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, + GLbitfield flags) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + bufObj = get_buffer(ctx, "glBufferStorage", target, GL_INVALID_OPERATION); + if (!bufObj) + return; + + _mesa_buffer_storage(ctx, bufObj, target, size, data, flags, + "glBufferStorage"); +} void GLAPIENTRY -_mesa_BufferData(GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage) +_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data, + GLbitfield flags) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferStorage"); + if (!bufObj) + return; + + /* + * In direct state access, buffer objects have an unspecified target since + * they are not required to be bound. + */ + _mesa_buffer_storage(ctx, bufObj, GL_NONE, size, data, flags, + "glNamedBufferStorage"); +} + + +void +_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLenum target, GLsizeiptr size, const GLvoid *data, + GLenum usage, const char *func) +{ bool valid_usage; if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", + _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n", + func, _mesa_lookup_enum_by_nr(target), (long int) size, data, _mesa_lookup_enum_by_nr(usage)); if (size < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func); return; } @@ -1448,16 +1533,13 @@ _mesa_BufferData(GLenum target, GLsizeiptrARB size, } if (!valid_usage) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBufferData(usage)"); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func, + _mesa_lookup_enum_by_nr(usage)); return; } - bufObj = get_buffer(ctx, "glBufferDataARB", target, GL_INVALID_OPERATION); - if (!bufObj) - return; - if (bufObj->Immutable) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferData(immutable)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); return; } @@ -1490,33 +1572,73 @@ _mesa_BufferData(GLenum target, GLsizeiptrARB size, * EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be * mapped to the GPU address space. */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferData()"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); } else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferData()"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); } } } +void GLAPIENTRY +_mesa_BufferData(GLenum target, GLsizeiptr size, + const GLvoid *data, GLenum usage) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION); + if (!bufObj) + return; + + _mesa_buffer_data(ctx, bufObj, target, size, data, usage, + "glBufferData"); +} void GLAPIENTRY -_mesa_BufferSubData(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data) +_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data, + GLenum usage) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; - bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, - false, GL_INVALID_OPERATION, - "glBufferSubDataARB" ); - if (!bufObj) { + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData"); + if (!bufObj) + return; + + /* In direct state access, buffer objects have an unspecified target since + * they are not required to be bound. + */ + _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage, + "glNamedBufferData"); +} + + +/** + * Implementation for glBufferSubData and glNamedBufferSubData. + * + * \param ctx GL context. + * \param bufObj The buffer object. + * \param offset Offset of the first byte of the subdata range. + * \param size Size, in bytes, of the subdata range. + * \param data The data store. + * \param func Name of calling function for recording errors. + * + */ +void +_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr size, const GLvoid *data, + const char *func) +{ + if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, + false, func)) { /* error already recorded */ return; } if (bufObj->Immutable && !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubData"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); return; } @@ -1526,105 +1648,107 @@ _mesa_BufferSubData(GLenum target, GLintptrARB offset, bufObj->Written = GL_TRUE; assert(ctx->Driver.BufferSubData); - ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj ); + ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj); } +void GLAPIENTRY +_mesa_BufferSubData(GLenum target, GLintptr offset, + GLsizeiptr size, const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + bufObj = get_buffer(ctx, "glBufferSubData", target, GL_INVALID_OPERATION); + if (!bufObj) + return; + + _mesa_buffer_sub_data(ctx, bufObj, offset, size, data, "glBufferSubData"); +} void GLAPIENTRY -_mesa_GetBufferSubData(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, void * data) +_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset, + GLsizeiptr size, const GLvoid *data) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; - bufObj = buffer_object_subdata_range_good(ctx, target, offset, size, - false, GL_INVALID_OPERATION, - "glGetBufferSubDataARB"); - if (!bufObj) { - /* error already recorded */ + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferSubData"); + if (!bufObj) return; - } - assert(ctx->Driver.GetBufferSubData); - ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj ); + _mesa_buffer_sub_data(ctx, bufObj, offset, size, data, + "glNamedBufferSubData"); } void GLAPIENTRY -_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, - GLenum type, const GLvoid* data) +_mesa_GetBufferSubData(GLenum target, GLintptr offset, + GLsizeiptr size, GLvoid *data) { GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object* bufObj; - mesa_format mesaFormat; - GLubyte clearValue[MAX_PIXEL_BYTES]; - GLsizeiptr clearValueSize; + struct gl_buffer_object *bufObj; - bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE); - if (!bufObj) { + bufObj = get_buffer(ctx, "glGetBufferSubData", target, + GL_INVALID_OPERATION); + if (!bufObj) return; - } - if (_mesa_check_disallowed_mapping(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glClearBufferData(buffer currently mapped)"); + if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, + "glGetBufferSubData")) { return; } - mesaFormat = validate_clear_buffer_format(ctx, internalformat, - format, type, - "glClearBufferData"); - if (mesaFormat == MESA_FORMAT_NONE) { - return; - } + assert(ctx->Driver.GetBufferSubData); + ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); +} - clearValueSize = _mesa_get_format_bytes(mesaFormat); - if (bufObj->Size % clearValueSize != 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glClearBufferData(size is not a multiple of " - "internalformat size)"); - return; - } +void GLAPIENTRY +_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset, + GLsizeiptr size, GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; - if (data == NULL) { - /* clear to zeros, per the spec */ - ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size, - NULL, clearValueSize, bufObj); + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glGetNamedBufferSubData"); + if (!bufObj) return; - } - if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, - format, type, data, "glClearBufferData")) { + if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, + "glGetNamedBufferSubData")) { return; } - ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size, - clearValue, clearValueSize, bufObj); + assert(ctx->Driver.GetBufferSubData); + ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); } -void GLAPIENTRY -_mesa_ClearBufferSubData(GLenum target, GLenum internalformat, - GLintptr offset, GLsizeiptr size, - GLenum format, GLenum type, - const GLvoid* data) +/** + * \param subdata true if caller is *SubData, false if *Data + */ +void +_mesa_clear_buffer_sub_data(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const GLvoid *data, + const char *func, bool subdata) { - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object* bufObj; mesa_format mesaFormat; GLubyte clearValue[MAX_PIXEL_BYTES]; GLsizeiptr clearValueSize; - bufObj = buffer_object_subdata_range_good(ctx, target, offset, size, - true, GL_INVALID_VALUE, - "glClearBufferSubData"); - if (!bufObj) { + /* This checks for disallowed mappings. */ + if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, + subdata, func)) { return; } mesaFormat = validate_clear_buffer_format(ctx, internalformat, - format, type, - "glClearBufferSubData"); + format, type, func); + if (mesaFormat == MESA_FORMAT_NONE) { return; } @@ -1632,8 +1756,8 @@ _mesa_ClearBufferSubData(GLenum target, GLenum internalformat, clearValueSize = _mesa_get_format_bytes(mesaFormat); if (offset % clearValueSize != 0 || size % clearValueSize != 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glClearBufferSubData(offset or size is not a multiple of " - "internalformat size)"); + "%s(offset or size is not a multiple of " + "internalformat size)", func); return; } @@ -1647,8 +1771,7 @@ _mesa_ClearBufferSubData(GLenum target, GLenum internalformat, } if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, - format, type, data, - "glClearBufferSubData")) { + format, type, data, func)) { return; } @@ -1658,131 +1781,87 @@ _mesa_ClearBufferSubData(GLenum target, GLenum internalformat, } } - -void * GLAPIENTRY -_mesa_MapBuffer(GLenum target, GLenum access) +void GLAPIENTRY +_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, + GLenum type, const GLvoid *data) { GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; - GLbitfield accessFlags; - void *map; - bool valid_access; + struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); + bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE); + if (!bufObj) + return; - switch (access) { - case GL_READ_ONLY_ARB: - accessFlags = GL_MAP_READ_BIT; - valid_access = _mesa_is_desktop_gl(ctx); - break; - case GL_WRITE_ONLY_ARB: - accessFlags = GL_MAP_WRITE_BIT; - valid_access = true; - break; - case GL_READ_WRITE_ARB: - accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; - valid_access = _mesa_is_desktop_gl(ctx); - break; - default: - valid_access = false; - break; - } + _mesa_clear_buffer_sub_data(ctx, bufObj, internalformat, 0, bufObj->Size, + format, type, data, + "glClearBufferData", false); +} - if (!valid_access) { - _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); - return NULL; - } +void GLAPIENTRY +_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat, + GLenum format, GLenum type, const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; - bufObj = get_buffer(ctx, "glMapBufferARB", target, GL_INVALID_OPERATION); + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData"); if (!bufObj) - return NULL; + return; - if (accessFlags & GL_MAP_READ_BIT && - !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBuffer(invalid read flag)"); - return NULL; - } + _mesa_clear_buffer_sub_data(ctx, bufObj, internalformat, 0, bufObj->Size, + format, type, data, + "glClearNamedBufferData", false); +} - if (accessFlags & GL_MAP_WRITE_BIT && - !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBuffer(invalid write flag)"); - return NULL; - } - if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); - return NULL; - } - - if (!bufObj->Size) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glMapBuffer(buffer size = 0)"); - return NULL; - } +void GLAPIENTRY +_mesa_ClearBufferSubData(GLenum target, GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; - assert(ctx->Driver.MapBufferRange); - map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj, - MAP_USER); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); - return NULL; - } - else { - /* The driver callback should have set these fields. - * This is important because other modules (like VBO) might call - * the driver function directly. - */ - assert(bufObj->Mappings[MAP_USER].Pointer == map); - assert(bufObj->Mappings[MAP_USER].Length == bufObj->Size); - assert(bufObj->Mappings[MAP_USER].Offset == 0); - bufObj->Mappings[MAP_USER].AccessFlags = accessFlags; - } + bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE); + if (!bufObj) + return; - if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) - bufObj->Written = GL_TRUE; + _mesa_clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, + format, type, data, + "glClearBufferSubData", true); +} -#ifdef VBO_DEBUG - printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", - bufObj->Name, bufObj->Size, access); - if (access == GL_WRITE_ONLY_ARB) { - GLuint i; - GLubyte *b = (GLubyte *) bufObj->Pointer; - for (i = 0; i < bufObj->Size; i++) - b[i] = i & 0xff; - } -#endif +void GLAPIENTRY +_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; -#ifdef BOUNDS_CHECK - { - GLubyte *buf = (GLubyte *) bufObj->Pointer; - GLuint i; - /* buffer is 100 bytes larger than requested, fill with magic value */ - for (i = 0; i < 100; i++) { - buf[bufObj->Size - i - 1] = 123; - } - } -#endif + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glClearNamedBufferSubData"); + if (!bufObj) + return; - return bufObj->Mappings[MAP_USER].Pointer; + _mesa_clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, + format, type, data, + "glClearNamedBufferSubData", true); } -GLboolean GLAPIENTRY -_mesa_UnmapBuffer(GLenum target) +GLboolean +_mesa_unmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj, + const char *func) { - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; GLboolean status = GL_TRUE; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - bufObj = get_buffer(ctx, "glUnmapBufferARB", target, GL_INVALID_OPERATION); - if (!bufObj) - return GL_FALSE; - if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffer is not mapped)", func); return GL_FALSE; } @@ -1831,129 +1910,164 @@ _mesa_UnmapBuffer(GLenum target) return status; } +GLboolean GLAPIENTRY +_mesa_UnmapBuffer(GLenum target) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; -void GLAPIENTRY -_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params) + bufObj = get_buffer(ctx, "glUnmapBuffer", target, GL_INVALID_OPERATION); + if (!bufObj) + return GL_FALSE; + + return _mesa_unmap_buffer(ctx, bufObj, "glUnmapBuffer"); +} + +GLboolean GLAPIENTRY +_mesa_UnmapNamedBuffer(GLuint buffer) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; - bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target, - GL_INVALID_OPERATION); + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer"); if (!bufObj) - return; + return GL_FALSE; + return _mesa_unmap_buffer(ctx, bufObj, "glUnmapNamedBuffer"); +} + + +static bool +get_buffer_parameter(struct gl_context *ctx, + struct gl_buffer_object *bufObj, GLenum pname, + GLint64 *params, const char *func) +{ switch (pname) { case GL_BUFFER_SIZE_ARB: - *params = (GLint) bufObj->Size; - return; + *params = bufObj->Size; + break; case GL_BUFFER_USAGE_ARB: *params = bufObj->Usage; - return; + break; case GL_BUFFER_ACCESS_ARB: *params = simplified_access_mode(ctx, bufObj->Mappings[MAP_USER].AccessFlags); - return; + break; case GL_BUFFER_MAPPED_ARB: *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); - return; + break; case GL_BUFFER_ACCESS_FLAGS: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; *params = bufObj->Mappings[MAP_USER].AccessFlags; - return; + break; case GL_BUFFER_MAP_OFFSET: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; - *params = (GLint) bufObj->Mappings[MAP_USER].Offset; - return; + *params = bufObj->Mappings[MAP_USER].Offset; + break; case GL_BUFFER_MAP_LENGTH: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; - *params = (GLint) bufObj->Mappings[MAP_USER].Length; - return; + *params = bufObj->Mappings[MAP_USER].Length; + break; case GL_BUFFER_IMMUTABLE_STORAGE: if (!ctx->Extensions.ARB_buffer_storage) goto invalid_pname; *params = bufObj->Immutable; - return; + break; case GL_BUFFER_STORAGE_FLAGS: if (!ctx->Extensions.ARB_buffer_storage) goto invalid_pname; *params = bufObj->StorageFlags; - return; + break; default: - ; /* fall-through */ + goto invalid_pname; } + return true; + invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func, _mesa_lookup_enum_by_nr(pname)); + return false; } +void GLAPIENTRY +_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + GLint64 parameter; + + bufObj = get_buffer(ctx, "glGetBufferParameteriv", target, + GL_INVALID_OPERATION); + if (!bufObj) + return; + + if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, + "glGetBufferParameteriv")) + return; /* Error already recorded. */ + + *params = (GLint) parameter; +} -/** - * New in GL 3.2 - * This is pretty much a duplicate of GetBufferParameteriv() but the - * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. - */ void GLAPIENTRY _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + GLint64 parameter; bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target, GL_INVALID_OPERATION); if (!bufObj) return; - switch (pname) { - case GL_BUFFER_SIZE_ARB: - *params = bufObj->Size; - return; - case GL_BUFFER_USAGE_ARB: - *params = bufObj->Usage; - return; - case GL_BUFFER_ACCESS_ARB: - *params = simplified_access_mode(ctx, - bufObj->Mappings[MAP_USER].AccessFlags); - return; - case GL_BUFFER_ACCESS_FLAGS: - if (!ctx->Extensions.ARB_map_buffer_range) - goto invalid_pname; - *params = bufObj->Mappings[MAP_USER].AccessFlags; - return; - case GL_BUFFER_MAPPED_ARB: - *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); - return; - case GL_BUFFER_MAP_OFFSET: - if (!ctx->Extensions.ARB_map_buffer_range) - goto invalid_pname; - *params = bufObj->Mappings[MAP_USER].Offset; - return; - case GL_BUFFER_MAP_LENGTH: - if (!ctx->Extensions.ARB_map_buffer_range) - goto invalid_pname; - *params = bufObj->Mappings[MAP_USER].Length; - return; - case GL_BUFFER_IMMUTABLE_STORAGE: - if (!ctx->Extensions.ARB_buffer_storage) - goto invalid_pname; - *params = bufObj->Immutable; + if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, + "glGetBufferParameteri64v")) + return; /* Error already recorded. */ + + *params = parameter; +} + +void GLAPIENTRY +_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + GLint64 parameter; + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glGetNamedBufferParameteriv"); + if (!bufObj) return; - case GL_BUFFER_STORAGE_FLAGS: - if (!ctx->Extensions.ARB_buffer_storage) - goto invalid_pname; - *params = bufObj->StorageFlags; + + if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, + "glGetNamedBufferParameteriv")) + return; /* Error already recorded. */ + + *params = (GLint) parameter; +} + +void GLAPIENTRY +_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, + GLint64 *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + GLint64 parameter; + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glGetNamedBufferParameteri64v"); + if (!bufObj) return; - default: - ; /* fall-through */ - } -invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); + if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, + "glGetNamedBufferParameteri64v")) + return; /* Error already recorded. */ + + *params = parameter; } @@ -1961,14 +2075,15 @@ void GLAPIENTRY _mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) { GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; + struct gl_buffer_object *bufObj; - if (pname != GL_BUFFER_MAP_POINTER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); + if (pname != GL_BUFFER_MAP_POINTER) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointerv(pname != " + "GL_BUFFER_MAP_POINTER)"); return; } - bufObj = get_buffer(ctx, "glGetBufferPointervARB", target, + bufObj = get_buffer(ctx, "glGetBufferPointerv", target, GL_INVALID_OPERATION); if (!bufObj) return; @@ -1976,66 +2091,75 @@ _mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) *params = bufObj->Mappings[MAP_USER].Pointer; } - void GLAPIENTRY -_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) +_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params) { GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *src, *dst; + struct gl_buffer_object *bufObj; - src = get_buffer(ctx, "glCopyBufferSubData", readTarget, - GL_INVALID_OPERATION); - if (!src) + if (pname != GL_BUFFER_MAP_POINTER) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != " + "GL_BUFFER_MAP_POINTER)"); return; + } - dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget, - GL_INVALID_OPERATION); - if (!dst) + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glGetNamedBufferPointerv"); + if (!bufObj) return; + *params = bufObj->Mappings[MAP_USER].Pointer; +} + + +void +_mesa_copy_buffer_sub_data(struct gl_context *ctx, + struct gl_buffer_object *src, + struct gl_buffer_object *dst, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size, const char *func) +{ if (_mesa_check_disallowed_mapping(src)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBufferSubData(readBuffer is mapped)"); + "%s(readBuffer is mapped)", func); return; } if (_mesa_check_disallowed_mapping(dst)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBufferSubData(writeBuffer is mapped)"); + "%s(writeBuffer is mapped)", func); return; } if (readOffset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(readOffset = %d)", (int) readOffset); + "%s(readOffset %d < 0)", func, (int) readOffset); return; } if (writeOffset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset); + "%s(writeOffset %d < 0)", func, (int) writeOffset); return; } if (size < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(writeOffset = %d)", (int) size); + "%s(size %d < 0)", func, (int) size); return; } if (readOffset + size > src->Size) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(readOffset + size = %d)", - (int) (readOffset + size)); + "%s(readOffset %d + size %d > src_buffer_size %d)", func, + (int) readOffset, (int) size, (int) src->Size); return; } if (writeOffset + size > dst->Size) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(writeOffset + size = %d)", - (int) (writeOffset + size)); + "%s(writeOffset %d + size %d > dst_buffer_size %d)", func, + (int) writeOffset, (int) size, (int) dst->Size); return; } @@ -2049,7 +2173,7 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, else { /* overlapping src/dst is illegal */ _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBufferSubData(overlapping src/dst)"); + "%s(overlapping src/dst)", func); return; } } @@ -2057,36 +2181,71 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); } +void GLAPIENTRY +_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *src, *dst; + + src = get_buffer(ctx, "glCopyBufferSubData", readTarget, + GL_INVALID_OPERATION); + if (!src) + return; -/** - * See GL_ARB_map_buffer_range spec - */ -void * GLAPIENTRY -_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, - GLbitfield access) + dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget, + GL_INVALID_OPERATION); + if (!dst) + return; + + _mesa_copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, + "glCopyBufferSubData"); +} + +void GLAPIENTRY +_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) { GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; + struct gl_buffer_object *src, *dst; + + src = _mesa_lookup_bufferobj_err(ctx, readBuffer, + "glCopyNamedBufferSubData"); + if (!src) + return; + + dst = _mesa_lookup_bufferobj_err(ctx, writeBuffer, + "glCopyNamedBufferSubData"); + if (!dst) + return; + + _mesa_copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, + "glCopyNamedBufferSubData"); +} + + +void * +_mesa_map_buffer_range(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr length, + GLbitfield access, const char *func) +{ void *map; GLbitfield allowed_access; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); - if (!ctx->Extensions.ARB_map_buffer_range) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(extension not supported)"); - return NULL; - } - if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", (long)offset); + "%s(offset %ld < 0)", func, (long) offset); return NULL; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", (long)length); + "%s(length %ld < 0)", func, (long) length); return NULL; } @@ -2096,10 +2255,13 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, * conditions: * * * <length> is zero." + * + * Additionally, page 94 of the PDF of the OpenGL 4.5 core spec + * (30.10.2014) also says this, so it's no longer allowed for desktop GL, + * either. */ - if (_mesa_is_gles(ctx) && length == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(length = 0)"); + if (length == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(length = 0)", func); return NULL; } @@ -2116,14 +2278,15 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, } if (access & ~allowed_access) { - /* generate an error if any other than allowed bit is set */ - _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)"); + /* generate an error if any bits other than those allowed are set */ + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(access has undefined bits set)", func); return NULL; } if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(access indicates neither read or write)"); + "%s(access indicates neither read or write)", func); return NULL; } @@ -2132,82 +2295,69 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT))) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); + "%s(read access with disallowed bits)", func); return NULL; } if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && ((access & GL_MAP_WRITE_BIT) == 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); + "%s(access has flush explicit without write)", func); return NULL; } - bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION); - if (!bufObj) - return NULL; - if (access & GL_MAP_READ_BIT && !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid read flag)"); + "%s(buffer does not allow read access)", func); return NULL; } if (access & GL_MAP_WRITE_BIT && !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid write flag)"); + "%s(buffer does not allow write access)", func); return NULL; } if (access & GL_MAP_COHERENT_BIT && !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid coherent flag)"); + "%s(buffer does not allow coherent access)", func); return NULL; } if (access & GL_MAP_PERSISTENT_BIT && !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid persistent flag)"); + "%s(buffer does not allow persistent access)", func); return NULL; } if (offset + length > bufObj->Size) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset + length > size)"); + "%s(offset %ld + length %ld > buffer_size %ld)", func, + offset, length, bufObj->Size); return NULL; } if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(buffer already mapped)"); + "%s(buffer already mapped)", func); return NULL; } if (!bufObj->Size) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glMapBufferRange(buffer size = 0)"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(buffer size = 0)", func); return NULL; } - /* Mapping zero bytes should return a non-null pointer. */ - if (!length) { - static long dummy = 0; - bufObj->Mappings[MAP_USER].Pointer = &dummy; - bufObj->Mappings[MAP_USER].Length = length; - bufObj->Mappings[MAP_USER].Offset = offset; - bufObj->Mappings[MAP_USER].AccessFlags = access; - return bufObj->Mappings[MAP_USER].Pointer; - } assert(ctx->Driver.MapBufferRange); map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj, MAP_USER); if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(map failed)", func); } else { /* The driver callback should have set all these fields. @@ -2220,61 +2370,189 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, assert(bufObj->Mappings[MAP_USER].AccessFlags == access); } + if (access & GL_MAP_WRITE_BIT) + bufObj->Written = GL_TRUE; + +#ifdef VBO_DEBUG + if (strstr(func, "Range") == NULL) { /* If not MapRange */ + printf("glMapBuffer(%u, sz %ld, access 0x%x)\n", + bufObj->Name, bufObj->Size, access); + /* Access must be write only */ + if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT))) { + GLuint i; + GLubyte *b = (GLubyte *) bufObj->Pointer; + for (i = 0; i < bufObj->Size; i++) + b[i] = i & 0xff; + } + } +#endif + +#ifdef BOUNDS_CHECK + if (strstr(func, "Range") == NULL) { /* If not MapRange */ + GLubyte *buf = (GLubyte *) bufObj->Pointer; + GLuint i; + /* buffer is 100 bytes larger than requested, fill with magic value */ + for (i = 0; i < 100; i++) { + buf[bufObj->Size - i - 1] = 123; + } + } +#endif + return map; } +void * GLAPIENTRY +_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(ARB_map_buffer_range not supported)"); + return NULL; + } + + bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION); + if (!bufObj) + return NULL; + + return _mesa_map_buffer_range(ctx, bufObj, offset, length, access, + "glMapBufferRange"); +} + +void * GLAPIENTRY +_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, + GLbitfield access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapNamedBufferRange(" + "ARB_map_buffer_range not supported)"); + return NULL; + } + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBufferRange"); + if (!bufObj) + return NULL; + + return _mesa_map_buffer_range(ctx, bufObj, offset, length, access, + "glMapNamedBufferRange"); +} /** - * See GL_ARB_map_buffer_range spec + * Converts GLenum access from MapBuffer and MapNamedBuffer into + * flags for input to _mesa_map_buffer_range. + * + * \return true if the type of requested access is permissible. */ -void GLAPIENTRY -_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +static bool +get_map_buffer_access_flags(struct gl_context *ctx, GLenum access, + GLbitfield *flags) +{ + switch (access) { + case GL_READ_ONLY_ARB: + *flags = GL_MAP_READ_BIT; + return _mesa_is_desktop_gl(ctx); + case GL_WRITE_ONLY_ARB: + *flags = GL_MAP_WRITE_BIT; + return true; + case GL_READ_WRITE_ARB: + *flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; + return _mesa_is_desktop_gl(ctx); + default: + return false; + } +} + +void * GLAPIENTRY +_mesa_MapBuffer(GLenum target, GLenum access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + GLbitfield accessFlags; + + if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glMapBuffer(invalid access)"); + return NULL; + } + + bufObj = get_buffer(ctx, "glMapBuffer", target, GL_INVALID_OPERATION); + if (!bufObj) + return NULL; + + return _mesa_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, + "glMapBuffer"); +} + +void * GLAPIENTRY +_mesa_MapNamedBuffer(GLuint buffer, GLenum access) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + GLbitfield accessFlags; + if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)"); + return NULL; + } + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBuffer"); + if (!bufObj) + return NULL; + + return _mesa_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, + "glMapNamedBuffer"); +} + + +void +_mesa_flush_mapped_buffer_range(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr length, + const char *func) +{ if (!ctx->Extensions.ARB_map_buffer_range) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFlushMappedBufferRange(extension not supported)"); + "%s(ARB_map_buffer_range not supported)", func); return; } if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glFlushMappedBufferRange(offset = %ld)", (long)offset); + "%s(offset %ld < 0)", func, (long) offset); return; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glFlushMappedBufferRange(length = %ld)", (long)length); + "%s(length %ld < 0)", func, (long) length); return; } - bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target, - GL_INVALID_OPERATION); - if (!bufObj) - return; - if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { /* buffer is not mapped */ _mesa_error(ctx, GL_INVALID_OPERATION, - "glFlushMappedBufferRange(buffer is not mapped)"); + "%s(buffer is not mapped)", func); return; } if ((bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); + "%s(GL_MAP_FLUSH_EXPLICIT_BIT not set)", func); return; } if (offset + length > bufObj->Mappings[MAP_USER].Length) { _mesa_error(ctx, GL_INVALID_VALUE, - "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)", - (long)offset, (long)length, - (long)bufObj->Mappings[MAP_USER].Length); + "%s(offset %ld + length %ld > mapped length %ld)", func, + (long) offset, (long) length, + (long) bufObj->Mappings[MAP_USER].Length); return; } @@ -2285,6 +2563,38 @@ _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) MAP_USER); } +void GLAPIENTRY +_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, + GLsizeiptr length) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target, + GL_INVALID_OPERATION); + if (!bufObj) + return; + + _mesa_flush_mapped_buffer_range(ctx, bufObj, offset, length, + "glFlushMappedBufferRange"); +} + +void GLAPIENTRY +_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, + GLsizeiptr length) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glFlushMappedNamedBufferRange"); + if (!bufObj) + return; + + _mesa_flush_mapped_buffer_range(ctx, bufObj, offset, length, + "glFlushMappedNamedBufferRange"); +} + static GLenum buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h index fe294fc0b..b5d73aec0 100644 --- a/mesalib/src/mesa/main/bufferobj.h +++ b/mesalib/src/mesa/main/bufferobj.h @@ -89,6 +89,10 @@ _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer); extern struct gl_buffer_object * _mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer); +extern struct gl_buffer_object * +_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer, + const char *caller); + extern void _mesa_begin_bufferobj_lookups(struct gl_context *ctx); @@ -126,15 +130,62 @@ extern void _mesa_init_buffer_object_functions(struct dd_function_table *driver); extern void +_mesa_buffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLenum target, GLsizeiptr size, const GLvoid *data, + GLbitfield flags, const char *func); + +extern void +_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLenum target, GLsizeiptr size, const GLvoid *data, + GLenum usage, const char *func); + +extern void +_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr size, const GLvoid *data, + const char *func); + +extern void _mesa_buffer_unmap_all_mappings(struct gl_context *ctx, struct gl_buffer_object *bufObj); extern void -_mesa_buffer_clear_subdata(struct gl_context *ctx, - GLintptr offset, GLsizeiptr size, - const GLvoid *clearValue, - GLsizeiptr clearValueSize, - struct gl_buffer_object *bufObj); +_mesa_copy_buffer_sub_data(struct gl_context *ctx, + struct gl_buffer_object *src, + struct gl_buffer_object *dst, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size, const char *func); + +extern void * +_mesa_map_buffer_range(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr length, + GLbitfield access, const char *func); + +extern void +_mesa_flush_mapped_buffer_range(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr length, + const char *func); + +extern void +_mesa_ClearBufferSubData_sw(struct gl_context *ctx, + GLintptr offset, GLsizeiptr size, + const GLvoid *clearValue, + GLsizeiptr clearValueSize, + struct gl_buffer_object *bufObj); + +extern void +_mesa_clear_buffer_sub_data(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const GLvoid *data, + const char *func, bool subdata); + +extern GLboolean +_mesa_unmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj, + const char *func); /* * API functions @@ -146,7 +197,10 @@ void GLAPIENTRY _mesa_DeleteBuffers(GLsizei n, const GLuint * buffer); void GLAPIENTRY -_mesa_GenBuffers(GLsizei n, GLuint * buffer); +_mesa_GenBuffers(GLsizei n, GLuint *buffers); + +void GLAPIENTRY +_mesa_CreateBuffers(GLsizei n, GLuint *buffers); GLboolean GLAPIENTRY _mesa_IsBuffer(GLuint buffer); @@ -156,34 +210,61 @@ _mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags); void GLAPIENTRY -_mesa_BufferData(GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage); +_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data, + GLbitfield flags); + +void GLAPIENTRY +_mesa_BufferData(GLenum target, GLsizeiptr size, + const GLvoid *data, GLenum usage); + +void GLAPIENTRY +_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, + const GLvoid *data, GLenum usage); + +void GLAPIENTRY +_mesa_BufferSubData(GLenum target, GLintptr offset, + GLsizeiptr size, const GLvoid *data); void GLAPIENTRY -_mesa_BufferSubData(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data); +_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset, + GLsizeiptr size, const GLvoid *data); void GLAPIENTRY -_mesa_GetBufferSubData(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, void * data); +_mesa_GetBufferSubData(GLenum target, GLintptr offset, + GLsizeiptr size, GLvoid *data); + +void GLAPIENTRY +_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset, + GLsizeiptr size, GLvoid *data); void GLAPIENTRY _mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, GLenum type, - const GLvoid * data); + const GLvoid *data); + +void GLAPIENTRY +_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat, + GLenum format, GLenum type, + const GLvoid *data); void GLAPIENTRY _mesa_ClearBufferSubData(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, - const GLvoid * data); + const GLvoid *data); -void * GLAPIENTRY -_mesa_MapBuffer(GLenum target, GLenum access); +void GLAPIENTRY +_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const GLvoid *data); GLboolean GLAPIENTRY _mesa_UnmapBuffer(GLenum target); +GLboolean GLAPIENTRY +_mesa_UnmapNamedBuffer(GLuint buffer); + void GLAPIENTRY _mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params); @@ -191,21 +272,52 @@ void GLAPIENTRY _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); void GLAPIENTRY +_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params); + +void GLAPIENTRY +_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, + GLint64 *params); + +void GLAPIENTRY _mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params); void GLAPIENTRY +_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params); + + +void GLAPIENTRY _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +void GLAPIENTRY +_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); + void * GLAPIENTRY _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +void * GLAPIENTRY +_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, + GLbitfield access); + +void * GLAPIENTRY +_mesa_MapBuffer(GLenum target, GLenum access); + +void * GLAPIENTRY +_mesa_MapNamedBuffer(GLuint buffer, GLenum access); + + void GLAPIENTRY _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); +void GLAPIENTRY +_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, + GLsizeiptr length); + GLenum GLAPIENTRY _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); diff --git a/mesalib/src/mesa/main/compiler.h b/mesalib/src/mesa/main/compiler.h index 95581fb49..55152fdef 100644 --- a/mesalib/src/mesa/main/compiler.h +++ b/mesalib/src/mesa/main/compiler.h @@ -57,29 +57,6 @@ extern "C" { # elif !defined(__sparc__) && defined(__sparc) # define __sparc__ # endif -# if !defined(__volatile) -# define __volatile volatile -# endif -#endif - - -/** - * Disable assorted warnings - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -# if !defined(__GNUC__) /* mingw environment */ -# pragma warning( disable : 4068 ) /* unknown pragma */ -# pragma warning( disable : 4710 ) /* function 'foo' not inlined */ -# pragma warning( disable : 4711 ) /* function 'foo' selected for automatic inline expansion */ -# pragma warning( disable : 4127 ) /* conditional expression is constant */ -# if defined(MESA_MINWARN) -# pragma warning( disable : 4244 ) /* '=' : conversion from 'const double ' to 'float ', possible loss of data */ -# pragma warning( disable : 4018 ) /* '<' : signed/unsigned mismatch */ -# pragma warning( disable : 4305 ) /* '=' : truncation from 'const double ' to 'float ' */ -# pragma warning( disable : 4550 ) /* 'function' undefined; assuming extern returning int */ -# pragma warning( disable : 4761 ) /* integral size mismatch in argument; conversion supplied */ -# endif -# endif #endif @@ -101,14 +78,6 @@ extern "C" { #elif defined(__APPLE__) #include <CoreFoundation/CFByteOrder.h> #define CPU_TO_LE32( x ) CFSwapInt32HostToLittle( x ) -#elif (defined(_AIX)) -static inline GLuint CPU_TO_LE32(GLuint x) -{ - return (((x & 0x000000ff) << 24) | - ((x & 0x0000ff00) << 8) | - ((x & 0x00ff0000) >> 8) | - ((x & 0xff000000) >> 24)); -} #elif defined(__OpenBSD__) #include <sys/types.h> #define CPU_TO_LE32( x ) htole32( x ) @@ -125,34 +94,6 @@ static inline GLuint CPU_TO_LE32(GLuint x) -/** - * Create a macro so that asm functions can be linked into compilers other - * than GNU C - */ -#ifndef _ASMAPI -#if defined(_WIN32) -#define _ASMAPI __cdecl -#else -#define _ASMAPI -#endif -#ifdef PTR_DECL_IN_FRONT -#define _ASMAPIP * _ASMAPI -#else -#define _ASMAPIP _ASMAPI * -#endif -#endif - - -/** - * LONGSTRING macro - * gcc -pedantic warns about long string literals, LONGSTRING silences that. - */ -#if !defined(__GNUC__) -# define LONGSTRING -#else -# define LONGSTRING __extension__ -#endif - #define IEEE_ONE 0x3f800000 diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index 22c2341d6..c1acda980 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -882,18 +882,35 @@ update_default_objects(struct gl_context *ctx) /** - * This is the default function we plug into all dispatch table slots - * This helps prevents a segfault when someone calls a GL function without - * first checking if the extension's supported. + * This function is called by the glapi no-op functions. For each OpenGL + * function/entrypoint there's a simple no-op function. These "no-op" + * functions call this function. + * + * If there's a current OpenGL context for the calling thread, we record a + * GL_INVALID_OPERATION error. This can happen either because the app's + * calling an unsupported extension function, or calling an illegal function + * (such as glClear between glBegin/glEnd). + * + * If there's no current OpenGL context for the calling thread, we can + * print a message to stderr. + * + * \param name the name of the OpenGL function, without the "gl" prefix */ -int -_mesa_generic_nop(void) +static void +nop_handler(const char *name) { GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "unsupported function called " - "(unsupported extension or deprecated function?)"); - return 0; + if (ctx) { + _mesa_error(ctx, GL_INVALID_OPERATION, "gl%s(invalid call)", name); + } +#if defined(DEBUG) + else if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) { + fprintf(stderr, + "GL User Error: gl%s called without a rendering context\n", + name); + fflush(stderr); + } +#endif } @@ -909,16 +926,13 @@ nop_glFlush(void) #endif -extern void (*__glapi_noop_table[])(void); - - /** - * Allocate and initialize a new dispatch table. All the dispatch - * function pointers will point at the _mesa_generic_nop() function - * which raises GL_INVALID_OPERATION. + * Allocate and initialize a new dispatch table. The table will be + * populated with pointers to "no-op" functions. In turn, the no-op + * functions will call nop_handler() above. */ -struct _glapi_table * -_mesa_alloc_dispatch_table(void) +static struct _glapi_table * +alloc_dispatch_table(void) { /* Find the larger of Mesa's dispatch table and libGL's dispatch table. * In practice, this'll be the same for stand-alone Mesa. But for DRI @@ -926,23 +940,10 @@ _mesa_alloc_dispatch_table(void) * DRI drivers. */ GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT); - struct _glapi_table *table; - - table = malloc(numEntries * sizeof(_glapi_proc)); - if (table) { - _glapi_proc *entry = (_glapi_proc *) table; - GLint i; - for (i = 0; i < numEntries; i++) { -#if defined(_WIN32) - /* FIXME: This will not generate an error, but at least it won't - * corrupt the stack like _mesa_generic_nop does. */ - entry[i] = __glapi_noop_table[i]; -#else - entry[i] = (_glapi_proc) _mesa_generic_nop; -#endif - } + struct _glapi_table *table = _glapi_new_nop_table(numEntries); #if defined(_WIN32) + if (table) { /* This is a special case for Windows in the event that * wglGetProcAddress is called between glBegin/End(). * @@ -960,8 +961,11 @@ _mesa_alloc_dispatch_table(void) * assertion passes and the test continues. */ SET_Flush(table, nop_glFlush); -#endif } +#endif + + _glapi_set_nop_handler(nop_handler); + return table; } @@ -997,7 +1001,7 @@ create_beginend_table(const struct gl_context *ctx) { struct _glapi_table *table; - table = _mesa_alloc_dispatch_table(); + table = alloc_dispatch_table(); if (!table) return NULL; @@ -1136,7 +1140,7 @@ _mesa_initialize_context(struct gl_context *ctx, goto fail; /* setup the API dispatch tables with all nop functions */ - ctx->OutsideBeginEnd = _mesa_alloc_dispatch_table(); + ctx->OutsideBeginEnd = alloc_dispatch_table(); if (!ctx->OutsideBeginEnd) goto fail; ctx->Exec = ctx->OutsideBeginEnd; @@ -1163,7 +1167,7 @@ _mesa_initialize_context(struct gl_context *ctx, switch (ctx->API) { case API_OPENGL_COMPAT: ctx->BeginEnd = create_beginend_table(ctx); - ctx->Save = _mesa_alloc_dispatch_table(); + ctx->Save = alloc_dispatch_table(); if (!ctx->BeginEnd || !ctx->Save) goto fail; diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h index d5650877e..1cd89a84a 100644 --- a/mesalib/src/mesa/main/context.h +++ b/mesalib/src/mesa/main/context.h @@ -175,9 +175,6 @@ _mesa_finish(struct gl_context *ctx); extern void _mesa_flush(struct gl_context *ctx); -extern int -_mesa_generic_nop(void); - extern void GLAPIENTRY _mesa_Finish( void ); diff --git a/mesalib/src/mesa/main/copyimage.c b/mesalib/src/mesa/main/copyimage.c index 455929dc2..fd22f2889 100644 --- a/mesalib/src/mesa/main/copyimage.c +++ b/mesalib/src/mesa/main/copyimage.c @@ -33,6 +33,12 @@ #include "texobj.h" #include "fbobject.h" #include "textureview.h" +#include "glformats.h" + +enum mesa_block_class { + BLOCK_CLASS_128_BITS, + BLOCK_CLASS_64_BITS +}; static bool prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, @@ -253,6 +259,124 @@ check_region_bounds(struct gl_context *ctx, struct gl_texture_image *tex_image, return true; } +static bool +compressed_format_compatible(struct gl_context *ctx, + GLenum compressedFormat, GLenum otherFormat) +{ + enum mesa_block_class compressedClass, otherClass; + + /* Two view-incompatible compressed formats are never compatible. */ + if (_mesa_is_compressed_format(ctx, otherFormat)) { + return false; + } + + /* + * From ARB_copy_image spec: + * Table 4.X.1 (Compatible internal formats for copying between + * compressed and uncompressed internal formats) + * --------------------------------------------------------------------- + * | Texel / | Uncompressed | | + * | Block | internal format | Compressed internal format | + * | size | | | + * --------------------------------------------------------------------- + * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, | + * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,| + * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, | + * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,| + * | | | COMPRESSED_RG_RGTC2, | + * | | | COMPRESSED_SIGNED_RG_RGTC2, | + * | | | COMPRESSED_RGBA_BPTC_UNORM, | + * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, | + * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, | + * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT | + * --------------------------------------------------------------------- + * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, | + * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, | + * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, | + * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,| + * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, | + * | | | COMPRESSED_SIGNED_RED_RGTC1 | + * --------------------------------------------------------------------- + */ + + switch (compressedFormat) { + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + case GL_COMPRESSED_RGBA_BPTC_UNORM: + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: + compressedClass = BLOCK_CLASS_128_BITS; + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + compressedClass = BLOCK_CLASS_64_BITS; + break; + default: + return false; + } + + switch (otherFormat) { + case GL_RGBA32UI: + case GL_RGBA32I: + case GL_RGBA32F: + otherClass = BLOCK_CLASS_128_BITS; + break; + case GL_RGBA16F: + case GL_RG32F: + case GL_RGBA16UI: + case GL_RG32UI: + case GL_RGBA16I: + case GL_RG32I: + case GL_RGBA16: + case GL_RGBA16_SNORM: + otherClass = BLOCK_CLASS_64_BITS; + break; + default: + return false; + } + + return compressedClass == otherClass; +} + +static bool +copy_format_compatible(struct gl_context *ctx, + GLenum srcFormat, GLenum dstFormat) +{ + /* + * From ARB_copy_image spec: + * For the purposes of CopyImageSubData, two internal formats + * are considered compatible if any of the following conditions are + * met: + * * the formats are the same, + * * the formats are considered compatible according to the + * compatibility rules used for texture views as defined in + * section 3.9.X. In particular, if both internal formats are listed + * in the same entry of Table 3.X.2, they are considered compatible, or + * * one format is compressed and the other is uncompressed and + * Table 4.X.1 lists the two formats in the same row. + */ + + if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) { + /* Also checks if formats are equal. */ + return true; + } else if (_mesa_is_compressed_format(ctx, srcFormat)) { + return compressed_format_compatible(ctx, srcFormat, dstFormat); + } else if (_mesa_is_compressed_format(ctx, dstFormat)) { + return compressed_format_compatible(ctx, dstFormat, srcFormat); + } + + return false; +} + void GLAPIENTRY _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, @@ -265,7 +389,7 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, struct gl_texture_object *srcTexObj, *dstTexObj; struct gl_texture_image *srcTexImage, *dstTexImage; GLuint src_bw, src_bh, dst_bw, dst_bh; - int i, srcNewZ, dstNewZ, Bpt; + int i, srcNewZ, dstNewZ; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " @@ -306,15 +430,6 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, goto cleanup; } - /* Very simple sanity check. This is sufficient if one of the textures - * is compressed. */ - Bpt = _mesa_get_format_bytes(srcTexImage->TexFormat); - if (_mesa_get_format_bytes(dstTexImage->TexFormat) != Bpt) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(internalFormat mismatch)"); - goto cleanup; - } - if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, "src")) goto cleanup; @@ -324,17 +439,11 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, (srcHeight / src_bh) * dst_bh, srcDepth, "dst")) goto cleanup; - if (_mesa_is_format_compressed(srcTexImage->TexFormat)) { - /* XXX: Technically, we should probaby do some more specific checking - * here. However, this should be sufficient for all compressed - * formats that mesa supports since it is a direct memory copy. - */ - } else if (_mesa_is_format_compressed(dstTexImage->TexFormat)) { - } else if (_mesa_texture_view_compatible_format(ctx, - srcTexImage->InternalFormat, - dstTexImage->InternalFormat)) { - } else { - return; /* Error logged by _mesa_texture_view_compatible_format */ + if (!copy_format_compatible(ctx, srcTexImage->InternalFormat, + dstTexImage->InternalFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyImageSubData(internalFormat mismatch)"); + goto cleanup; } for (i = 0; i < srcDepth; ++i) { diff --git a/mesalib/src/mesa/main/formats.c b/mesalib/src/mesa/main/formats.c index 422c9dc46..2bc8bcad9 100644 --- a/mesalib/src/mesa/main/formats.c +++ b/mesalib/src/mesa/main/formats.c @@ -388,7 +388,7 @@ array_formats_equal(const void *a, const void *b) } static void -format_array_format_table_init() +format_array_format_table_init(void) { const struct gl_format_info *info; mesa_array_format array_format; diff --git a/mesalib/src/mesa/main/imports.c b/mesalib/src/mesa/main/imports.c index a7ffe2296..68c731657 100644 --- a/mesalib/src/mesa/main/imports.c +++ b/mesalib/src/mesa/main/imports.c @@ -45,6 +45,7 @@ #include <stdio.h> #include <stdarg.h> #include "c99_math.h" +#include "util/rounding.h" /* for _mesa_roundeven */ #include "imports.h" #include "context.h" #include "mtypes.h" @@ -307,26 +308,6 @@ _mesa_bitcount_64(uint64_t n) #endif -/* Using C99 rounding functions for roundToEven() implementation is - * difficult, because round(), rint, and nearbyint() are affected by - * fesetenv(), which the application may have done for its own - * purposes. Mesa's IROUND macro is close to what we want, but it - * rounds away from 0 on n + 0.5. - */ -int -_mesa_round_to_even(float val) -{ - int rounded = IROUND(val); - - if (val - floor(val) == 0.5) { - if (rounded % 2 != 0) - rounded += val > 0 ? -1 : 1; - } - - return rounded; -} - - /** * Convert a 4-byte float to a 2-byte half float. * @@ -388,7 +369,7 @@ _mesa_float_to_half(float val) * or normal. */ e = 0; - m = _mesa_round_to_even((1 << 24) * fabsf(fi.f)); + m = (int) _mesa_roundevenf((1 << 24) * fabsf(fi.f)); } else if (new_exp > 15) { /* map this value to infinity */ @@ -402,7 +383,7 @@ _mesa_float_to_half(float val) * either normal or infinite. */ e = new_exp + 15; - m = _mesa_round_to_even(flt_m / (float) (1 << 13)); + m = (int) _mesa_roundevenf(flt_m / (float) (1 << 13)); } } @@ -481,24 +462,6 @@ _mesa_half_to_float(GLhalfARB val) /** \name String */ /*@{*/ -/** - * Implemented using malloc() and strcpy. - * Note that NULL is handled accordingly. - */ -char * -_mesa_strdup( const char *s ) -{ - if (s) { - size_t l = strlen(s); - char *s2 = malloc(l + 1); - if (s2) - strcpy(s2, s); - return s2; - } - else { - return NULL; - } -} /** Compute simple checksum/hash for a string */ unsigned int diff --git a/mesalib/src/mesa/main/imports.h b/mesalib/src/mesa/main/imports.h index c211b1555..8877966ec 100755 --- a/mesalib/src/mesa/main/imports.h +++ b/mesalib/src/mesa/main/imports.h @@ -432,9 +432,6 @@ _mesa_fls(unsigned int n) #endif } -extern int -_mesa_round_to_even(float val); - extern GLhalfARB _mesa_float_to_half(float f); @@ -447,9 +444,6 @@ _mesa_half_is_negative(GLhalfARB h) return h & 0x8000; } -extern char * -_mesa_strdup( const char *s ); - extern unsigned int _mesa_str_checksum(const char *str); diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index efeee8bff..8e1dba6f0 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -693,15 +693,16 @@ struct gl_colorbuffer_attrib * \name Logic op */ /*@{*/ - GLenum LogicOp; /**< Logic operator */ GLboolean IndexLogicOpEnabled; /**< Color index logic op enabled flag */ GLboolean ColorLogicOpEnabled; /**< RGBA logic op enabled flag */ + GLenum LogicOp; /**< Logic operator */ + /*@}*/ GLboolean DitherFlag; /**< Dither enable flag */ - GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ GLboolean _ClampFragmentColor; /** < with GL_FIXED_ONLY_ARB resolved */ + GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ GLenum ClampReadColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ GLboolean sRGBEnabled; /**< Framebuffer sRGB blending/updating requested */ @@ -799,6 +800,7 @@ struct gl_eval_attrib struct gl_fog_attrib { GLboolean Enabled; /**< Fog enabled flag */ + GLboolean ColorSumEnabled; GLfloat ColorUnclamped[4]; /**< Fog color */ GLfloat Color[4]; /**< Fog color */ GLfloat Density; /**< Density >= 0.0 */ @@ -806,7 +808,6 @@ struct gl_fog_attrib GLfloat End; /**< End distance in eye coords */ GLfloat Index; /**< Fog index */ GLenum Mode; /**< Fog mode */ - GLboolean ColorSumEnabled; GLenum FogCoordinateSource; /**< GL_EXT_fog_coord */ GLfloat _Scale; /**< (End == Start) ? 1.0 : 1.0 / (End - Start) */ GLenum FogDistanceMode; /**< GL_NV_fog_distance */ @@ -846,16 +847,17 @@ struct gl_light_attrib struct gl_material Material; GLboolean Enabled; /**< Lighting enabled flag */ + GLboolean ColorMaterialEnabled; + GLenum ShadeModel; /**< GL_FLAT or GL_SMOOTH */ GLenum ProvokingVertex; /**< GL_EXT_provoking_vertex */ GLenum ColorMaterialFace; /**< GL_FRONT, BACK or FRONT_AND_BACK */ GLenum ColorMaterialMode; /**< GL_AMBIENT, GL_DIFFUSE, etc */ GLbitfield _ColorMaterialBitmask; /**< bitmask formed from Face and Mode */ - GLboolean ColorMaterialEnabled; - GLenum ClampVertexColor; /**< GL_TRUE, GL_FALSE, GL_FIXED_ONLY */ - GLboolean _ClampVertexColor; - struct gl_light EnabledList; /**< List sentinel */ + + GLboolean _ClampVertexColor; + GLenum ClampVertexColor; /**< GL_TRUE, GL_FALSE, GL_FIXED_ONLY */ /** * Derived state for optimizations: @@ -863,6 +865,8 @@ struct gl_light_attrib /*@{*/ GLboolean _NeedEyeCoords; GLboolean _NeedVertices; /**< Use fast shader? */ + struct gl_light EnabledList; /**< List sentinel */ + GLfloat _BaseColor[2][3]; /*@}*/ }; @@ -900,13 +904,15 @@ struct gl_multisample_attrib GLboolean SampleAlphaToCoverage; GLboolean SampleAlphaToOne; GLboolean SampleCoverage; - GLfloat SampleCoverageValue; GLboolean SampleCoverageInvert; GLboolean SampleShading; - GLfloat MinSampleShadingValue; /* ARB_texture_multisample / GL3.2 additions */ GLboolean SampleMask; + + GLfloat SampleCoverageValue; + GLfloat MinSampleShadingValue; + /** The GL spec defines this as an array but >32x MSAA is madness */ GLbitfield SampleMaskValue; }; @@ -977,11 +983,11 @@ struct gl_pixel_attrib */ struct gl_point_attrib { - GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */ GLfloat Size; /**< User-specified point size */ GLfloat Params[3]; /**< GL_EXT_point_parameters */ GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */ GLfloat Threshold; /**< GL_EXT_point_parameters */ + GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */ GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */ GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */ GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/ @@ -1347,6 +1353,9 @@ struct gl_texture_unit GLfloat LodBias; /**< for biasing mipmap levels */ + /** Texture targets that have a non-default texture bound */ + GLbitfield _BoundTextures; + /** Current sampler object (GL_ARB_sampler_objects) */ struct gl_sampler_object *Sampler; @@ -1373,8 +1382,6 @@ struct gl_texture_unit /** Points to highest priority, complete and enabled texture object */ struct gl_texture_object *_Current; - /** Texture targets that have a non-default texture bound */ - GLbitfield _BoundTextures; }; @@ -1384,16 +1391,15 @@ struct gl_texture_unit struct gl_texture_attrib { GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */ - struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; + + /** GL_ARB_seamless_cubemap */ + GLboolean CubeMapSeamless; struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS]; /** GL_ARB_texture_buffer_object */ struct gl_buffer_object *BufferObject; - /** GL_ARB_seamless_cubemap */ - GLboolean CubeMapSeamless; - /** Texture coord units/sets used for fragment texturing */ GLbitfield _EnabledCoordUnits; @@ -1411,6 +1417,8 @@ struct gl_texture_attrib /** Largest index + 1 of texture units that have had any CurrentTex set. */ GLint NumCurrentTexUsed; + + struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; }; @@ -1536,12 +1544,12 @@ struct gl_client_array GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */ GLsizei Stride; /**< user-specified stride */ GLsizei StrideB; /**< actual stride in bytes */ + GLuint _ElementSize; /**< size of each element in bytes */ const GLubyte *Ptr; /**< Points to array data */ GLboolean Enabled; /**< Enabled flag is a boolean */ GLboolean Normalized; /**< GL_ARB_vertex_program */ GLboolean Integer; /**< Integer-valued? */ GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ - GLuint _ElementSize; /**< size of each element in bytes */ struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ }; @@ -1600,9 +1608,11 @@ struct gl_vertex_array_object { /** Name of the VAO as received from glGenVertexArray. */ GLuint Name; - GLchar *Label; /**< GL_KHR_debug */ GLint RefCount; + + GLchar *Label; /**< GL_KHR_debug */ + mtx_t Mutex; /** @@ -1707,6 +1717,9 @@ struct gl_array_attrib GLuint RestartIndex; /*@}*/ + /** One of the DRAW_xxx flags, not consumed by drivers */ + gl_draw_method DrawMethod; + /* GL_ARB_vertex_buffer_object */ struct gl_buffer_object *ArrayBufferObj; @@ -1716,9 +1729,6 @@ struct gl_array_attrib */ const struct gl_client_array **_DrawArrays; /**< 0..VERT_ATTRIB_MAX-1 */ - /** One of the DRAW_xxx flags, not consumed by drivers */ - gl_draw_method DrawMethod; - /** Legal array datatypes and the API for which they have been computed */ GLbitfield LegalTypesMask; gl_api LegalTypesMaskAPI; @@ -1880,8 +1890,8 @@ struct gl_transform_feedback_info struct gl_transform_feedback_object { GLuint Name; /**< AKA the object ID */ - GLchar *Label; /**< GL_KHR_debug */ GLint RefCount; + GLchar *Label; /**< GL_KHR_debug */ GLboolean Active; /**< Is transform feedback enabled? */ GLboolean Paused; /**< Is transform feedback paused? */ GLboolean EndedAnytime; /**< Has EndTransformFeedback been called @@ -1889,14 +1899,6 @@ struct gl_transform_feedback_object GLboolean EverBound; /**< Has this object been bound? */ /** - * The shader program active when BeginTransformFeedback() was called. - * When active and unpaused, this equals ctx->Shader.CurrentProgram[stage], - * where stage is the pipeline stage that is the source of data for - * transform feedback. - */ - struct gl_shader_program *shader_program; - - /** * GLES: if Active is true, remaining number of primitives which can be * rendered without overflow. This is necessary to track because GLES * requires us to generate INVALID_OPERATION if a call to glDrawArrays or @@ -1907,6 +1909,14 @@ struct gl_transform_feedback_object */ unsigned GlesRemainingPrims; + /** + * The shader program active when BeginTransformFeedback() was called. + * When active and unpaused, this equals ctx->Shader.CurrentProgram[stage], + * where stage is the pipeline stage that is the source of data for + * transform feedback. + */ + struct gl_shader_program *shader_program; + /** The feedback buffers */ GLuint BufferNames[MAX_FEEDBACK_BUFFERS]; struct gl_buffer_object *Buffers[MAX_FEEDBACK_BUFFERS]; @@ -2229,8 +2239,9 @@ enum gl_frag_depth_layout struct gl_program { GLuint Id; - GLubyte *String; /**< Null-terminated program text */ GLint RefCount; + GLubyte *String; /**< Null-terminated program text */ + GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_GEOMETRY_PROGRAM_NV */ GLenum Format; /**< String encoding format */ @@ -2533,18 +2544,20 @@ struct gl_shader GLenum Type; gl_shader_stage Stage; GLuint Name; /**< AKA the handle */ - GLchar *Label; /**< GL_KHR_debug */ GLint RefCount; /**< Reference count */ + GLchar *Label; /**< GL_KHR_debug */ GLboolean DeletePending; GLboolean CompileStatus; - const GLchar *Source; /**< Source code string */ + bool IsES; /**< True if this shader uses GLSL ES */ + GLuint SourceChecksum; /**< for debug/logging purposes */ + const GLchar *Source; /**< Source code string */ + struct gl_program *Program; /**< Post-compile assembly code */ GLchar *InfoLog; struct gl_sl_pragmas Pragmas; unsigned Version; /**< GLSL version used for linking */ - GLboolean IsES; /**< True if this shader uses GLSL ES */ /** * \name Sampler tracking @@ -2588,8 +2601,8 @@ struct gl_shader * * These fields are only set post-linking. */ - struct gl_uniform_block *UniformBlocks; unsigned NumUniformBlocks; + struct gl_uniform_block *UniformBlocks; struct exec_list *ir; struct glsl_symbol_table *symbols; @@ -2879,8 +2892,8 @@ struct gl_shader_program */ unsigned LastClipDistanceArraySize; - struct gl_uniform_block *UniformBlocks; unsigned NumUniformBlocks; + struct gl_uniform_block *UniformBlocks; /** * Indices into the _LinkedShaders's UniformBlocks[] array for each stage @@ -2911,7 +2924,7 @@ struct gl_shader_program GLchar *InfoLog; unsigned Version; /**< GLSL version used for linking */ - GLboolean IsES; /**< True if this program uses GLSL ES */ + bool IsES; /**< True if this program uses GLSL ES */ /** * Per-stage shaders resulting from the first stage of linking. @@ -3036,7 +3049,7 @@ struct gl_shader_compiler_options struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */ - struct nir_shader_compiler_options *NirOptions; + const struct nir_shader_compiler_options *NirOptions; }; @@ -3265,9 +3278,10 @@ struct gl_framebuffer * polygon face orientation, and polygon stipple will have to be inverted. */ GLuint Name; + GLint RefCount; + GLchar *Label; /**< GL_KHR_debug */ - GLint RefCount; GLboolean DeletePending; /** @@ -3301,6 +3315,13 @@ struct gl_framebuffer GLboolean _AllColorBuffersFixedPoint; /* no integer, no float */ GLboolean _HasSNormOrFloatColorBuffer; + /** + * The maximum number of layers in the framebuffer, or 0 if the framebuffer + * is not layered. For cube maps and cube map arrays, each cube face + * counts as a layer. + */ + GLuint MaxNumLayers; + /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */ struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT]; @@ -3317,13 +3338,6 @@ struct gl_framebuffer struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS]; struct gl_renderbuffer *_ColorReadBuffer; - /** - * The maximum number of layers in the framebuffer, or 0 if the framebuffer - * is not layered. For cube maps and cube map arrays, each cube face - * counts as a layer. - */ - GLuint MaxNumLayers; - /** Delete this framebuffer */ void (*Delete)(struct gl_framebuffer *fb); }; @@ -4161,6 +4175,13 @@ struct gl_image_unit GLboolean Layered; /** + * GL_TRUE if the state of this image unit is valid and access from + * the shader is allowed. Otherwise loads from this unit should + * return zero and stores should have no effect. + */ + GLboolean _Valid; + + /** * Layer of the texture object bound to this unit, or zero if the * whole level is bound. */ @@ -4184,12 +4205,6 @@ struct gl_image_unit */ mesa_format _ActualFormat; - /** - * GL_TRUE if the state of this image unit is valid and access from - * the shader is allowed. Otherwise loads from this unit should - * return zero and stores should have no effect. - */ - GLboolean _Valid; }; /** diff --git a/mesalib/src/mesa/main/objectlabel.c b/mesalib/src/mesa/main/objectlabel.c index 78df96b9b..aecb5b1fa 100644 --- a/mesalib/src/mesa/main/objectlabel.c +++ b/mesalib/src/mesa/main/objectlabel.c @@ -76,7 +76,7 @@ set_label(struct gl_context *ctx, char **labelPtr, const char *label, MAX_LABEL_LENGTH); /* null-terminated string */ - *labelPtr = _mesa_strdup(label); + *labelPtr = strdup(label); } } } diff --git a/mesalib/src/mesa/main/pbo.c b/mesalib/src/mesa/main/pbo.c index 5c906ed74..0c1602532 100644 --- a/mesalib/src/mesa/main/pbo.c +++ b/mesalib/src/mesa/main/pbo.c @@ -80,7 +80,7 @@ _mesa_validate_pbo_access(GLuint dimensions, */ if (!_mesa_is_bufferobj(pack->BufferObj)) { offset = 0; - size = clientMemSize; + size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize; } else { offset = (uintptr_t)ptr; size = pack->BufferObj->Size; @@ -164,23 +164,18 @@ _mesa_map_pbo_source(struct gl_context *ctx, return buf; } - /** - * Combine PBO-read validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. + * Perform PBO validation for read operations with uncompressed textures. + * If any GL errors are detected, false is returned, otherwise returns true. * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_source - * A call to this function should have a matching call to - * _mesa_unmap_pbo_source(). */ -const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, - GLsizei clientMemSize, - const GLvoid *ptr, const char *where) +bool +_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLsizei clientMemSize, + const GLvoid *ptr, const char *where) { assert(dimensions == 1 || dimensions == 2 || dimensions == 3); @@ -188,24 +183,85 @@ _mesa_map_validate_pbo_source(struct gl_context *ctx, format, type, clientMemSize, ptr)) { if (_mesa_is_bufferobj(unpack->BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); + "%s(out of bounds PBO access)", + where); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds access: bufSize (%d) is too small)", where, clientMemSize); } - return NULL; + return false; } if (!_mesa_is_bufferobj(unpack->BufferObj)) { /* non-PBO access: no further validation to be done */ - return ptr; + return true; } if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", + where); + return false; + } + + return true; +} + +/** + * Perform PBO validation for read operations with compressed textures. + * If any GL errors are detected, false is returned, otherwise returns true. + */ +bool +_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei imageSize, const GLvoid *pixels, + const char *where) +{ + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* not using a PBO */ + return true; + } + + if ((const GLubyte *) pixels + imageSize > + ((const GLubyte *) 0) + unpack->BufferObj->Size) { + /* out of bounds read! */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)", + where); + return false; + } + + if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", + where); + return false; + } + + return true; +} + +/** + * Perform PBO-read mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_source + * \sa _mesa_map_pbo_source + * A call to this function should have a matching call to + * _mesa_unmap_pbo_source(). + */ +const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLsizei clientMemSize, + const GLvoid *ptr, const char *where) +{ + if (!_mesa_validate_pbo_source(ctx, dimensions, unpack, + width, height, depth, format, type, + clientMemSize, ptr, where)) { + return NULL; } ptr = _mesa_map_pbo_source(ctx, unpack, ptr); @@ -381,28 +437,27 @@ _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, { GLubyte *buf; + if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing, + imageSize, pixels, funcName)) { + /* error is already set during validation */ + return NULL; + } + if (!_mesa_is_bufferobj(packing->BufferObj)) { /* not using a PBO - return pointer unchanged */ return pixels; } - if ((const GLubyte *) pixels + imageSize > - ((const GLubyte *) 0) + packing->BufferObj->Size) { - /* out of bounds read! */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)", - funcName, dimensions); - return NULL; - } buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0, packing->BufferObj->Size, GL_MAP_READ_BIT, packing->BufferObj, MAP_INTERNAL); - if (!buf) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, - dimensions); - return NULL; - } + + /* Validation above already checked that PBO is not mapped, so buffer + * should not be null. + */ + assert(buf); return ADD_POINTERS(buf, pixels); } diff --git a/mesalib/src/mesa/main/pbo.h b/mesalib/src/mesa/main/pbo.h index 9851ef1a1..b3f24e62b 100644 --- a/mesalib/src/mesa/main/pbo.h +++ b/mesalib/src/mesa/main/pbo.h @@ -92,4 +92,18 @@ _mesa_unmap_teximage_pbo(struct gl_context *ctx, const struct gl_pixelstore_attrib *unpack); +extern bool +_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLsizei clientMemSize, + const GLvoid *ptr, const char *where); + +extern bool +_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei imageSize, const GLvoid *ptr, + const char *where); + #endif diff --git a/mesalib/src/mesa/main/querymatrix.c b/mesalib/src/mesa/main/querymatrix.c index ef8517571..18361c929 100644 --- a/mesalib/src/mesa/main/querymatrix.c +++ b/mesalib/src/mesa/main/querymatrix.c @@ -13,7 +13,7 @@ #include <stdlib.h> -#include <math.h> +#include "c99_math.h" #include "glheader.h" #include "querymatrix.h" #include "main/get.h" @@ -37,169 +37,120 @@ #define INT_TO_FIXED(x) ((GLfixed) ((x) << 16)) #define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0)) -#if defined(fpclassify) -/* ISO C99 says that fpclassify is a macro. Assume that any implementation - * of fpclassify, whether it's in a C99 compiler or not, will be a macro. - */ -#elif defined(_MSC_VER) -/* Not required on VS2013 and above. */ -/* Oddly, the fpclassify() function doesn't exist in such a form - * on MSVC. This is an implementation using slightly different - * lower-level Windows functions. - */ -#include <float.h> - -enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} -fpclassify(double x) -{ - switch(_fpclass(x)) { - case _FPCLASS_SNAN: /* signaling NaN */ - case _FPCLASS_QNAN: /* quiet NaN */ - return FP_NAN; - case _FPCLASS_NINF: /* negative infinity */ - case _FPCLASS_PINF: /* positive infinity */ - return FP_INFINITE; - case _FPCLASS_NN: /* negative normal */ - case _FPCLASS_PN: /* positive normal */ - return FP_NORMAL; - case _FPCLASS_ND: /* negative denormalized */ - case _FPCLASS_PD: /* positive denormalized */ - return FP_SUBNORMAL; - case _FPCLASS_NZ: /* negative zero */ - case _FPCLASS_PZ: /* positive zero */ - return FP_ZERO; - default: - /* Should never get here; but if we do, this will guarantee - * that the pattern is not treated like a number. - */ - return FP_NAN; - } -} - -#else - -enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} -fpclassify(double x) -{ - /* XXX do something better someday */ - return FP_NORMAL; -} - -#endif -GLbitfield GLAPIENTRY _mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) +GLbitfield GLAPIENTRY +_mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) { - GLfloat matrix[16]; - GLint tmp; - GLenum currentMode = GL_FALSE; - GLenum desiredMatrix = GL_FALSE; - /* The bitfield returns 1 for each component that is invalid (i.e. - * NaN or Inf). In case of error, everything is invalid. - */ - GLbitfield rv; - register unsigned int i; - unsigned int bit; - - /* This data structure defines the mapping between the current matrix - * mode and the desired matrix identifier. - */ - static struct { - GLenum currentMode; - GLenum desiredMatrix; - } modes[] = { - {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, - {GL_PROJECTION, GL_PROJECTION_MATRIX}, - {GL_TEXTURE, GL_TEXTURE_MATRIX}, - }; - - /* Call Mesa to get the current matrix in floating-point form. First, - * we have to figure out what the current matrix mode is. - */ - _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); - currentMode = (GLenum) tmp; - - /* The mode is either GL_FALSE, if for some reason we failed to query - * the mode, or a given mode from the above table. Search for the - * returned mode to get the desired matrix; if we don't find it, - * we can return immediately, as _mesa_GetInteger() will have - * logged the necessary error already. - */ - for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) { - if (modes[i].currentMode == currentMode) { - desiredMatrix = modes[i].desiredMatrix; - break; - } - } - if (desiredMatrix == GL_FALSE) { - /* Early error means all values are invalid. */ - return 0xffff; - } - - /* Now pull the matrix itself. */ - _mesa_GetFloatv(desiredMatrix, matrix); - - rv = 0; - for (i = 0, bit = 1; i < 16; i++, bit<<=1) { - float normalizedFraction; - int exp; - - switch (fpclassify(matrix[i])) { - /* A "subnormal" or denormalized number is too small to be - * represented in normal format; but despite that it's a - * valid floating point number. FP_ZERO and FP_NORMAL - * are both valid as well. We should be fine treating - * these three cases as legitimate floating-point numbers. - */ - case FP_SUBNORMAL: - case FP_NORMAL: - case FP_ZERO: - normalizedFraction = (GLfloat)frexp(matrix[i], &exp); - mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); - exponent[i] = (GLint) exp; - break; - - /* If the entry is not-a-number or an infinity, then the - * matrix component is invalid. The invalid flag for - * the component is already set; might as well set the - * other return values to known values. We'll set - * distinct values so that a savvy end user could determine - * whether the matrix component was a NaN or an infinity, - * but this is more useful for debugging than anything else - * since the standard doesn't specify any such magic - * values to return. - */ - case FP_NAN: - mantissa[i] = INT_TO_FIXED(0); - exponent[i] = (GLint) 0; - rv |= bit; - break; - - case FP_INFINITE: - /* Return +/- 1 based on whether it's a positive or - * negative infinity. - */ - if (matrix[i] > 0) { - mantissa[i] = INT_TO_FIXED(1); - } - else { - mantissa[i] = -INT_TO_FIXED(1); - } - exponent[i] = (GLint) 0; - rv |= bit; - break; - - /* We should never get here; but here's a catching case - * in case fpclassify() is returnings something unexpected. - */ - default: - mantissa[i] = INT_TO_FIXED(2); - exponent[i] = (GLint) 0; - rv |= bit; - break; - } - - } /* for each component */ - - /* All done */ - return rv; + GLfloat matrix[16]; + GLint tmp; + GLenum currentMode = GL_FALSE; + GLenum desiredMatrix = GL_FALSE; + /* The bitfield returns 1 for each component that is invalid (i.e. + * NaN or Inf). In case of error, everything is invalid. + */ + GLbitfield rv; + unsigned i, bit; + + /* This data structure defines the mapping between the current matrix + * mode and the desired matrix identifier. + */ + static const struct { + GLenum currentMode; + GLenum desiredMatrix; + } modes[] = { + {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, + {GL_PROJECTION, GL_PROJECTION_MATRIX}, + {GL_TEXTURE, GL_TEXTURE_MATRIX}, + }; + + /* Call Mesa to get the current matrix in floating-point form. First, + * we have to figure out what the current matrix mode is. + */ + _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); + currentMode = (GLenum) tmp; + + /* The mode is either GL_FALSE, if for some reason we failed to query + * the mode, or a given mode from the above table. Search for the + * returned mode to get the desired matrix; if we don't find it, + * we can return immediately, as _mesa_GetInteger() will have + * logged the necessary error already. + */ + for (i = 0; i < ARRAY_SIZE(modes); i++) { + if (modes[i].currentMode == currentMode) { + desiredMatrix = modes[i].desiredMatrix; + break; + } + } + if (desiredMatrix == GL_FALSE) { + /* Early error means all values are invalid. */ + return 0xffff; + } + + /* Now pull the matrix itself. */ + _mesa_GetFloatv(desiredMatrix, matrix); + + rv = 0; + for (i = 0, bit = 1; i < 16; i++, bit<<=1) { + float normalizedFraction; + int exp; + + switch (fpclassify(matrix[i])) { + case FP_SUBNORMAL: + case FP_NORMAL: + case FP_ZERO: + /* A "subnormal" or denormalized number is too small to be + * represented in normal format; but despite that it's a + * valid floating point number. FP_ZERO and FP_NORMAL + * are both valid as well. We should be fine treating + * these three cases as legitimate floating-point numbers. + */ + normalizedFraction = (GLfloat)frexp(matrix[i], &exp); + mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); + exponent[i] = (GLint) exp; + break; + + case FP_NAN: + /* If the entry is not-a-number or an infinity, then the + * matrix component is invalid. The invalid flag for + * the component is already set; might as well set the + * other return values to known values. We'll set + * distinct values so that a savvy end user could determine + * whether the matrix component was a NaN or an infinity, + * but this is more useful for debugging than anything else + * since the standard doesn't specify any such magic + * values to return. + */ + mantissa[i] = INT_TO_FIXED(0); + exponent[i] = (GLint) 0; + rv |= bit; + break; + + case FP_INFINITE: + /* Return +/- 1 based on whether it's a positive or + * negative infinity. + */ + if (matrix[i] > 0) { + mantissa[i] = INT_TO_FIXED(1); + } + else { + mantissa[i] = -INT_TO_FIXED(1); + } + exponent[i] = (GLint) 0; + rv |= bit; + break; + + default: + /* We should never get here; but here's a catching case + * in case fpclassify() is returnings something unexpected. + */ + mantissa[i] = INT_TO_FIXED(2); + exponent[i] = (GLint) 0; + rv |= bit; + break; + } + + } /* for each component */ + + /* All done */ + return rv; } diff --git a/mesalib/src/mesa/main/scissor.c b/mesalib/src/mesa/main/scissor.c index 83f39e2a0..bc8224c7d 100644 --- a/mesalib/src/mesa/main/scissor.c +++ b/mesalib/src/mesa/main/scissor.c @@ -201,13 +201,13 @@ void GLAPIENTRY _mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) { - ScissorIndexed(index, left, bottom, width, height, "glScissorIndexd"); + ScissorIndexed(index, left, bottom, width, height, "glScissorIndexed"); } void GLAPIENTRY _mesa_ScissorIndexedv(GLuint index, const GLint *v) { - ScissorIndexed(index, v[0], v[1], v[2], v[3], "glScissorIndexdv"); + ScissorIndexed(index, v[0], v[1], v[2], v[3], "glScissorIndexedv"); } /** diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index 5731d581a..30716f5e3 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -1027,15 +1027,14 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, static void -use_shader_program(struct gl_context *ctx, GLenum type, +use_shader_program(struct gl_context *ctx, gl_shader_stage stage, struct gl_shader_program *shProg, struct gl_pipeline_object *shTarget) { struct gl_shader_program **target; - gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type); target = &shTarget->CurrentProgram[stage]; - if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL)) + if ((shProg != NULL) && (shProg->_LinkedShaders[stage] == NULL)) shProg = NULL; if (*target != shProg) { @@ -1048,17 +1047,17 @@ use_shader_program(struct gl_context *ctx, GLenum type, * it from that binding point as well. This ensures that the correct * semantics of glDeleteProgram are maintained. */ - switch (type) { - case GL_VERTEX_SHADER: + switch (stage) { + case MESA_SHADER_VERTEX: /* Empty for now. */ break; - case GL_GEOMETRY_SHADER_ARB: + case MESA_SHADER_GEOMETRY: /* Empty for now. */ break; - case GL_COMPUTE_SHADER: + case MESA_SHADER_COMPUTE: /* Empty for now. */ break; - case GL_FRAGMENT_SHADER: + case MESA_SHADER_FRAGMENT: if (*target == ctx->_Shader->_CurrentFragmentProgram) { _mesa_reference_shader_program(ctx, &ctx->_Shader->_CurrentFragmentProgram, @@ -1079,10 +1078,9 @@ use_shader_program(struct gl_context *ctx, GLenum type, void _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg) { - use_shader_program(ctx, GL_VERTEX_SHADER, shProg, &ctx->Shader); - use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg, &ctx->Shader); - use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, &ctx->Shader); - use_shader_program(ctx, GL_COMPUTE_SHADER, shProg, &ctx->Shader); + int i; + for (i = 0; i < MESA_SHADER_STAGES; i++) + use_shader_program(ctx, i, shProg, &ctx->Shader); _mesa_active_program(ctx, shProg, "glUseProgram"); if (ctx->Driver.UseProgram) @@ -1460,7 +1458,7 @@ read_shader(const char *fname) fclose(f); - shader = _mesa_strdup(buffer); + shader = strdup(buffer); free(buffer); return shader; @@ -1889,7 +1887,8 @@ _mesa_use_shader_program(struct gl_context *ctx, GLenum type, struct gl_shader_program *shProg, struct gl_pipeline_object *shTarget) { - use_shader_program(ctx, type, shProg, shTarget); + gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type); + use_shader_program(ctx, stage, shProg, shTarget); if (ctx->Driver.UseProgram) ctx->Driver.UseProgram(ctx, shProg); diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index f975c160e..255d36559 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -1088,48 +1088,9 @@ _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, /* Must handle special case GL_TEXTURE_CUBE_MAP. */ if (texObj->Target == GL_TEXTURE_CUBE_MAP) { - /* Error checking */ - if (texObj->NumLayers < 6) { - /* Not enough image planes for a cube map. The spec does not say - * what should happen in this case because the user has always - * specified each cube face separately (using - * GL_TEXTURE_CUBE_MAP_POSITIVE_X+i) in previous GL versions. - * This is addressed in Khronos Bug 13223. - */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetTextureImage(insufficient cube map storage)"); - return; - } - - /* - * What do we do if the user created a texture with the following code - * and then called this function with its handle? - * - * GLuint tex; - * glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &tex); - * glBindTexture(GL_TEXTURE_CUBE_MAP, tex); - * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, ...); - * glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, ...); - * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, ...); - * // Note: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y not set, or given the - * // wrong format, or given the wrong size, etc. - * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, ...); - * glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, ...); - * - * A bug has been filed against the spec for this case. In the - * meantime, we will check for cube completeness. - * - * According to Section 8.17 Texture Completeness in the OpenGL 4.5 - * Core Profile spec (30.10.2014): - * "[A] cube map texture is cube complete if the - * following conditions all hold true: The [base level] texture - * images of each of the six cube map faces have identical, positive, - * and square dimensions. The [base level] images were each specified - * with the same internal format." - * - * It seems reasonable to check for cube completeness of an arbitrary - * level here so that the returned data has a consistent format and size - * and therefore fits in the user's buffer. + /* Make sure the texture object is a proper cube. + * (See texturesubimage in teximage.c for details on why this check is + * performed.) */ if (!_mesa_cube_level_complete(texObj, level)) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -1140,6 +1101,8 @@ _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, /* Copy each face. */ for (i = 0; i < 6; ++i) { texImage = texObj->Image[i][level]; + assert(texImage); + _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level, format, type, bufSize, pixels, true); @@ -1340,13 +1303,21 @@ _mesa_GetCompressedTextureImage(GLuint texture, GLint level, /* Must handle special case GL_TEXTURE_CUBE_MAP. */ if (texObj->Target == GL_TEXTURE_CUBE_MAP) { - assert(texObj->NumLayers >= 6); + + /* Make sure the texture object is a proper cube. + * (See texturesubimage in teximage.c for details on why this check is + * performed.) + */ + if (!_mesa_cube_level_complete(texObj, level)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTextureImage(cube map incomplete)"); + return; + } /* Copy each face. */ for (i = 0; i < 6; ++i) { texImage = texObj->Image[i][level]; - if (!texImage) - return; + assert(texImage); _mesa_get_compressed_texture_image(ctx, texObj, texImage, texObj->Target, level, diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index 611d664b6..8d9d7cfc1 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -53,6 +53,7 @@ #include "mtypes.h" #include "glformats.h" #include "texstore.h" +#include "pbo.h" /** @@ -1619,32 +1620,30 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, /* Check size */ if (subWidth < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "%s%dD(width=%d)", func, dims, subWidth); + "%s(width=%d)", func, subWidth); return GL_TRUE; } if (dims > 1 && subHeight < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "%s%dD(height=%d)", func, dims, subHeight); + "%s(height=%d)", func, subHeight); return GL_TRUE; } if (dims > 2 && subDepth < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "%s%dD(depth=%d)", func, dims, subDepth); + "%s(depth=%d)", func, subDepth); return GL_TRUE; } /* check xoffset and width */ if (xoffset < - (GLint) destImage->Border) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset)", - func, dims); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset)", func); return GL_TRUE; } if (xoffset + subWidth > (GLint) destImage->Width) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset+width)", - func, dims); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset+width)", func); return GL_TRUE; } @@ -1652,13 +1651,11 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, if (dims > 1) { GLint yBorder = (target == GL_TEXTURE_1D_ARRAY) ? 0 : destImage->Border; if (yoffset < -yBorder) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset)", - func, dims); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset)", func); return GL_TRUE; } if (yoffset + subHeight > (GLint) destImage->Height) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset+height)", - func, dims); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset+height)", func); return GL_TRUE; } } @@ -1671,7 +1668,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, 0 : destImage->Border; if (zoffset < -zBorder) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", func); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset)", func); return GL_TRUE; } @@ -1679,7 +1676,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, if (target == GL_TEXTURE_CUBE_MAP) depth = 6; if (zoffset + subDepth > depth) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset+depth)", func); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset+depth)", func); return GL_TRUE; } } @@ -1697,8 +1694,8 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, /* offset must be multiple of block size */ if ((xoffset % bw != 0) || (yoffset % bh != 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s%dD(xoffset = %d, yoffset = %d)", - func, dims, xoffset, yoffset); + "%s(xoffset = %d, yoffset = %d)", + func, xoffset, yoffset); return GL_TRUE; } @@ -1710,14 +1707,14 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims, if ((subWidth % bw != 0) && (xoffset + subWidth != (GLint) destImage->Width)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s%dD(width = %d)", func, dims, subWidth); + "%s(width = %d)", func, subWidth); return GL_TRUE; } if ((subHeight % bh != 0) && (yoffset + subHeight != (GLint) destImage->Height)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s%dD(height = %d)", func, dims, subHeight); + "%s(height = %d)", func, subHeight); return GL_TRUE; } } @@ -2113,7 +2110,8 @@ texture_error_check( struct gl_context *ctx, GLint level, GLint internalFormat, GLenum format, GLenum type, GLint width, GLint height, - GLint depth, GLint border ) + GLint depth, GLint border, + const GLvoid *pixels ) { GLenum err; @@ -2198,6 +2196,13 @@ texture_error_check( struct gl_context *ctx, return GL_TRUE; } + /* validate the bound PBO, if any */ + if (!_mesa_validate_pbo_source(ctx, dimensions, &ctx->Unpack, + width, height, depth, format, type, + INT_MAX, pixels, "glTexImage")) { + return GL_TRUE; + } + /* make sure internal format and format basically agree */ if (!texture_formats_agree(internalFormat, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -2294,7 +2299,7 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize) + GLsizei imageSize, const GLvoid *data) { const GLint maxLevels = _mesa_max_texture_levels(ctx, target); GLint expectedSize; @@ -2322,6 +2327,13 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, return GL_TRUE; } + /* validate the bound PBO, if any */ + if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, &ctx->Unpack, + imageSize, data, + "glCompressedTexImage")) { + return GL_TRUE; + } + switch (internalFormat) { case GL_PALETTE4_RGB8_OES: case GL_PALETTE4_RGBA8_OES: @@ -2454,30 +2466,28 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, - GLenum format, GLenum type, bool dsa) + GLenum format, GLenum type, const GLvoid *pixels, + bool dsa, const char *callerName) { struct gl_texture_image *texImage; GLenum err; - const char* suffix = dsa ? "ture" : ""; if (!texObj) { /* must be out of memory */ - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sSubImage%dD()", - suffix, dimensions); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", callerName); return GL_TRUE; } /* check target (proxies not allowed) */ if (!legal_texsubimage_target(ctx, dimensions, target, dsa)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTex%sSubImage%uD(target=%s)", - suffix, dimensions, _mesa_lookup_enum_by_nr(target)); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)", + callerName, _mesa_lookup_enum_by_nr(target)); return GL_TRUE; } /* level check */ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sSubImage%uD(level=%d)", - suffix, dimensions, level); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level=%d)", callerName, level); return GL_TRUE; } @@ -2489,9 +2499,8 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, if (_mesa_is_gles(ctx) && !_mesa_is_gles3(ctx)) { err = _mesa_es_error_check_format_and_type(format, type, dimensions); if (err != GL_NO_ERROR) { - _mesa_error(ctx, err, - "glTex%sSubImage%dD(format = %s, type = %s)", - suffix, dimensions, _mesa_lookup_enum_by_nr(format), + _mesa_error(ctx, err, "%s(format = %s, type = %s)", + callerName, _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type)); return GL_TRUE; } @@ -2500,34 +2509,37 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, - "glTex%sSubImage%dD(incompatible format = %s, type = %s)", - suffix, dimensions, _mesa_lookup_enum_by_nr(format), + "%s(incompatible format = %s, type = %s)", + callerName, _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type)); return GL_TRUE; } + /* validate the bound PBO, if any */ + if (!_mesa_validate_pbo_source(ctx, dimensions, &ctx->Unpack, + width, height, depth, format, type, + INT_MAX, pixels, callerName)) { + return GL_TRUE; + } + texImage = _mesa_select_tex_image(texObj, target, level); if (!texImage) { /* non-existant texture level */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTex%sSubImage%dD(invalid texture image)", suffix, - dimensions); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture image)", + callerName); return GL_TRUE; } if (error_check_subtexture_dimensions(ctx, dimensions, texImage, xoffset, yoffset, zoffset, - width, height, depth, - dsa ? "glTextureSubImage" : - "glTexSubImage")) { + width, height, depth, callerName)) { return GL_TRUE; } if (_mesa_is_format_compressed(texImage->TexFormat)) { if (compressedteximage_only_format(ctx, texImage->InternalFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTex%sSubImage%dD(no compression for format)", - suffix, dimensions); + "%s(no compression for format)", callerName); return GL_TRUE; } } @@ -2537,8 +2549,7 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, if (_mesa_is_format_integer_color(texImage->TexFormat) != _mesa_is_enum_format_integer(format)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTex%sSubImage%dD(integer/non-integer format mismatch)", - suffix, dimensions); + "%s(integer/non-integer format mismatch)", callerName); return GL_TRUE; } } @@ -2815,10 +2826,9 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions, const struct gl_texture_object *texObj, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLint width, GLint height, bool dsa) + GLint width, GLint height, const char *caller) { struct gl_texture_image *texImage; - const char *suffix = dsa ? "ture" : ""; /* Check that the source buffer is complete */ if (_mesa_is_user_fbo(ctx->ReadBuffer)) { @@ -2827,31 +2837,26 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions, } if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glCopyTex%sSubImage%dD(invalid readbuffer)", - suffix, dimensions); + "%s(invalid readbuffer)", caller); return GL_TRUE; } if (ctx->ReadBuffer->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTex%sSubImage%dD(multisample FBO)", suffix, - dimensions); + "%s(multisample FBO)", caller); return GL_TRUE; } } /* Check level */ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTex%sSubImage%dD(level=%d)", suffix, - dimensions, level); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level=%d)", caller, level); return GL_TRUE; } /* Get dest image pointers */ if (!texObj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTex%sSubImage%dD()", - suffix, dimensions); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", caller); return GL_TRUE; } @@ -2859,37 +2864,33 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions, if (!texImage) { /* destination image does not exist */ _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTex%sSubImage%dD(invalid texture image)", - suffix, dimensions); + "%s(invalid texture image)", caller); return GL_TRUE; } if (error_check_subtexture_dimensions(ctx, dimensions, texImage, xoffset, yoffset, zoffset, - width, height, 1, dsa ? - "glCompressedTextureSubImage" : - "glCompressedTexSubImage")) { + width, height, 1, caller)) { return GL_TRUE; } if (_mesa_is_format_compressed(texImage->TexFormat)) { if (compressedteximage_only_format(ctx, texImage->InternalFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTex%sSubImage%dD(no compression for format)", - suffix, dimensions); + "%s(no compression for format)", caller); return GL_TRUE; } } if (texImage->InternalFormat == GL_YCBCR_MESA) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTex%sSubImage2D", suffix); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s()", caller); return GL_TRUE; } if (!_mesa_source_buffer_exists(ctx, texImage->_BaseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTex%sSubImage%dD(missing readbuffer, format=0x%x)", - suffix, dimensions, texImage->_BaseFormat); + "%s(missing readbuffer, format=0x%x)", caller, + texImage->_BaseFormat); return GL_TRUE; } @@ -2907,8 +2908,7 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions, if (_mesa_is_format_integer_color(rb->Format) != _mesa_is_format_integer_color(texImage->TexFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTex%sSubImage%dD(integer vs non-integer)", - suffix, dimensions); + "%s(integer vs non-integer)", caller); return GL_TRUE; } } @@ -3218,12 +3218,13 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, if (compressed_texture_error_check(ctx, dims, target, level, internalFormat, width, height, depth, - border, imageSize)) + border, imageSize, pixels)) return; } else { if (texture_error_check(ctx, dims, target, level, internalFormat, - format, type, width, height, depth, border)) + format, type, width, height, depth, border, + pixels)) return; } @@ -3562,7 +3563,8 @@ static void texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels) + GLenum format, GLenum type, const GLvoid *pixels, + const char *callerName) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; @@ -3573,7 +3575,8 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, if (texsubimage_error_check(ctx, dims, texObj, target, level, xoffset, yoffset, zoffset, - width, height, depth, format, type, false)) { + width, height, depth, format, type, + pixels, false, callerName)) { return; /* error was detected */ } @@ -3603,7 +3606,8 @@ texturesubimage(struct gl_context *ctx, GLuint dims, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels) + GLenum format, GLenum type, const GLvoid *pixels, + const char *callerName) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; @@ -3627,7 +3631,8 @@ texturesubimage(struct gl_context *ctx, GLuint dims, if (texsubimage_error_check(ctx, dims, texObj, texObj->Target, level, xoffset, yoffset, zoffset, - width, height, depth, format, type, true)) { + width, height, depth, format, type, + pixels, true, callerName)) { return; /* error was detected */ } @@ -3636,20 +3641,6 @@ texturesubimage(struct gl_context *ctx, GLuint dims, if (texObj->Target == GL_TEXTURE_CUBE_MAP) { GLint rowStride; - /* Error checking */ - if (texObj->NumLayers < 6) { - /* Not enough image planes for a cube map. The spec does not say - * what should happen in this case because the user has always - * specified each cube face separately (using - * GL_TEXTURE_CUBE_MAP_POSITIVE_X+i) in previous GL versions. - * This is addressed in Khronos Bug 13223. - */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTextureSubImage%uD(insufficient cube map storage)", - dims); - return; - } - /* * What do we do if the user created a texture with the following code * and then called this function with its handle? @@ -3691,6 +3682,8 @@ texturesubimage(struct gl_context *ctx, GLuint dims, /* Copy in each face. */ for (i = 0; i < 6; ++i) { texImage = texObj->Image[i][level]; + assert(texImage); + _mesa_texture_sub_image(ctx, 3, texObj, texImage, texObj->Target, level, xoffset, yoffset, zoffset, width, height, 1, format, @@ -3700,8 +3693,7 @@ texturesubimage(struct gl_context *ctx, GLuint dims, } else { texImage = _mesa_select_tex_image(texObj, texObj->Target, level); - if (!texImage) - return; + assert(texImage); _mesa_texture_sub_image(ctx, dims, texObj, texImage, texObj->Target, level, xoffset, yoffset, zoffset, @@ -3721,7 +3713,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level, texsubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1, - format, type, pixels); + format, type, pixels, "glTexSubImage1D"); } @@ -3736,7 +3728,7 @@ _mesa_TexSubImage2D( GLenum target, GLint level, texsubimage(ctx, 2, target, level, xoffset, yoffset, 0, width, height, 1, - format, type, pixels); + format, type, pixels, "glTexSubImage2D"); } @@ -3752,7 +3744,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level, texsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, width, height, depth, - format, type, pixels); + format, type, pixels, "glTexSubImage3D"); } void GLAPIENTRY @@ -3765,7 +3757,7 @@ _mesa_TextureSubImage1D(GLuint texture, GLint level, texturesubimage(ctx, 1, texture, level, xoffset, 0, 0, width, 1, 1, - format, type, pixels); + format, type, pixels, "glTextureSubImage1D"); } @@ -3780,7 +3772,7 @@ _mesa_TextureSubImage2D(GLuint texture, GLint level, texturesubimage(ctx, 2, texture, level, xoffset, yoffset, 0, width, height, 1, - format, type, pixels); + format, type, pixels, "glTextureSubImage2D"); } @@ -3795,7 +3787,7 @@ _mesa_TextureSubImage3D(GLuint texture, GLint level, texturesubimage(ctx, 3, texture, level, xoffset, yoffset, zoffset, width, height, depth, - format, type, pixels); + format, type, pixels, "glTextureSubImage3D"); } @@ -4040,15 +4032,14 @@ _mesa_copy_texture_sub_image(struct gl_context *ctx, GLuint dims, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, - bool dsa) + const char *caller) { struct gl_texture_image *texImage; FLUSH_VERTICES(ctx, 0); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glCopyTex%sSubImage%uD %s %d %d %d %d %d %d %d %d\n", - dsa ? "ture" : "", dims, + _mesa_debug(ctx, "%s %s %d %d %d %d %d %d %d %d\n", caller, _mesa_lookup_enum_by_nr(target), level, xoffset, yoffset, zoffset, x, y, width, height); @@ -4057,7 +4048,7 @@ _mesa_copy_texture_sub_image(struct gl_context *ctx, GLuint dims, if (copytexsubimage_error_check(ctx, dims, texObj, target, level, xoffset, yoffset, zoffset, - width, height, dsa)) { + width, height, caller)) { return; } @@ -4103,14 +4094,14 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { struct gl_texture_object* texObj; + const char *self = "glCopyTexSubImage1D"; GET_CURRENT_CONTEXT(ctx); /* Check target (proxies not allowed). Target must be checked prior to * calling _mesa_get_current_tex_object. */ if (!legal_texsubimage_target(ctx, 1, target, false)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTexSubImage1D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(target)); return; } @@ -4120,7 +4111,7 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, return; _mesa_copy_texture_sub_image(ctx, 1, texObj, target, level, xoffset, 0, 0, - x, y, width, 1, false); + x, y, width, 1, self); } @@ -4131,14 +4122,14 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_object* texObj; + const char *self = "glCopyTexSubImage2D"; GET_CURRENT_CONTEXT(ctx); /* Check target (proxies not allowed). Target must be checked prior to * calling _mesa_get_current_tex_object. */ if (!legal_texsubimage_target(ctx, 2, target, false)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTexSubImage2D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(target)); return; } @@ -4149,7 +4140,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, _mesa_copy_texture_sub_image(ctx, 2, texObj, target, level, xoffset, yoffset, 0, - x, y, width, height, false); + x, y, width, height, self); } @@ -4160,14 +4151,14 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_object* texObj; + const char *self = "glCopyTexSubImage3D"; GET_CURRENT_CONTEXT(ctx); /* Check target (proxies not allowed). Target must be checked prior to * calling _mesa_get_current_tex_object. */ if (!legal_texsubimage_target(ctx, 3, target, false)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTexSubImage3D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(target)); return; } @@ -4178,7 +4169,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, _mesa_copy_texture_sub_image(ctx, 3, texObj, target, level, xoffset, yoffset, zoffset, - x, y, width, height, false); + x, y, width, height, self); } void GLAPIENTRY @@ -4186,22 +4177,22 @@ _mesa_CopyTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) { struct gl_texture_object* texObj; + const char *self = "glCopyTextureSubImage1D"; GET_CURRENT_CONTEXT(ctx); - texObj = _mesa_lookup_texture_err(ctx, texture, "glCopyTextureSubImage1D"); + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; /* Check target (proxies not allowed). */ if (!legal_texsubimage_target(ctx, 1, texObj->Target, true)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTextureSubImage1D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(texObj->Target)); return; } _mesa_copy_texture_sub_image(ctx, 1, texObj, texObj->Target, level, - xoffset, 0, 0, x, y, width, 1, true); + xoffset, 0, 0, x, y, width, 1, self); } void GLAPIENTRY @@ -4210,23 +4201,23 @@ _mesa_CopyTextureSubImage2D(GLuint texture, GLint level, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_texture_object* texObj; + const char *self = "glCopyTextureSubImage2D"; GET_CURRENT_CONTEXT(ctx); - texObj = _mesa_lookup_texture_err(ctx, texture, "glCopyTextureSubImage2D"); + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; /* Check target (proxies not allowed). */ if (!legal_texsubimage_target(ctx, 2, texObj->Target, true)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTextureSubImage2D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(texObj->Target)); return; } _mesa_copy_texture_sub_image(ctx, 2, texObj, texObj->Target, level, xoffset, yoffset, 0, - x, y, width, height, true); + x, y, width, height, self); } @@ -4237,23 +4228,31 @@ _mesa_CopyTextureSubImage3D(GLuint texture, GLint level, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_texture_object* texObj; + const char *self = "glCopyTextureSubImage3D"; GET_CURRENT_CONTEXT(ctx); - texObj = _mesa_lookup_texture_err(ctx, texture, "glCopyTextureSubImage3D"); + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; /* Check target (proxies not allowed). */ if (!legal_texsubimage_target(ctx, 3, texObj->Target, true)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTextureSubImage3D(invalid target %s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", self, _mesa_lookup_enum_by_nr(texObj->Target)); return; } - _mesa_copy_texture_sub_image(ctx, 3, texObj, texObj->Target, level, - xoffset, yoffset, zoffset, - x, y, width, height, true); + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + /* Act like CopyTexSubImage2D */ + _mesa_copy_texture_sub_image(ctx, 2, texObj, + GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset, + level, xoffset, yoffset, 0, + x, y, width, height, self); + } + else + _mesa_copy_texture_sub_image(ctx, 3, texObj, texObj->Target, level, + xoffset, yoffset, zoffset, + x, y, width, height, self); } static bool @@ -4636,68 +4635,72 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, bool dsa) + GLenum format, GLsizei imageSize, + const GLvoid *data, const char *callerName) { struct gl_texture_image *texImage; GLint expectedSize; - const char *suffix = dsa ? "ture" : ""; /* this will catch any invalid compressed format token */ if (!_mesa_is_compressed_format(ctx, format)) { _mesa_error(ctx, GL_INVALID_ENUM, - "glCompressedTex%sSubImage%uD(format)", suffix, dims); + "%s(format)", callerName); return GL_TRUE; } if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCompressedTex%sSubImage%uD(level=%d)", - suffix, dims, level); + "%s(level=%d)", + callerName, level); + return GL_TRUE; + } + + /* validate the bound PBO, if any */ + if (!_mesa_validate_pbo_source_compressed(ctx, dims, &ctx->Unpack, + imageSize, data, callerName)) { return GL_TRUE; } /* Check for invalid pixel storage modes */ if (!_mesa_compressed_pixel_storage_error_check(ctx, dims, - &ctx->Unpack, - dsa ? "glCompressedTextureSubImage" : - "glCompressedTexSubImage")) { + &ctx->Unpack, callerName)) { return GL_TRUE; } expectedSize = compressed_tex_size(width, height, depth, format); if (expectedSize != imageSize) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCompressedTex%sSubImage%uD(size=%d)", - suffix, dims, imageSize); + "%s(size=%d)", + callerName, imageSize); return GL_TRUE; } texImage = _mesa_select_tex_image(texObj, target, level); if (!texImage) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTex%sSubImage%uD(invalid texture image)", - suffix, dims); + "%s(invalid texture image)", + callerName); return GL_TRUE; } if ((GLint) format != texImage->InternalFormat) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTex%sSubImage%uD(format=0x%x)", - suffix, dims, format); + "%s(format=0x%x)", + callerName, format); return GL_TRUE; } if (compressedteximage_only_format(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTex%sSubImage%uD(format=0x%x cannot be updated)", - suffix, dims, format); + "%s(format=0x%x cannot be updated)", + callerName, format); return GL_TRUE; } if (error_check_subtexture_dimensions(ctx, dims, texImage, xoffset, yoffset, zoffset, width, height, depth, - "glCompressedTexSubImage")) { + callerName)) { return GL_TRUE; } @@ -4748,30 +4751,19 @@ _mesa_CompressedTexImage3D(GLenum target, GLint level, void _mesa_compressed_texture_sub_image(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj, + struct gl_texture_image *texImage, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, - const GLvoid *data, bool dsa) + const GLvoid *data) { - struct gl_texture_image *texImage; - - if (compressed_subtexture_error_check(ctx, dims, texObj, target, - level, xoffset, yoffset, zoffset, - width, height, depth, - format, imageSize, dsa)) { - return; - } - FLUSH_VERTICES(ctx, 0); _mesa_lock_texture(ctx, texObj); { - texImage = _mesa_select_tex_image(texObj, target, level); - assert(texImage); - if (width > 0 && height > 0 && depth > 0) { ctx->Driver.CompressedTexSubImage(ctx, dims, texImage, xoffset, yoffset, zoffset, @@ -4795,6 +4787,8 @@ _mesa_CompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei imageSize, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); if (compressed_subtexture_target_check(ctx, target, 1, format, false, @@ -4806,9 +4800,20 @@ _mesa_CompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset, if (!texObj) return; - _mesa_compressed_texture_sub_image(ctx, 1, texObj, target, level, + if (compressed_subtexture_error_check(ctx, 1, texObj, target, + level, xoffset, 0, 0, + width, 1, 1, + format, imageSize, data, + "glCompressedTexSubImage1D")) { + return; + } + + texImage = _mesa_select_tex_image(texObj, target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 1, texObj, texImage, target, level, xoffset, 0, 0, width, 1, 1, - format, imageSize, data, false); + format, imageSize, data); } void GLAPIENTRY @@ -4817,6 +4822,8 @@ _mesa_CompressedTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLsizei imageSize, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); texObj = _mesa_lookup_texture_err(ctx, texture, @@ -4830,9 +4837,21 @@ _mesa_CompressedTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, return; } - _mesa_compressed_texture_sub_image(ctx, 1, texObj, texObj->Target, level, + if (compressed_subtexture_error_check(ctx, 1, texObj, texObj->Target, + level, xoffset, 0, 0, + width, 1, 1, + format, imageSize, data, + "glCompressedTextureSubImage1D")) { + return; + } + + texImage = _mesa_select_tex_image(texObj, texObj->Target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 1, texObj, texImage, + texObj->Target, level, xoffset, 0, 0, width, 1, 1, - format, imageSize, data, true); + format, imageSize, data); } @@ -4843,6 +4862,8 @@ _mesa_CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); if (compressed_subtexture_target_check(ctx, target, 2, format, false, @@ -4854,9 +4875,21 @@ _mesa_CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, if (!texObj) return; - _mesa_compressed_texture_sub_image(ctx, 2, texObj, target, level, + if (compressed_subtexture_error_check(ctx, 2, texObj, target, + level, xoffset, yoffset, 0, + width, height, 1, + format, imageSize, data, + "glCompressedTexSubImage2D")) { + return; + } + + + texImage = _mesa_select_tex_image(texObj, target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 2, texObj, texImage, target, level, xoffset, yoffset, 0, width, height, 1, - format, imageSize, data, false); + format, imageSize, data); } void GLAPIENTRY @@ -4867,6 +4900,8 @@ _mesa_CompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); texObj = _mesa_lookup_texture_err(ctx, texture, @@ -4880,9 +4915,21 @@ _mesa_CompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, return; } - _mesa_compressed_texture_sub_image(ctx, 2, texObj, texObj->Target, level, + if (compressed_subtexture_error_check(ctx, 2, texObj, texObj->Target, + level, xoffset, yoffset, 0, + width, height, 1, + format, imageSize, data, + "glCompressedTextureSubImage2D")) { + return; + } + + texImage = _mesa_select_tex_image(texObj, texObj->Target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 2, texObj, texImage, + texObj->Target, level, xoffset, yoffset, 0, width, height, 1, - format, imageSize, data, true); + format, imageSize, data); } void GLAPIENTRY @@ -4892,6 +4939,8 @@ _mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLsizei imageSize, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); if (compressed_subtexture_target_check(ctx, target, 3, format, false, @@ -4903,10 +4952,22 @@ _mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, if (!texObj) return; - _mesa_compressed_texture_sub_image(ctx, 3, texObj, target, level, + if (compressed_subtexture_error_check(ctx, 3, texObj, target, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + "glCompressedTexSubImage3D")) { + return; + } + + + texImage = _mesa_select_tex_image(texObj, target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 3, texObj, texImage, target, level, xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, data, false); + format, imageSize, data); } void GLAPIENTRY @@ -4917,6 +4978,8 @@ _mesa_CompressedTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, const GLvoid *data) { struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); texObj = _mesa_lookup_texture_err(ctx, texture, @@ -4930,10 +4993,60 @@ _mesa_CompressedTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, return; } - _mesa_compressed_texture_sub_image(ctx, 3, texObj, texObj->Target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, imageSize, data, true); + if (compressed_subtexture_error_check(ctx, 3, texObj, texObj->Target, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + "glCompressedTextureSubImage3D")) { + return; + } + + /* Must handle special case GL_TEXTURE_CUBE_MAP. */ + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + const char *pixels = data; + int i; + GLint image_stride; + + /* Make sure the texture object is a proper cube. + * (See texturesubimage in teximage.c for details on why this check is + * performed.) + */ + if (!_mesa_cube_level_complete(texObj, level)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTextureSubImage3D(cube map incomplete)"); + return; + } + + /* Copy in each face. */ + for (i = 0; i < 6; ++i) { + texImage = texObj->Image[i][level]; + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 3, texObj, texImage, + texObj->Target, level, + xoffset, yoffset, zoffset, + width, height, 1, + format, imageSize, pixels); + + /* Compressed images don't have a client format */ + image_stride = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, 1); + + pixels += image_stride; + imageSize -= image_stride; + } + } + else { + texImage = _mesa_select_tex_image(texObj, texObj->Target, level); + assert(texImage); + + _mesa_compressed_texture_sub_image(ctx, 3, texObj, texImage, + texObj->Target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data); + } } static mesa_format @@ -5152,24 +5265,34 @@ _mesa_validate_texbuffer_format(const struct gl_context *ctx, void _mesa_texture_buffer_range(struct gl_context *ctx, - struct gl_texture_object *texObj, GLenum target, + struct gl_texture_object *texObj, GLenum internalFormat, struct gl_buffer_object *bufObj, - GLintptr offset, GLsizeiptr size, bool range, - bool dsa) + GLintptr offset, GLsizeiptr size, + const char *caller) { mesa_format format; - FLUSH_VERTICES(ctx, 0); + /* NOTE: ARB_texture_buffer_object has interactions with + * the compatibility profile that are not implemented. + */ + if (!(ctx->API == API_OPENGL_CORE && + ctx->Extensions.ARB_texture_buffer_object)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(ARB_texture_buffer_object is not" + " implemented for the compatibility profile)", caller); + return; + } format = _mesa_validate_texbuffer_format(ctx, internalFormat); if (format == MESA_FORMAT_NONE) { _mesa_error(ctx, GL_INVALID_ENUM, - "glTex%sBuffer%s(internalFormat 0x%x)", dsa ? "ture" : "", - range ? "Range" : "", internalFormat); + "%s(internalFormat 0x%x)", caller, internalFormat); return; } + FLUSH_VERTICES(ctx, 0); + _mesa_lock_texture(ctx, texObj); { _mesa_reference_buffer_object(ctx, &texObj->BufferObject, bufObj); @@ -5188,6 +5311,75 @@ _mesa_texture_buffer_range(struct gl_context *ctx, } +/** + * Make sure the texture buffer target is GL_TEXTURE_BUFFER. + * Return true if it is, and return false if it is not + * (and throw INVALID ENUM as dictated in the OpenGL 4.5 + * core spec, 02.02.2015, PDF page 245). + */ +static bool +check_texture_buffer_target(struct gl_context *ctx, GLenum target, + const char *caller) +{ + if (target != GL_TEXTURE_BUFFER_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(texture target is not GL_TEXTURE_BUFFER)", caller); + return false; + } + else + return true; +} + +/** + * Check for errors related to the texture buffer range. + * Return false if errors are found, true if none are found. + */ +static bool +check_texture_buffer_range(struct gl_context *ctx, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr size, + const char *caller) +{ + /* OpenGL 4.5 core spec (02.02.2015) says in Section 8.9 Buffer + * Textures (PDF page 245): + * "An INVALID_VALUE error is generated if offset is negative, if + * size is less than or equal to zero, or if offset + size is greater + * than the value of BUFFER_SIZE for the buffer bound to target." + */ + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d < 0)", caller, + (int) offset); + return false; + } + + if (size <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d <= 0)", caller, + (int) size); + return false; + } + + if (offset + size > bufObj->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(offset=%d + size=%d > buffer_size=%d)", caller, + (int) offset, (int) size, (int) bufObj->Size); + return false; + } + + /* OpenGL 4.5 core spec (02.02.2015) says in Section 8.9 Buffer + * Textures (PDF page 245): + * "An INVALID_VALUE error is generated if offset is not an integer + * multiple of the value of TEXTURE_BUFFER_OFFSET_ALIGNMENT." + */ + if (offset % ctx->Const.TextureBufferOffsetAlignment) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(invalid offset alignment)", caller); + return false; + } + + return true; +} + + /** GL_ARB_texture_buffer_object */ void GLAPIENTRY _mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer) @@ -5197,33 +5389,25 @@ _mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer) GET_CURRENT_CONTEXT(ctx); - /* Need to catch this before it gets to _mesa_get_current_tex_object */ - if (target != GL_TEXTURE_BUFFER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(target)"); - return; - } - - /* NOTE: ARB_texture_buffer_object has interactions with - * the compatibility profile that are not implemented. + /* Need to catch a bad target before it gets to + * _mesa_get_current_tex_object. */ - if (!(ctx->API == API_OPENGL_CORE && - ctx->Extensions.ARB_texture_buffer_object)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer"); + if (!check_texture_buffer_target(ctx, target, "glTexBuffer")) return; - } - bufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (!bufObj && buffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer); - return; - } + if (buffer) { + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glTexBuffer"); + if (!bufObj) + return; + } else + bufObj = NULL; texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; - _mesa_texture_buffer_range(ctx, texObj, target, internalFormat, bufObj, 0, - buffer ? -1 : 0, false, false); + _mesa_texture_buffer_range(ctx, texObj, internalFormat, bufObj, 0, + buffer ? -1 : 0, "glTexBuffer"); } @@ -5237,46 +5421,41 @@ _mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, GET_CURRENT_CONTEXT(ctx); - /* Need to catch this before it gets to _mesa_get_current_tex_object */ - if (target != GL_TEXTURE_BUFFER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexBufferRange(target)"); - return; - } - - if (!(ctx->API == API_OPENGL_CORE && - ctx->Extensions.ARB_texture_buffer_range)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange"); + /* Need to catch a bad target before it gets to + * _mesa_get_current_tex_object. + */ + if (!check_texture_buffer_target(ctx, target, "glTexBufferRange")) return; - } - bufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (bufObj) { - if (offset < 0 || - size <= 0 || - (offset + size) > bufObj->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexBufferRange"); + if (buffer) { + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glTexBufferRange"); + if (!bufObj) return; - } - if (offset % ctx->Const.TextureBufferOffsetAlignment) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexBufferRange(invalid offset alignment)"); + + if (!check_texture_buffer_range(ctx, bufObj, offset, size, + "glTexBufferRange")) return; - } - } else if (buffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange(buffer %u)", - buffer); - return; + } else { + + /* OpenGL 4.5 core spec (02.02.2015) says in Section 8.9 Buffer + * Textures (PDF page 254): + * "If buffer is zero, then any buffer object attached to the buffer + * texture is detached, the values offset and size are ignored and + * the state for offset and size for the buffer texture are reset to + * zero." + */ offset = 0; size = 0; + bufObj = NULL; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; - _mesa_texture_buffer_range(ctx, texObj, target, internalFormat, bufObj, - offset, size, true, false); + _mesa_texture_buffer_range(ctx, texObj, internalFormat, bufObj, + offset, size, "glTexBufferRange"); } void GLAPIENTRY @@ -5287,35 +5466,69 @@ _mesa_TextureBuffer(GLuint texture, GLenum internalFormat, GLuint buffer) GET_CURRENT_CONTEXT(ctx); - /* NOTE: ARB_texture_buffer_object has interactions with - * the compatibility profile that are not implemented. - */ - if (!(ctx->API == API_OPENGL_CORE && - ctx->Extensions.ARB_texture_buffer_object)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureBuffer"); + if (buffer) { + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glTextureBuffer"); + if (!bufObj) + return; + } else + bufObj = NULL; + + /* Get the texture object by Name. */ + texObj = _mesa_lookup_texture_err(ctx, texture, "glTextureBuffer"); + if (!texObj) return; - } - bufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (!bufObj && buffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureBuffer(buffer %u)", - buffer); + if (!check_texture_buffer_target(ctx, texObj->Target, "glTextureBuffer")) return; + + _mesa_texture_buffer_range(ctx, texObj, internalFormat, + bufObj, 0, buffer ? -1 : 0, "glTextureBuffer"); +} + +void GLAPIENTRY +_mesa_TextureBufferRange(GLuint texture, GLenum internalFormat, GLuint buffer, + GLintptr offset, GLsizeiptr size) +{ + struct gl_texture_object *texObj; + struct gl_buffer_object *bufObj; + + GET_CURRENT_CONTEXT(ctx); + + if (buffer) { + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glTextureBufferRange"); + if (!bufObj) + return; + + if (!check_texture_buffer_range(ctx, bufObj, offset, size, + "glTextureBufferRange")) + return; + + } else { + + /* OpenGL 4.5 core spec (02.02.2015) says in Section 8.9 Buffer + * Textures (PDF page 254): + * "If buffer is zero, then any buffer object attached to the buffer + * texture is detached, the values offset and size are ignored and + * the state for offset and size for the buffer texture are reset to + * zero." + */ + offset = 0; + size = 0; + bufObj = NULL; } /* Get the texture object by Name. */ - texObj = _mesa_lookup_texture_err(ctx, texture, - "glTextureBuffer(texture)"); + texObj = _mesa_lookup_texture_err(ctx, texture, "glTextureBufferRange"); if (!texObj) return; - if (texObj->Target != GL_TEXTURE_BUFFER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTextureBuffer(target)"); + if (!check_texture_buffer_target(ctx, texObj->Target, + "glTextureBufferRange")) return; - } - _mesa_texture_buffer_range(ctx, texObj, texObj->Target, internalFormat, - bufObj, 0, buffer ? -1 : 0, false, true); + _mesa_texture_buffer_range(ctx, texObj, internalFormat, + bufObj, offset, size, "glTextureBufferRange"); } static GLboolean diff --git a/mesalib/src/mesa/main/teximage.h b/mesalib/src/mesa/main/teximage.h index b7336bc6c..1eebaa8b6 100644 --- a/mesalib/src/mesa/main/teximage.h +++ b/mesalib/src/mesa/main/teximage.h @@ -181,13 +181,14 @@ _mesa_texture_sub_image(struct gl_context *ctx, GLuint dims, extern void _mesa_compressed_texture_sub_image(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj, + struct gl_texture_image *texImage, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, - const GLvoid *data, bool dsa); + const GLvoid *data); extern void _mesa_copy_texture_sub_image(struct gl_context *ctx, GLuint dims, @@ -195,7 +196,8 @@ _mesa_copy_texture_sub_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, - GLsizei width, GLsizei height, bool dsa); + GLsizei width, GLsizei height, + const char *caller); extern void _mesa_texture_image_multisample(struct gl_context *ctx, GLuint dims, @@ -208,11 +210,11 @@ _mesa_texture_image_multisample(struct gl_context *ctx, GLuint dims, extern void _mesa_texture_buffer_range(struct gl_context *ctx, - struct gl_texture_object *texObj, GLenum target, + struct gl_texture_object *texObj, GLenum internalFormat, struct gl_buffer_object *bufObj, - GLintptr offset, GLsizeiptr size, bool range, - bool dsa); + GLintptr offset, GLsizeiptr size, + const char *caller); /*@}*/ @@ -408,6 +410,10 @@ _mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, extern void GLAPIENTRY _mesa_TextureBuffer(GLuint texture, GLenum internalFormat, GLuint buffer); +extern void GLAPIENTRY +_mesa_TextureBufferRange(GLuint texture, GLenum internalFormat, GLuint buffer, + GLintptr offset, GLsizeiptr size); + extern void GLAPIENTRY _mesa_TexImage2DMultisample(GLenum target, GLsizei samples, diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c index a3e23ced5..ce678c864 100644 --- a/mesalib/src/mesa/main/transformfeedback.c +++ b/mesalib/src/mesa/main/transformfeedback.c @@ -762,7 +762,7 @@ _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count, /* Save the new names and the count */ for (i = 0; i < count; i++) { - shProg->TransformFeedback.VaryingNames[i] = _mesa_strdup(varyings[i]); + shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]); } shProg->TransformFeedback.NumVarying = count; diff --git a/mesalib/src/mesa/main/uniform_query.cpp b/mesalib/src/mesa/main/uniform_query.cpp index 9f82de952..2ab5528c3 100644 --- a/mesalib/src/mesa/main/uniform_query.cpp +++ b/mesalib/src/mesa/main/uniform_query.cpp @@ -260,8 +260,8 @@ validate_uniform_parameters(struct gl_context *ctx, if (uni->array_elements == 0) { if (count > 1) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(count > 1 for non-array, location=%d)", - caller, location); + "%s(count = %u for non-array \"%s\"@%d)", + caller, count, uni->name, location); return NULL; } @@ -601,6 +601,46 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, } } + +/** + * Return printable string for a given GLSL_TYPE_x + */ +static const char * +glsl_type_name(enum glsl_base_type type) +{ + switch (type) { + case GLSL_TYPE_UINT: + return "uint"; + case GLSL_TYPE_INT: + return "int"; + case GLSL_TYPE_FLOAT: + return "float"; + case GLSL_TYPE_DOUBLE: + return "double"; + case GLSL_TYPE_BOOL: + return "bool"; + case GLSL_TYPE_SAMPLER: + return "sampler"; + case GLSL_TYPE_IMAGE: + return "image"; + case GLSL_TYPE_ATOMIC_UINT: + return "atomic_uint"; + case GLSL_TYPE_STRUCT: + return "struct"; + case GLSL_TYPE_INTERFACE: + return "interface"; + case GLSL_TYPE_ARRAY: + return "array"; + case GLSL_TYPE_VOID: + return "void"; + case GLSL_TYPE_ERROR: + return "error"; + default: + return "other"; + } +} + + /** * Called via glUniform*() functions. */ @@ -620,11 +660,28 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, if (uni == NULL) return; + if (uni->type->is_matrix()) { + /* Can't set matrix uniforms (like mat4) with glUniform */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(uniform \"%s\"@%d is matrix)", + src_components, uni->name, location); + return; + } + /* Verify that the types are compatible. */ const unsigned components = uni->type->is_sampler() ? 1 : uni->type->vector_elements; + if (components != src_components) { + /* glUniformN() must match float/vecN type */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(\"%s\"@%u has %u components, not %u)", + src_components, uni->name, location, + components, src_components); + return; + } + bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: @@ -639,8 +696,12 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, break; } - if (uni->type->is_matrix() || components != src_components || !match) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); + if (!match) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(\"%s\"@%d is %s, not %s)", + src_components, uni->name, location, + glsl_type_name(uni->type->base_type), + glsl_type_name(basicType)); return; } |