From 683155917770af9e63a938bc450df25d1904d567 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 8 May 2014 00:18:25 +0200 Subject: xserver xcb-proto mesa pixman xkeyboard-config git update 7 May 2014 xserver commit a5b9757142a2ab471ca26651dce9cc5f5e351f3d libxcb commit d978a4f69b30b630f28d07f1003cf290284d24d8 libxcb/xcb-proto commit 389889e2f95af19e7fc7ac89e7faeb2f28652415 xkeyboard-config commit 3e54f31b1f118f00c240f59d72d7ddb685c6db79 libX11 commit 8be4610939b833587954957f5963eb4191b43d19 libXdmcp commit 089081dca4ba3598c6f9bf401c029378943b5854 libXext commit 11aad96bd689d54156064d2e81213dc827a689d1 libfontenc commit 0037a42107b952c9d903719615747e760e4e7247 libXinerama commit edd95182b26eb5d576d4878c559e0f17dddaa909 libXau commit 1e4635be11154dd8262f37b379511bd627defa2a xkbcomp commit d4e02a09258063c6d024c3ccd42d6b22212e6e18 pixman commit 91f32ce961bc85f98b3372b95681ad8918d24b18 xextproto commit 66afec3f49e8eb0d4c2e9af7088fc3116d4bafd7 randrproto commit a4a6694c059d74247c16527eef4a0ec9f56bbef6 glproto commit f84853d97d5749308992412a215fa518b6536eb3 mkfontscale commit 399db42a151687f1181ae23d28a76d31125a2853 xwininfo commit ba0d1b0da21d2dbdd81098ed5778f3792b472e13 libXft commit 4acfdaf95adb0a05c2a25550bdde036c865902f4 libXmu commit 22d9c590901e121936f50dee97dc60c4f7defb63 libxtrans commit a57a7f62242e1ea972b81414741729bf3dbae0a4 fontconfig commit 81664fe54f117e4781fda5a30429b51858302e91 mesa commit 9ced3fc649ec04710a5f5c855bfb582b898cff83 --- mesalib/src/mesa/main/bufferobj.c | 923 ++++++++++++++++++++++++++- mesalib/src/mesa/main/bufferobj.h | 21 + mesalib/src/mesa/main/config.h | 8 + mesalib/src/mesa/main/dd.h | 6 +- mesalib/src/mesa/main/dlist.c | 920 +++++++++++++++++++++++++- mesalib/src/mesa/main/errors.c | 6 + mesalib/src/mesa/main/errors.h | 3 + mesalib/src/mesa/main/extensions.c | 7 +- mesalib/src/mesa/main/ff_fragment_shader.cpp | 2 +- mesalib/src/mesa/main/format_unpack.c | 105 +++ mesalib/src/mesa/main/format_unpack.h | 10 +- mesalib/src/mesa/main/get.c | 2 +- mesalib/src/mesa/main/get_hash_params.py | 8 +- mesalib/src/mesa/main/hash.c | 89 ++- mesalib/src/mesa/main/hash.h | 9 + mesalib/src/mesa/main/imports.h | 4 +- mesalib/src/mesa/main/mtypes.h | 38 +- mesalib/src/mesa/main/performance_monitor.c | 614 ++++++++++++++++++ mesalib/src/mesa/main/performance_monitor.h | 43 +- mesalib/src/mesa/main/pipelineobj.c | 13 +- mesalib/src/mesa/main/pipelineobj.h | 4 + mesalib/src/mesa/main/samplerobj.c | 121 ++++ mesalib/src/mesa/main/samplerobj.h | 2 + mesalib/src/mesa/main/shader_query.cpp | 71 ++- mesalib/src/mesa/main/shaderapi.c | 152 +---- mesalib/src/mesa/main/shaderimage.c | 143 +++++ mesalib/src/mesa/main/shaderimage.h | 3 + mesalib/src/mesa/main/texgetimage.c | 18 +- mesalib/src/mesa/main/texobj.c | 175 ++++- mesalib/src/mesa/main/texobj.h | 13 + mesalib/src/mesa/main/texstate.c | 3 + mesalib/src/mesa/main/texstore.c | 174 +++-- mesalib/src/mesa/main/transformfeedback.c | 10 +- mesalib/src/mesa/main/transformfeedback.h | 14 + mesalib/src/mesa/main/uniforms.h | 2 +- mesalib/src/mesa/main/varray.c | 128 +++- mesalib/src/mesa/main/varray.h | 20 + 37 files changed, 3516 insertions(+), 368 deletions(-) (limited to 'mesalib/src/mesa/main') diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 36acd64ce..7b1bba097 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -975,6 +975,78 @@ _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) } +struct gl_buffer_object * +_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer) +{ + return (struct gl_buffer_object *) + _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer); +} + + +void +_mesa_begin_bufferobj_lookups(struct gl_context *ctx) +{ + _mesa_HashLockMutex(ctx->Shared->BufferObjects); +} + + +void +_mesa_end_bufferobj_lookups(struct gl_context *ctx) +{ + _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); +} + + +/** + * Look up a buffer object for a multi-bind function. + * + * Unlike _mesa_lookup_bufferobj(), this function also takes care + * of generating an error if the buffer ID is not zero or the name + * of an existing buffer object. + * + * If the buffer ID refers to an existing buffer object, a pointer + * to the buffer object is returned. If the ID is zero, a pointer + * to the shared NullBufferObj is returned. If the ID is not zero + * and does not refer to a valid buffer object, this function + * returns NULL. + * + * This function assumes that the caller has already locked the + * hash table mutex by calling _mesa_begin_bufferobj_lookups(). + */ +struct gl_buffer_object * +_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx, + const GLuint *buffers, + GLuint index, const char *caller) +{ + struct gl_buffer_object *bufObj; + + if (buffers[index] != 0) { + bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]); + + /* The multi-bind functions don't create the buffer objects + when they don't exist. */ + if (bufObj == &DummyBufferObject) + bufObj = NULL; + } else + bufObj = ctx->Shared->NullBufferObj; + + if (!bufObj) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if any value + * in is not zero or the name of an existing + * buffer object (per binding)." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffers[%u]=%u is not zero or the name " + "of an existing buffer object)", + caller, index, buffers[index]); + } + + return bufObj; +} + + /** * If *ptr points to obj, set ptr = the Null/default buffer object. * This is a helper for buffer object deletion. @@ -2529,17 +2601,45 @@ _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, } } +/** + * Binds a buffer object to a uniform buffer binding point. + * + * The caller is responsible for flushing vertices and updating + * NewDriverState. + */ static void set_ubo_binding(struct gl_context *ctx, - int index, - struct gl_buffer_object *bufObj, - GLintptr offset, - GLsizeiptr size, - GLboolean autoSize) + struct gl_uniform_buffer_binding *binding, + struct gl_buffer_object *bufObj, + GLintptr offset, + GLsizeiptr size, + GLboolean autoSize) +{ + _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); + + binding->Offset = offset; + binding->Size = size; + binding->AutomaticSize = autoSize; +} + +/** + * Binds a buffer object to a uniform buffer binding point. + * + * Unlike set_ubo_binding(), this function also flushes vertices + * and updates NewDriverState. It also checks if the binding + * has actually changed before updating it. + */ +static void +bind_uniform_buffer(struct gl_context *ctx, + GLuint index, + struct gl_buffer_object *bufObj, + GLintptr offset, + GLsizeiptr size, + GLboolean autoSize) { - struct gl_uniform_buffer_binding *binding; + struct gl_uniform_buffer_binding *binding = + &ctx->UniformBufferBindings[index]; - binding = &ctx->UniformBufferBindings[index]; if (binding->BufferObject == bufObj && binding->Offset == offset && binding->Size == size && @@ -2550,10 +2650,7 @@ set_ubo_binding(struct gl_context *ctx, FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; - _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); - binding->Offset = offset; - binding->Size = size; - binding->AutomaticSize = autoSize; + set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize); } /** @@ -2588,7 +2685,7 @@ bind_buffer_range_uniform_buffer(struct gl_context *ctx, } _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); - set_ubo_binding(ctx, index, bufObj, offset, size, GL_FALSE); + bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE); } @@ -2607,19 +2704,52 @@ bind_buffer_base_uniform_buffer(struct gl_context *ctx, } _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); + if (bufObj == ctx->Shared->NullBufferObj) - set_ubo_binding(ctx, index, bufObj, -1, -1, GL_TRUE); + bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); else - set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE); + bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); } +/** + * Binds a buffer object to an atomic buffer binding point. + * + * The caller is responsible for validating the offset, + * flushing the vertices and updating NewDriverState. + */ static void set_atomic_buffer_binding(struct gl_context *ctx, - unsigned index, + struct gl_atomic_buffer_binding *binding, struct gl_buffer_object *bufObj, GLintptr offset, - GLsizeiptr size, - const char *name) + GLsizeiptr size) +{ + _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); + + if (bufObj == ctx->Shared->NullBufferObj) { + binding->Offset = -1; + binding->Size = -1; + } else { + binding->Offset = offset; + binding->Size = size; + } +} + +/** + * Binds a buffer object to an atomic buffer binding point. + * + * Unlike set_atomic_buffer_binding(), this function also validates the + * index and offset, flushes vertices, and updates NewDriverState. + * It also checks if the binding has actually changing before + * updating it. + */ +static void +bind_atomic_buffer(struct gl_context *ctx, + unsigned index, + struct gl_buffer_object *bufObj, + GLintptr offset, + GLsizeiptr size, + const char *name) { struct gl_atomic_buffer_binding *binding; @@ -2647,15 +2777,704 @@ set_atomic_buffer_binding(struct gl_context *ctx, FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; - _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); + set_atomic_buffer_binding(ctx, binding, bufObj, offset, size); +} - if (bufObj == ctx->Shared->NullBufferObj) { - binding->Offset = -1; - binding->Size = -1; - } else { - binding->Offset = offset; - binding->Size = size; +static inline bool +bind_buffers_check_offset_and_size(struct gl_context *ctx, + GLuint index, + const GLintptr *offsets, + const GLsizeiptr *sizes) +{ + if (offsets[index] < 0) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated by BindBuffersRange if any + * value in is less than zero (per binding)." + */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(offsets[%u]=%lld < 0)", + index, (long long int) offsets[index]); + return false; + } + + if (sizes[index] <= 0) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated by BindBuffersRange if any + * value in is less than or equal to zero (per binding)." + */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(sizes[%u]=%lld <= 0)", + index, (long long int) sizes[index]); + return false; + } + + return true; +} + +static bool +error_check_bind_uniform_buffers(struct gl_context *ctx, + GLuint first, GLsizei count, + const char *caller) +{ + if (!ctx->Extensions.ARB_uniform_buffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(target=GL_UNIFORM_BUFFER)", caller); + return false; + } + + /* The ARB_multi_bind_spec says: + * + * "An INVALID_OPERATION error is generated if + is + * greater than the number of target-specific indexed binding points, + * as described in section 6.7.1." + */ + if (first + count > ctx->Const.MaxUniformBufferBindings) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(first=%u + count=%d > the value of " + "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)", + caller, first, count, + ctx->Const.MaxUniformBufferBindings); + return false; + } + + return true; +} + +/** + * Unbind all uniform buffers in the range + * through +-1 + */ +static void +unbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count) +{ + struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj; + GLuint i; + + for (i = 0; i < count; i++) + set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i], + bufObj, -1, -1, GL_TRUE); +} + +static void +bind_uniform_buffers_base(struct gl_context *ctx, GLuint first, GLsizei count, + const GLuint *buffers) +{ + GLuint i; + + if (!error_check_bind_uniform_buffers(ctx, first, count, "glBindBuffersBase")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state." + */ + unbind_uniform_buffers(ctx, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_uniform_buffer_binding *binding = + &ctx->UniformBufferBindings[first + i]; + struct gl_buffer_object *bufObj; + + if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) + bufObj = binding->BufferObject; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersBase"); + + if (bufObj) { + if (bufObj == ctx->Shared->NullBufferObj) + set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE); + else + set_ubo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE); + } + } + + _mesa_end_bufferobj_lookups(ctx); +} + +static void +bind_uniform_buffers_range(struct gl_context *ctx, GLuint first, GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, const GLsizeiptr *sizes) +{ + GLuint i; + + if (!error_check_bind_uniform_buffers(ctx, first, count, + "glBindBuffersRange")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state. + * In this case, the offsets and sizes associated with the + * binding points are set to default values, ignoring + * and ." + */ + unbind_uniform_buffers(ctx, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_uniform_buffer_binding *binding = + &ctx->UniformBufferBindings[first + i]; + struct gl_buffer_object *bufObj; + + if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) + continue; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated by BindBuffersRange if any + * pair of values in and does not respectively + * satisfy the constraints described for those parameters for the + * specified target, as described in section 6.7.1 (per binding)." + * + * Section 6.7.1 refers to table 6.5, which says: + * + * "┌───────────────────────────────────────────────────────────────┐ + * │ Uniform buffer array bindings (see sec. 7.6) │ + * ├─────────────────────┬─────────────────────────────────────────┤ + * │ ... │ ... │ + * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │ + * │ │ OFFSET_ALIGNMENT │ + * │ ... │ ... │ + * │ size restriction │ none │ + * └─────────────────────┴─────────────────────────────────────────┘" + */ + if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(offsets[%u]=%lld is misaligned; " + "it must be a multiple of the value of " + "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when " + "target=GL_UNIFORM_BUFFER)", + i, (long long int) offsets[i], + ctx->Const.UniformBufferOffsetAlignment); + continue; + } + + if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) + bufObj = binding->BufferObject; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersRange"); + + if (bufObj) { + if (bufObj == ctx->Shared->NullBufferObj) + set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE); + else + set_ubo_binding(ctx, binding, bufObj, + offsets[i], sizes[i], GL_FALSE); + } + } + + _mesa_end_bufferobj_lookups(ctx); +} + +static bool +error_check_bind_xfb_buffers(struct gl_context *ctx, + struct gl_transform_feedback_object *tfObj, + GLuint first, GLsizei count, const char *caller) +{ + if (!ctx->Extensions.EXT_transform_feedback) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller); + return false; } + + /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says: + * + * "An INVALID_OPERATION error is generated : + * + * ... + * • by BindBufferRange or BindBufferBase if target is TRANSFORM_- + * FEEDBACK_BUFFER and transform feedback is currently active." + * + * We assume that this is also meant to apply to BindBuffersRange + * and BindBuffersBase. + */ + if (tfObj->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(Changing transform feedback buffers while " + "transform feedback is active)", caller); + return false; + } + + /* The ARB_multi_bind_spec says: + * + * "An INVALID_OPERATION error is generated if + is + * greater than the number of target-specific indexed binding points, + * as described in section 6.7.1." + */ + if (first + count > ctx->Const.MaxTransformFeedbackBuffers) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(first=%u + count=%d > the value of " + "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)", + caller, first, count, + ctx->Const.MaxTransformFeedbackBuffers); + return false; + } + + return true; +} + +/** + * Unbind all transform feedback buffers in the range + * through +-1 + */ +static void +unbind_xfb_buffers(struct gl_context *ctx, + struct gl_transform_feedback_object *tfObj, + GLuint first, GLsizei count) +{ + struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; + GLuint i; + + for (i = 0; i < count; i++) + _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, + bufObj, 0, 0); +} + +static void +bind_xfb_buffers_base(struct gl_context *ctx, + GLuint first, GLsizei count, + const GLuint *buffers) +{ + struct gl_transform_feedback_object *tfObj = + ctx->TransformFeedback.CurrentObject; + GLuint i; + + if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, + "glBindBuffersBase")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state." + */ + unbind_xfb_buffers(ctx, tfObj, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_buffer_object * const boundBufObj = tfObj->Buffers[first + i]; + struct gl_buffer_object *bufObj; + + if (boundBufObj && boundBufObj->Name == buffers[i]) + bufObj = boundBufObj; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersBase"); + + if (bufObj) + _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, + bufObj, 0, 0); + } + + _mesa_end_bufferobj_lookups(ctx); +} + +static void +bind_xfb_buffers_range(struct gl_context *ctx, + GLuint first, GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, + const GLsizeiptr *sizes) +{ + struct gl_transform_feedback_object *tfObj = + ctx->TransformFeedback.CurrentObject; + GLuint i; + + if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, + "glBindBuffersRange")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state. + * In this case, the offsets and sizes associated with the + * binding points are set to default values, ignoring + * and ." + */ + unbind_xfb_buffers(ctx, tfObj, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + const GLuint index = first + i; + struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index]; + struct gl_buffer_object *bufObj; + + if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) + continue; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated by BindBuffersRange if any + * pair of values in and does not respectively + * satisfy the constraints described for those parameters for the + * specified target, as described in section 6.7.1 (per binding)." + * + * Section 6.7.1 refers to table 6.5, which says: + * + * "┌───────────────────────────────────────────────────────────────┐ + * │ Transform feedback array bindings (see sec. 13.2.2) │ + * ├───────────────────────┬───────────────────────────────────────┤ + * │ ... │ ... │ + * │ offset restriction │ multiple of 4 │ + * │ ... │ ... │ + * │ size restriction │ multiple of 4 │ + * └───────────────────────┴───────────────────────────────────────┘" + */ + if (offsets[i] & 0x3) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(offsets[%u]=%lld is misaligned; " + "it must be a multiple of 4 when " + "target=GL_TRANSFORM_FEEDBACK_BUFFER)", + i, (long long int) offsets[i]); + continue; + } + + if (sizes[i] & 0x3) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(sizes[%u]=%lld is misaligned; " + "it must be a multiple of 4 when " + "target=GL_TRANSFORM_FEEDBACK_BUFFER)", + i, (long long int) sizes[i]); + continue; + } + + if (boundBufObj && boundBufObj->Name == buffers[i]) + bufObj = boundBufObj; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersRange"); + + if (bufObj) + _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj, + offsets[i], sizes[i]); + } + + _mesa_end_bufferobj_lookups(ctx); +} + +static bool +error_check_bind_atomic_buffers(struct gl_context *ctx, + GLuint first, GLsizei count, + const char *caller) +{ + if (!ctx->Extensions.ARB_shader_atomic_counters) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller); + return false; + } + + /* The ARB_multi_bind_spec says: + * + * "An INVALID_OPERATION error is generated if + is + * greater than the number of target-specific indexed binding points, + * as described in section 6.7.1." + */ + if (first + count > ctx->Const.MaxAtomicBufferBindings) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(first=%u + count=%d > the value of " + "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)", + caller, first, count, ctx->Const.MaxAtomicBufferBindings); + return false; + } + + return true; +} + +/** + * Unbind all atomic counter buffers in the range + * through +-1 + */ +static void +unbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count) +{ + struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; + GLuint i; + + for (i = 0; i < count; i++) + set_atomic_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i], + bufObj, -1, -1); +} + +static void +bind_atomic_buffers_base(struct gl_context *ctx, + GLuint first, + GLsizei count, + const GLuint *buffers) +{ + GLuint i; + + if (!error_check_bind_atomic_buffers(ctx, first, count, + "glBindBuffersBase")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state." + */ + unbind_atomic_buffers(ctx, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_atomic_buffer_binding *binding = + &ctx->AtomicBufferBindings[first + i]; + struct gl_buffer_object *bufObj; + + if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) + bufObj = binding->BufferObject; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersBase"); + + if (bufObj) + set_atomic_buffer_binding(ctx, binding, bufObj, 0, 0); + } + + _mesa_end_bufferobj_lookups(ctx); +} + +static void +bind_atomic_buffers_range(struct gl_context *ctx, + GLuint first, + GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, + const GLsizeiptr *sizes) +{ + GLuint i; + + if (!error_check_bind_atomic_buffers(ctx, first, count, + "glBindBuffersRange")) + return; + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; + + if (!buffers) { + /* The ARB_multi_bind spec says: + * + * "If is NULL, all bindings from through + * +-1 are reset to their unbound (zero) state. + * In this case, the offsets and sizes associated with the + * binding points are set to default values, ignoring + * and ." + */ + unbind_atomic_buffers(ctx, first, count); + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by a + * command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require a + * first pass to scan the entire list of bound objects for errors + * and then a second pass to actually perform the bindings. + * Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding point + * is not updated and an error will be generated. However, other + * binding points in the same command will be updated if their + * parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_atomic_buffer_binding *binding = + &ctx->AtomicBufferBindings[first + i]; + struct gl_buffer_object *bufObj; + + if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) + continue; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated by BindBuffersRange if any + * pair of values in and does not respectively + * satisfy the constraints described for those parameters for the + * specified target, as described in section 6.7.1 (per binding)." + * + * Section 6.7.1 refers to table 6.5, which says: + * + * "┌───────────────────────────────────────────────────────────────┐ + * │ Atomic counter array bindings (see sec. 7.7.2) │ + * ├───────────────────────┬───────────────────────────────────────┤ + * │ ... │ ... │ + * │ offset restriction │ multiple of 4 │ + * │ ... │ ... │ + * │ size restriction │ none │ + * └───────────────────────┴───────────────────────────────────────┘" + */ + if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindBuffersRange(offsets[%u]=%lld is misaligned; " + "it must be a multiple of %d when " + "target=GL_ATOMIC_COUNTER_BUFFER)", + i, (long long int) offsets[i], ATOMIC_COUNTER_SIZE); + continue; + } + + if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) + bufObj = binding->BufferObject; + else + bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindBuffersRange"); + + if (bufObj) + set_atomic_buffer_binding(ctx, binding, bufObj, offsets[i], sizes[i]); + } + + _mesa_end_bufferobj_lookups(ctx); } void GLAPIENTRY @@ -2697,8 +3516,8 @@ _mesa_BindBufferRange(GLenum target, GLuint index, bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); return; case GL_ATOMIC_COUNTER_BUFFER: - set_atomic_buffer_binding(ctx, index, bufObj, offset, size, - "glBindBufferRange"); + bind_atomic_buffer(ctx, index, bufObj, offset, size, + "glBindBufferRange"); return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); @@ -2761,8 +3580,8 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) bind_buffer_base_uniform_buffer(ctx, index, bufObj); return; case GL_ATOMIC_COUNTER_BUFFER: - set_atomic_buffer_binding(ctx, index, bufObj, 0, 0, - "glBindBufferBase"); + bind_atomic_buffer(ctx, index, bufObj, 0, 0, + "glBindBufferBase"); return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); @@ -2770,6 +3589,54 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) } } +void GLAPIENTRY +_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, const GLsizeiptr *sizes) +{ + GET_CURRENT_CONTEXT(ctx); + + switch (target) { + case GL_TRANSFORM_FEEDBACK_BUFFER: + bind_xfb_buffers_range(ctx, first, count, buffers, offsets, sizes); + return; + case GL_UNIFORM_BUFFER: + bind_uniform_buffers_range(ctx, first, count, buffers, offsets, sizes); + return; + case GL_ATOMIC_COUNTER_BUFFER: + bind_atomic_buffers_range(ctx, first, count, buffers, + offsets, sizes); + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)", + _mesa_lookup_enum_by_nr(target)); + break; + } +} + +void GLAPIENTRY +_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count, + const GLuint *buffers) +{ + GET_CURRENT_CONTEXT(ctx); + + switch (target) { + case GL_TRANSFORM_FEEDBACK_BUFFER: + bind_xfb_buffers_base(ctx, first, count, buffers); + return; + case GL_UNIFORM_BUFFER: + bind_uniform_buffers_base(ctx, first, count, buffers); + return; + case GL_ATOMIC_COUNTER_BUFFER: + bind_atomic_buffers_base(ctx, first, count, buffers); + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)", + _mesa_lookup_enum_by_nr(target)); + break; + } +} + void GLAPIENTRY _mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr length) diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h index c08c4fdf2..0779605c0 100644 --- a/mesalib/src/mesa/main/bufferobj.h +++ b/mesalib/src/mesa/main/bufferobj.h @@ -86,6 +86,20 @@ _mesa_update_default_objects_buffer_objects(struct gl_context *ctx); extern struct gl_buffer_object * _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 void +_mesa_begin_bufferobj_lookups(struct gl_context *ctx); + +extern void +_mesa_end_bufferobj_lookups(struct gl_context *ctx); + +extern struct gl_buffer_object * +_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx, + const GLuint *buffers, + GLuint index, const char *caller); + extern void _mesa_initialize_buffer_object(struct gl_context *ctx, struct gl_buffer_object *obj, @@ -209,6 +223,13 @@ _mesa_BindBufferRange(GLenum target, GLuint index, void GLAPIENTRY _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer); +void GLAPIENTRY +_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, const GLsizeiptr *sizes); +void GLAPIENTRY +_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count, + const GLuint *buffers); void GLAPIENTRY _mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr length); diff --git a/mesalib/src/mesa/main/config.h b/mesalib/src/mesa/main/config.h index 30da5d422..c96502a7f 100644 --- a/mesalib/src/mesa/main/config.h +++ b/mesalib/src/mesa/main/config.h @@ -281,6 +281,14 @@ #define MAX_VERTEX_STREAMS 4 /*@}*/ +/** For GL_INTEL_performance_query */ +/*@{*/ +#define MAX_PERFQUERY_QUERY_NAME_LENGTH 256 +#define MAX_PERFQUERY_COUNTER_NAME_LENGTH 256 +#define MAX_PERFQUERY_COUNTER_DESC_LENGTH 1024 +#define PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS 0 +/*@}*/ + /* * Color channel component order * diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index 971524135..633ea2c3a 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -314,10 +314,10 @@ struct dd_function_table { /*@{*/ /** - * Called by glBindTexture(). + * Called by glBindTexture() and glBindTextures(). */ - void (*BindTexture)( struct gl_context *ctx, GLenum target, - struct gl_texture_object *tObj ); + void (*BindTexture)( struct gl_context *ctx, GLuint texUnit, + GLenum target, struct gl_texture_object *tObj ); /** * Called to allocate a new texture object. Drivers will usually diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c index d431fd221..5874b99f0 100644 --- a/mesalib/src/mesa/main/dlist.c +++ b/mesalib/src/mesa/main/dlist.c @@ -364,6 +364,42 @@ typedef enum OPCODE_UNIFORM_3UIV, OPCODE_UNIFORM_4UIV, + /* OpenGL 4.2 / GL_ARB_separate_shader_objects */ + OPCODE_USE_PROGRAM_STAGES, + OPCODE_PROGRAM_UNIFORM_1F, + OPCODE_PROGRAM_UNIFORM_2F, + OPCODE_PROGRAM_UNIFORM_3F, + OPCODE_PROGRAM_UNIFORM_4F, + OPCODE_PROGRAM_UNIFORM_1FV, + OPCODE_PROGRAM_UNIFORM_2FV, + OPCODE_PROGRAM_UNIFORM_3FV, + OPCODE_PROGRAM_UNIFORM_4FV, + OPCODE_PROGRAM_UNIFORM_1I, + OPCODE_PROGRAM_UNIFORM_2I, + OPCODE_PROGRAM_UNIFORM_3I, + OPCODE_PROGRAM_UNIFORM_4I, + OPCODE_PROGRAM_UNIFORM_1IV, + OPCODE_PROGRAM_UNIFORM_2IV, + OPCODE_PROGRAM_UNIFORM_3IV, + OPCODE_PROGRAM_UNIFORM_4IV, + OPCODE_PROGRAM_UNIFORM_1UI, + OPCODE_PROGRAM_UNIFORM_2UI, + OPCODE_PROGRAM_UNIFORM_3UI, + OPCODE_PROGRAM_UNIFORM_4UI, + OPCODE_PROGRAM_UNIFORM_1UIV, + OPCODE_PROGRAM_UNIFORM_2UIV, + OPCODE_PROGRAM_UNIFORM_3UIV, + OPCODE_PROGRAM_UNIFORM_4UIV, + OPCODE_PROGRAM_UNIFORM_MATRIX22F, + OPCODE_PROGRAM_UNIFORM_MATRIX33F, + OPCODE_PROGRAM_UNIFORM_MATRIX44F, + OPCODE_PROGRAM_UNIFORM_MATRIX23F, + OPCODE_PROGRAM_UNIFORM_MATRIX32F, + OPCODE_PROGRAM_UNIFORM_MATRIX24F, + OPCODE_PROGRAM_UNIFORM_MATRIX42F, + OPCODE_PROGRAM_UNIFORM_MATRIX34F, + OPCODE_PROGRAM_UNIFORM_MATRIX43F, + /* GL_ARB_color_buffer_float */ OPCODE_CLAMP_COLOR, @@ -407,10 +443,6 @@ typedef enum OPCODE_TEXPARAMETER_I, OPCODE_TEXPARAMETER_UI, - /* GL_EXT_separate_shader_objects */ - OPCODE_ACTIVE_PROGRAM_EXT, - OPCODE_USE_SHADER_PROGRAM_EXT, - /* GL_ARB_instanced_arrays */ OPCODE_VERTEX_ATTRIB_DIVISOR, @@ -765,6 +797,33 @@ _mesa_delete_list(struct gl_context *ctx, struct gl_display_list *dlist) free(get_pointer(&n[4])); n += InstSize[n[0].opcode]; break; + case OPCODE_PROGRAM_UNIFORM_1FV: + case OPCODE_PROGRAM_UNIFORM_2FV: + case OPCODE_PROGRAM_UNIFORM_3FV: + case OPCODE_PROGRAM_UNIFORM_4FV: + case OPCODE_PROGRAM_UNIFORM_1IV: + case OPCODE_PROGRAM_UNIFORM_2IV: + case OPCODE_PROGRAM_UNIFORM_3IV: + case OPCODE_PROGRAM_UNIFORM_4IV: + case OPCODE_PROGRAM_UNIFORM_1UIV: + case OPCODE_PROGRAM_UNIFORM_2UIV: + case OPCODE_PROGRAM_UNIFORM_3UIV: + case OPCODE_PROGRAM_UNIFORM_4UIV: + free(get_pointer(&n[4])); + n += InstSize[n[0].opcode]; + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX22F: + case OPCODE_PROGRAM_UNIFORM_MATRIX33F: + case OPCODE_PROGRAM_UNIFORM_MATRIX44F: + case OPCODE_PROGRAM_UNIFORM_MATRIX24F: + case OPCODE_PROGRAM_UNIFORM_MATRIX42F: + case OPCODE_PROGRAM_UNIFORM_MATRIX23F: + case OPCODE_PROGRAM_UNIFORM_MATRIX32F: + case OPCODE_PROGRAM_UNIFORM_MATRIX34F: + case OPCODE_PROGRAM_UNIFORM_MATRIX43F: + free(get_pointer(&n[5])); + n += InstSize[n[0].opcode]; + break; case OPCODE_PIXEL_MAP: free(get_pointer(&n[3])); n += InstSize[n[0].opcode]; @@ -6510,49 +6569,689 @@ save_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, } static void GLAPIENTRY -save_ClampColorARB(GLenum target, GLenum clamp) +save_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) { GET_CURRENT_CONTEXT(ctx); Node *n; ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); - n = alloc_instruction(ctx, OPCODE_CLAMP_COLOR, 2); + n = alloc_instruction(ctx, OPCODE_USE_PROGRAM_STAGES, 3); if (n) { - n[1].e = target; - n[2].e = clamp; + n[1].ui = pipeline; + n[2].ui = stages; + n[3].ui = program; } if (ctx->ExecuteFlag) { - CALL_ClampColor(ctx->Exec, (target, clamp)); + CALL_UseProgramStages(ctx->Exec, (pipeline, stages, program)); + } +} + +static void GLAPIENTRY +save_ProgramUniform1f(GLuint program, GLint location, GLfloat x) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1F, 3); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].f = x; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform1f(ctx->Exec, (program, location, x)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2f(GLuint program, GLint location, GLfloat x, GLfloat y) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2F, 4); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].f = x; + n[4].f = y; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2f(ctx->Exec, (program, location, x, y)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3f(GLuint program, GLint location, + GLfloat x, GLfloat y, GLfloat z) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3F, 5); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].f = x; + n[4].f = y; + n[5].f = z; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3f(ctx->Exec, (program, location, x, y, z)); + } +} + +static void GLAPIENTRY +save_ProgramUniform4f(GLuint program, GLint location, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4F, 6); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].f = x; + n[4].f = y; + n[5].f = z; + n[6].f = w; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform4f(ctx->Exec, (program, location, x, y, z, w)); + } +} + +static void GLAPIENTRY +save_ProgramUniform1fv(GLuint program, GLint location, GLsizei count, + const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1FV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform1fv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2fv(GLuint program, GLint location, GLsizei count, + const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2FV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2fv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3fv(GLuint program, GLint location, GLsizei count, + const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3FV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3fv(ctx->Exec, (program, location, count, v)); } } static void GLAPIENTRY -save_UseShaderProgramEXT(GLenum type, GLuint program) +save_ProgramUniform4fv(GLuint program, GLint location, GLsizei count, + const GLfloat *v) { GET_CURRENT_CONTEXT(ctx); Node *n; ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); - n = alloc_instruction(ctx, OPCODE_USE_SHADER_PROGRAM_EXT, 2); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4FV, 3 + POINTER_DWORDS); if (n) { - n[1].ui = type; - n[2].ui = program; + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLfloat))); } if (ctx->ExecuteFlag) { - CALL_UseShaderProgramEXT(ctx->Exec, (type, program)); + CALL_ProgramUniform4fv(ctx->Exec, (program, location, count, v)); } } static void GLAPIENTRY -save_ActiveProgramEXT(GLuint program) +save_ProgramUniform1i(GLuint program, GLint location, GLint x) { GET_CURRENT_CONTEXT(ctx); Node *n; ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); - n = alloc_instruction(ctx, OPCODE_ACTIVE_PROGRAM_EXT, 1); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1I, 3); if (n) { n[1].ui = program; + n[2].i = location; + n[3].i = x; } if (ctx->ExecuteFlag) { - CALL_ActiveProgramEXT(ctx->Exec, (program)); + CALL_ProgramUniform1i(ctx->Exec, (program, location, x)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2i(GLuint program, GLint location, GLint x, GLint y) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2I, 4); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = x; + n[4].i = y; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2i(ctx->Exec, (program, location, x, y)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3i(GLuint program, GLint location, + GLint x, GLint y, GLint z) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3I, 5); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = x; + n[4].i = y; + n[5].i = z; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3i(ctx->Exec, (program, location, x, y, z)); + } +} + +static void GLAPIENTRY +save_ProgramUniform4i(GLuint program, GLint location, + GLint x, GLint y, GLint z, GLint w) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4I, 6); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = x; + n[4].i = y; + n[5].i = z; + n[6].i = w; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform4i(ctx->Exec, (program, location, x, y, z, w)); + } +} + +static void GLAPIENTRY +save_ProgramUniform1iv(GLuint program, GLint location, GLsizei count, + const GLint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1IV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform1iv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2iv(GLuint program, GLint location, GLsizei count, + const GLint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2IV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2iv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3iv(GLuint program, GLint location, GLsizei count, + const GLint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3IV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3iv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform4iv(GLuint program, GLint location, GLsizei count, + const GLint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4IV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform4iv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform1ui(GLuint program, GLint location, GLuint x) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1UI, 3); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].ui = x; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform1ui(ctx->Exec, (program, location, x)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2ui(GLuint program, GLint location, GLuint x, GLuint y) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2UI, 4); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].ui = x; + n[4].ui = y; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2ui(ctx->Exec, (program, location, x, y)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3ui(GLuint program, GLint location, + GLuint x, GLuint y, GLuint z) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3UI, 5); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].ui = x; + n[4].ui = y; + n[5].ui = z; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3ui(ctx->Exec, (program, location, x, y, z)); + } +} + +static void GLAPIENTRY +save_ProgramUniform4ui(GLuint program, GLint location, + GLuint x, GLuint y, GLuint z, GLuint w) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4UI, 6); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].ui = x; + n[4].ui = y; + n[5].ui = z; + n[6].ui = w; + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform4ui(ctx->Exec, (program, location, x, y, z, w)); + } +} + +static void GLAPIENTRY +save_ProgramUniform1uiv(GLuint program, GLint location, GLsizei count, + const GLuint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1UIV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLuint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform1uiv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform2uiv(GLuint program, GLint location, GLsizei count, + const GLuint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2UIV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLuint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform2uiv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform3uiv(GLuint program, GLint location, GLsizei count, + const GLuint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3UIV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLuint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform3uiv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniform4uiv(GLuint program, GLint location, GLsizei count, + const GLuint *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4UIV, 3 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLuint))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniform4uiv(ctx->Exec, (program, location, count, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX22F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 2 * 2 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix2fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix2x3fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX23F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 2 * 3 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix2x3fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix2x4fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX24F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 2 * 4 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix2x4fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix3x2fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX32F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 3 * 2 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix3x2fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX33F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 3 * 3 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix3fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix3x4fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX34F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 3 * 4 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix3x4fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix4x2fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX42F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 4 * 2 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix4x2fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix4x3fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX43F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 4 * 3 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix4x3fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, + GLboolean transpose, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX44F, + 4 + POINTER_DWORDS); + if (n) { + n[1].ui = program; + n[2].i = location; + n[3].i = count; + n[4].b = transpose; + save_pointer(&n[5], memdup(v, count * 4 * 4 * sizeof(GLfloat))); + } + if (ctx->ExecuteFlag) { + CALL_ProgramUniformMatrix4fv(ctx->Exec, + (program, location, count, transpose, v)); + } +} + +static void GLAPIENTRY +save_ClampColorARB(GLenum target, GLenum clamp) +{ + GET_CURRENT_CONTEXT(ctx); + Node *n; + ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx); + n = alloc_instruction(ctx, OPCODE_CLAMP_COLOR, 2); + if (n) { + n[1].e = target; + n[2].e = clamp; + } + if (ctx->ExecuteFlag) { + CALL_ClampColor(ctx->Exec, (target, clamp)); } } @@ -7692,12 +8391,6 @@ execute_list(struct gl_context *ctx, GLuint list) case OPCODE_USE_PROGRAM: CALL_UseProgram(ctx->Exec, (n[1].ui)); break; - case OPCODE_USE_SHADER_PROGRAM_EXT: - CALL_UseShaderProgramEXT(ctx->Exec, (n[1].ui, n[2].ui)); - break; - case OPCODE_ACTIVE_PROGRAM_EXT: - CALL_ActiveProgramEXT(ctx->Exec, (n[1].ui)); - break; case OPCODE_UNIFORM_1F: CALL_Uniform1f(ctx->Exec, (n[1].i, n[2].f)); break; @@ -7815,6 +8508,147 @@ execute_list(struct gl_context *ctx, GLuint list) (n[1].i, n[2].i, n[3].b, get_pointer(&n[4]))); break; + case OPCODE_USE_PROGRAM_STAGES: + CALL_UseProgramStages(ctx->Exec, (n[1].ui, n[2].ui, n[3].ui)); + break; + case OPCODE_PROGRAM_UNIFORM_1F: + CALL_ProgramUniform1f(ctx->Exec, (n[1].ui, n[2].i, n[3].f)); + break; + case OPCODE_PROGRAM_UNIFORM_2F: + CALL_ProgramUniform2f(ctx->Exec, (n[1].ui, n[2].i, n[3].f, n[4].f)); + break; + case OPCODE_PROGRAM_UNIFORM_3F: + CALL_ProgramUniform3f(ctx->Exec, (n[1].ui, n[2].i, + n[3].f, n[4].f, n[5].f)); + break; + case OPCODE_PROGRAM_UNIFORM_4F: + CALL_ProgramUniform4f(ctx->Exec, (n[1].ui, n[2].i, + n[3].f, n[4].f, n[5].f, n[6].f)); + break; + case OPCODE_PROGRAM_UNIFORM_1FV: + CALL_ProgramUniform1fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_2FV: + CALL_ProgramUniform2fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_3FV: + CALL_ProgramUniform3fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_4FV: + CALL_ProgramUniform4fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_1I: + CALL_ProgramUniform1i(ctx->Exec, (n[1].ui, n[2].i, n[3].i)); + break; + case OPCODE_PROGRAM_UNIFORM_2I: + CALL_ProgramUniform2i(ctx->Exec, (n[1].ui, n[2].i, n[3].i, n[4].i)); + break; + case OPCODE_PROGRAM_UNIFORM_3I: + CALL_ProgramUniform3i(ctx->Exec, (n[1].ui, n[2].i, + n[3].i, n[4].i, n[5].i)); + break; + case OPCODE_PROGRAM_UNIFORM_4I: + CALL_ProgramUniform4i(ctx->Exec, (n[1].ui, n[2].i, + n[3].i, n[4].i, n[5].i, n[6].i)); + break; + case OPCODE_PROGRAM_UNIFORM_1IV: + CALL_ProgramUniform1iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_2IV: + CALL_ProgramUniform2iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_3IV: + CALL_ProgramUniform3iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_4IV: + CALL_ProgramUniform4iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_1UI: + CALL_ProgramUniform1ui(ctx->Exec, (n[1].ui, n[2].i, n[3].ui)); + break; + case OPCODE_PROGRAM_UNIFORM_2UI: + CALL_ProgramUniform2ui(ctx->Exec, (n[1].ui, n[2].i, + n[3].ui, n[4].ui)); + break; + case OPCODE_PROGRAM_UNIFORM_3UI: + CALL_ProgramUniform3ui(ctx->Exec, (n[1].ui, n[2].i, + n[3].ui, n[4].ui, n[5].ui)); + break; + case OPCODE_PROGRAM_UNIFORM_4UI: + CALL_ProgramUniform4ui(ctx->Exec, (n[1].ui, n[2].i, + n[3].ui, + n[4].ui, n[5].ui, n[6].ui)); + break; + case OPCODE_PROGRAM_UNIFORM_1UIV: + CALL_ProgramUniform1uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_2UIV: + CALL_ProgramUniform2uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_3UIV: + CALL_ProgramUniform3uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_4UIV: + CALL_ProgramUniform4uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i, + get_pointer(&n[4]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX22F: + CALL_ProgramUniformMatrix2fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX23F: + CALL_ProgramUniformMatrix2x3fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX24F: + CALL_ProgramUniformMatrix2x4fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX32F: + CALL_ProgramUniformMatrix3x2fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX33F: + CALL_ProgramUniformMatrix3fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX34F: + CALL_ProgramUniformMatrix3x4fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX42F: + CALL_ProgramUniformMatrix4x2fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX43F: + CALL_ProgramUniformMatrix4x3fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_PROGRAM_UNIFORM_MATRIX44F: + CALL_ProgramUniformMatrix4fv(ctx->Exec, + (n[1].ui, n[2].i, n[3].i, n[4].b, + get_pointer(&n[5]))); + break; + case OPCODE_CLAMP_COLOR: CALL_ClampColor(ctx->Exec, (n[1].e, n[2].e)); break; @@ -8763,10 +9597,6 @@ _mesa_initialize_save_table(const struct gl_context *ctx) SET_TexParameterIiv(table, save_TexParameterIiv); SET_TexParameterIuiv(table, save_TexParameterIuiv); - /* 377. GL_EXT_separate_shader_objects */ - SET_UseShaderProgramEXT(table, save_UseShaderProgramEXT); - SET_ActiveProgramEXT(table, save_ActiveProgramEXT); - /* GL_ARB_color_buffer_float */ SET_ClampColor(table, save_ClampColorARB); @@ -8856,6 +9686,42 @@ _mesa_initialize_save_table(const struct gl_context *ctx) SET_DrawArraysInstancedBaseInstance(table, save_DrawArraysInstancedBaseInstance); SET_DrawElementsInstancedBaseInstance(table, save_DrawElementsInstancedBaseInstance); SET_DrawElementsInstancedBaseVertexBaseInstance(table, save_DrawElementsInstancedBaseVertexBaseInstance); + + /* OpenGL 4.2 / GL_ARB_separate_shader_objects */ + SET_UseProgramStages(table, save_UseProgramStages); + SET_ProgramUniform1f(table, save_ProgramUniform1f); + SET_ProgramUniform2f(table, save_ProgramUniform2f); + SET_ProgramUniform3f(table, save_ProgramUniform3f); + SET_ProgramUniform4f(table, save_ProgramUniform4f); + SET_ProgramUniform1fv(table, save_ProgramUniform1fv); + SET_ProgramUniform2fv(table, save_ProgramUniform2fv); + SET_ProgramUniform3fv(table, save_ProgramUniform3fv); + SET_ProgramUniform4fv(table, save_ProgramUniform4fv); + SET_ProgramUniform1i(table, save_ProgramUniform1i); + SET_ProgramUniform2i(table, save_ProgramUniform2i); + SET_ProgramUniform3i(table, save_ProgramUniform3i); + SET_ProgramUniform4i(table, save_ProgramUniform4i); + SET_ProgramUniform1iv(table, save_ProgramUniform1iv); + SET_ProgramUniform2iv(table, save_ProgramUniform2iv); + SET_ProgramUniform3iv(table, save_ProgramUniform3iv); + SET_ProgramUniform4iv(table, save_ProgramUniform4iv); + SET_ProgramUniform1ui(table, save_ProgramUniform1ui); + SET_ProgramUniform2ui(table, save_ProgramUniform2ui); + SET_ProgramUniform3ui(table, save_ProgramUniform3ui); + SET_ProgramUniform4ui(table, save_ProgramUniform4ui); + SET_ProgramUniform1uiv(table, save_ProgramUniform1uiv); + SET_ProgramUniform2uiv(table, save_ProgramUniform2uiv); + SET_ProgramUniform3uiv(table, save_ProgramUniform3uiv); + SET_ProgramUniform4uiv(table, save_ProgramUniform4uiv); + SET_ProgramUniformMatrix2fv(table, save_ProgramUniformMatrix2fv); + SET_ProgramUniformMatrix3fv(table, save_ProgramUniformMatrix3fv); + SET_ProgramUniformMatrix4fv(table, save_ProgramUniformMatrix4fv); + SET_ProgramUniformMatrix2x3fv(table, save_ProgramUniformMatrix2x3fv); + SET_ProgramUniformMatrix3x2fv(table, save_ProgramUniformMatrix3x2fv); + SET_ProgramUniformMatrix2x4fv(table, save_ProgramUniformMatrix2x4fv); + SET_ProgramUniformMatrix4x2fv(table, save_ProgramUniformMatrix4x2fv); + SET_ProgramUniformMatrix3x4fv(table, save_ProgramUniformMatrix3x4fv); + SET_ProgramUniformMatrix4x3fv(table, save_ProgramUniformMatrix4x3fv); } diff --git a/mesalib/src/mesa/main/errors.c b/mesalib/src/mesa/main/errors.c index 30a867298..aa0ff50ac 100644 --- a/mesalib/src/mesa/main/errors.c +++ b/mesalib/src/mesa/main/errors.c @@ -1414,6 +1414,12 @@ _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) _mesa_record_error(ctx, error); } +void +_mesa_error_no_memory(const char *caller) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller); +} /** * Report debug information. Print error message to stderr via fprintf(). diff --git a/mesalib/src/mesa/main/errors.h b/mesalib/src/mesa/main/errors.h index 06d0b21fc..b388138e8 100644 --- a/mesalib/src/mesa/main/errors.h +++ b/mesalib/src/mesa/main/errors.h @@ -63,6 +63,9 @@ _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) PRINTF extern void _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) PRINTFLIKE(3, 4); +extern void +_mesa_error_no_memory(const char *caller); + extern void _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3); diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index a72284c9a..c2ff7e3b7 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -114,6 +114,7 @@ static const struct extension extension_table[] = { { "GL_ARB_invalidate_subdata", o(dummy_true), GL, 2012 }, { "GL_ARB_map_buffer_alignment", o(dummy_true), GL, 2011 }, { "GL_ARB_map_buffer_range", o(ARB_map_buffer_range), GL, 2008 }, + { "GL_ARB_multi_bind", o(dummy_true), GL, 2013 }, { "GL_ARB_multi_draw_indirect", o(ARB_draw_indirect), GLC, 2012 }, { "GL_ARB_multisample", o(dummy_true), GLL, 1994 }, { "GL_ARB_multitexture", o(dummy_true), GLL, 1998 }, @@ -127,7 +128,7 @@ static const struct extension extension_table[] = { { "GL_ARB_sample_shading", o(ARB_sample_shading), GL, 2009 }, { "GL_ARB_sampler_objects", o(dummy_true), GL, 2009 }, { "GL_ARB_seamless_cube_map", o(ARB_seamless_cube_map), GL, 2009 }, - { "GL_ARB_separate_shader_objects", o(ARB_separate_shader_objects), GL, 2010 }, + { "GL_ARB_separate_shader_objects", o(dummy_true), GL, 2010 }, { "GL_ARB_shader_atomic_counters", o(ARB_shader_atomic_counters), GL, 2011 }, { "GL_ARB_shader_bit_encoding", o(ARB_shader_bit_encoding), GL, 2010 }, { "GL_ARB_shader_image_load_store", o(ARB_shader_image_load_store), GL, 2011 }, @@ -217,7 +218,7 @@ static const struct extension extension_table[] = { { "GL_EXT_provoking_vertex", o(EXT_provoking_vertex), GL, 2009 }, { "GL_EXT_rescale_normal", o(dummy_true), GLL, 1997 }, { "GL_EXT_secondary_color", o(dummy_true), GLL, 1999 }, - { "GL_EXT_separate_shader_objects", o(EXT_separate_shader_objects), GLL, 2008 }, + { "GL_EXT_separate_shader_objects", o(dummy_true), ES2, 2013 }, { "GL_EXT_separate_specular_color", o(dummy_true), GLL, 1997 }, { "GL_EXT_shader_integer_mix", o(EXT_shader_integer_mix), GL | ES3, 2013 }, { "GL_EXT_shadow_funcs", o(ARB_shadow), GLL, 2002 }, @@ -330,6 +331,7 @@ static const struct extension extension_table[] = { { "GL_IBM_rasterpos_clip", o(dummy_true), GLL, 1996 }, { "GL_IBM_texture_mirrored_repeat", o(dummy_true), GLL, 1998 }, { "GL_INGR_blend_func_separate", o(EXT_blend_func_separate), GLL, 1999 }, + { "GL_INTEL_performance_query", o(INTEL_performance_query), GL | ES2, 2013 }, { "GL_MESA_pack_invert", o(MESA_pack_invert), GL, 2002 }, { "GL_MESA_texture_signed_rgba", o(EXT_texture_snorm), GL, 2009 }, { "GL_MESA_window_pos", o(dummy_true), GLL, 2000 }, @@ -409,7 +411,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) ctx->Extensions.ARB_occlusion_query = GL_TRUE; ctx->Extensions.ARB_occlusion_query2 = GL_TRUE; ctx->Extensions.ARB_point_sprite = GL_TRUE; - ctx->Extensions.EXT_separate_shader_objects = GL_TRUE; ctx->Extensions.ARB_shadow = GL_TRUE; ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; ctx->Extensions.ARB_texture_cube_map = GL_TRUE; diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp index 605f3713e..8c360970f 100644 --- a/mesalib/src/mesa/main/ff_fragment_shader.cpp +++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp @@ -1299,7 +1299,7 @@ create_new_program(struct gl_context *ctx, struct state_key *key) * fixed function program in a GLES2 context at all, but that's a * big mess to clean up. */ - p.shader_program->InternalSeparateShader = GL_TRUE; + p.shader_program->SeparateShader = GL_TRUE; state->language_version = 130; state->es_shader = false; diff --git a/mesalib/src/mesa/main/format_unpack.c b/mesalib/src/mesa/main/format_unpack.c index cf96609ea..9cc8f4dba 100644 --- a/mesalib/src/mesa/main/format_unpack.c +++ b/mesalib/src/mesa/main/format_unpack.c @@ -4263,3 +4263,108 @@ _mesa_unpack_uint_24_8_depth_stencil_row(mesa_format format, GLuint n, return; } } + +static void +unpack_float_32_uint_24_8_Z24_UNORM_S8_UINT(const GLuint *src, + GLuint *dst, GLuint n) +{ + GLuint i; + struct z32f_x24s8 *d = (struct z32f_x24s8 *) dst; + const GLdouble scale = 1.0 / (GLdouble) 0xffffff; + + for (i = 0; i < n; i++) { + const GLuint z24 = src[i] & 0xffffff; + d[i].z = z24 * scale; + d[i].x24s8 = src[i] >> 24; + assert(d[i].z >= 0.0f); + assert(d[i].z <= 1.0f); + } +} + +static void +unpack_float_32_uint_24_8_Z32_FLOAT_S8X24_UINT(const GLuint *src, + GLuint *dst, GLuint n) +{ + memcpy(dst, src, n * sizeof(struct z32f_x24s8)); +} + +static void +unpack_float_32_uint_24_8_S8_UINT_Z24_UNORM(const GLuint *src, + GLuint *dst, GLuint n) +{ + GLuint i; + struct z32f_x24s8 *d = (struct z32f_x24s8 *) dst; + const GLdouble scale = 1.0 / (GLdouble) 0xffffff; + + for (i = 0; i < n; i++) { + const GLuint z24 = src[i] >> 8; + d[i].z = z24 * scale; + d[i].x24s8 = src[i] & 0xff; + assert(d[i].z >= 0.0f); + assert(d[i].z <= 1.0f); + } +} + +/** + * Unpack depth/stencil returning as GL_FLOAT_32_UNSIGNED_INT_24_8_REV. + * \param format the source data format + * + * In GL_FLOAT_32_UNSIGNED_INT_24_8_REV lower 4 bytes contain float + * component and higher 4 bytes contain packed 24-bit and 8-bit + * components. + * + * 31 30 29 28 ... 4 3 2 1 0 31 30 29 ... 9 8 7 6 5 ... 2 1 0 + * +-------------------------+ +--------------------------------+ + * | Float Component | | Unused | 8 bit stencil | + * +-------------------------+ +--------------------------------+ + * lower 4 bytes higher 4 bytes + */ +void +_mesa_unpack_float_32_uint_24_8_depth_stencil_row(mesa_format format, GLuint n, + const void *src, GLuint *dst) +{ + switch (format) { + case MESA_FORMAT_S8_UINT_Z24_UNORM: + unpack_float_32_uint_24_8_S8_UINT_Z24_UNORM(src, dst, n); + break; + case MESA_FORMAT_Z24_UNORM_S8_UINT: + unpack_float_32_uint_24_8_Z24_UNORM_S8_UINT(src, dst, n); + break; + case MESA_FORMAT_Z32_FLOAT_S8X24_UINT: + unpack_float_32_uint_24_8_Z32_FLOAT_S8X24_UINT(src, dst, n); + break; + default: + _mesa_problem(NULL, + "bad format %s in _mesa_unpack_uint_24_8_depth_stencil_row", + _mesa_get_format_name(format)); + return; + } +} + +/** + * Unpack depth/stencil + * \param format the source data format + * \param type the destination data type + */ +void +_mesa_unpack_depth_stencil_row(mesa_format format, GLuint n, + const void *src, GLenum type, + GLuint *dst) +{ + assert(type == GL_UNSIGNED_INT_24_8 || + type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + + switch (type) { + case GL_UNSIGNED_INT_24_8: + _mesa_unpack_uint_24_8_depth_stencil_row(format, n, src, dst); + break; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + _mesa_unpack_float_32_uint_24_8_depth_stencil_row(format, n, src, dst); + break; + default: + _mesa_problem(NULL, + "bad type 0x%x in _mesa_unpack_depth_stencil_row", + type); + return; + } +} diff --git a/mesalib/src/mesa/main/format_unpack.h b/mesalib/src/mesa/main/format_unpack.h index 1fcfc04b3..51f97df4d 100644 --- a/mesalib/src/mesa/main/format_unpack.h +++ b/mesalib/src/mesa/main/format_unpack.h @@ -63,5 +63,13 @@ void _mesa_unpack_uint_24_8_depth_stencil_row(mesa_format format, GLuint n, const void *src, GLuint *dst); - +void +_mesa_unpack_float_32_uint_24_8_depth_stencil_row(mesa_format format, + GLuint n, + const void *src, + GLuint *dst); +void +_mesa_unpack_depth_stencil_row(mesa_format format, GLuint n, + const void *src, GLenum type, + GLuint *dst); #endif /* FORMAT_UNPACK_H */ diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index fe35ff3ef..80a5839b5 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -387,7 +387,6 @@ EXTRA_EXT(ARB_texture_cube_map_array); EXTRA_EXT(ARB_texture_buffer_range); EXTRA_EXT(ARB_texture_multisample); EXTRA_EXT(ARB_texture_gather); -EXTRA_EXT(ARB_separate_shader_objects); EXTRA_EXT(ARB_shader_atomic_counters); EXTRA_EXT(ARB_draw_indirect); EXTRA_EXT(ARB_shader_image_load_store); @@ -395,6 +394,7 @@ EXTRA_EXT(ARB_viewport_array); EXTRA_EXT(ARB_compute_shader); EXTRA_EXT(ARB_gpu_shader5); EXTRA_EXT2(ARB_transform_feedback3, ARB_gpu_shader5); +EXTRA_EXT(INTEL_performance_query); static const int extra_ARB_color_buffer_float_or_glcore[] = { diff --git a/mesalib/src/mesa/main/get_hash_params.py b/mesalib/src/mesa/main/get_hash_params.py index 06d0bbacc..d40fa0778 100644 --- a/mesalib/src/mesa/main/get_hash_params.py +++ b/mesalib/src/mesa/main/get_hash_params.py @@ -311,6 +311,12 @@ descriptor=[ # GL_ARB_get_program_binary / GL_OES_get_program_binary [ "NUM_PROGRAM_BINARY_FORMATS", "CONST(0), NO_EXTRA" ], [ "PROGRAM_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, NO_EXTRA" ], + +# GL_INTEL_performance_query + [ "PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_QUERY_NAME_LENGTH), extra_INTEL_performance_query" ], + [ "PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_NAME_LENGTH), extra_INTEL_performance_query" ], + [ "PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_DESC_LENGTH), extra_INTEL_performance_query" ], + [ "PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL", "CONST(PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS), extra_INTEL_performance_query" ], ]}, # GLES3 is not a typo. @@ -727,7 +733,7 @@ descriptor=[ [ "MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB", "CONTEXT_INT(Const.MaxProgramTextureGatherComponents), extra_ARB_texture_gather"], # GL_ARB_separate_shader_objects - [ "PROGRAM_PIPELINE_BINDING", "LOC_CUSTOM, TYPE_INT, GL_PROGRAM_PIPELINE_BINDING, extra_ARB_separate_shader_objects" ], + [ "PROGRAM_PIPELINE_BINDING", "LOC_CUSTOM, TYPE_INT, GL_PROGRAM_PIPELINE_BINDING, NO_EXTRA" ], # GL_ARB_shader_atomic_counters [ "ATOMIC_COUNTER_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_atomic_counters" ], diff --git a/mesalib/src/mesa/main/hash.c b/mesalib/src/mesa/main/hash.c index 4c92005e0..23018e9da 100644 --- a/mesalib/src/mesa/main/hash.c +++ b/mesalib/src/mesa/main/hash.c @@ -194,15 +194,55 @@ _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key) /** - * Insert a key/pointer pair into the hash table. - * If an entry with this key already exists we'll replace the existing entry. - * + * Lookup an entry in the hash table without locking the mutex. + * + * The hash table mutex must be locked manually by calling + * _mesa_HashLockMutex() before calling this function. + * + * \param table the hash table. + * \param key the key. + * + * \return pointer to user's data or NULL if key not in table + */ +void * +_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key) +{ + return _mesa_HashLookup_unlocked(table, key); +} + + +/** + * Lock the hash table mutex. + * + * This function should be used when multiple objects need + * to be looked up in the hash table, to avoid having to lock + * and unlock the mutex each time. + * * \param table the hash table. - * \param key the key (not zero). - * \param data pointer to user data. */ void -_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) +_mesa_HashLockMutex(struct _mesa_HashTable *table) +{ + assert(table); + mtx_lock(&table->Mutex); +} + + +/** + * Unlock the hash table mutex. + * + * \param table the hash table. + */ +void +_mesa_HashUnlockMutex(struct _mesa_HashTable *table) +{ + assert(table); + mtx_unlock(&table->Mutex); +} + + +static inline void +_mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data) { uint32_t hash = uint_hash(key); struct hash_entry *entry; @@ -210,8 +250,6 @@ _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) assert(table); assert(key); - mtx_lock(&table->Mutex); - if (key > table->MaxKey) table->MaxKey = key; @@ -225,11 +263,44 @@ _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) _mesa_hash_table_insert(table->ht, hash, uint_key(key), data); } } +} - mtx_unlock(&table->Mutex); + +/** + * Insert a key/pointer pair into the hash table without locking the mutex. + * If an entry with this key already exists we'll replace the existing entry. + * + * The hash table mutex must be locked manually by calling + * _mesa_HashLockMutex() before calling this function. + * + * \param table the hash table. + * \param key the key (not zero). + * \param data pointer to user data. + */ +void +_mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data) +{ + _mesa_HashInsert_unlocked(table, key, data); } +/** + * Insert a key/pointer pair into the hash table. + * If an entry with this key already exists we'll replace the existing entry. + * + * \param table the hash table. + * \param key the key (not zero). + * \param data pointer to user data. + */ +void +_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) +{ + assert(table); + mtx_lock(&table->Mutex); + _mesa_HashInsert_unlocked(table, key, data); + mtx_unlock(&table->Mutex); +} + /** * Remove an entry from the hash table. diff --git a/mesalib/src/mesa/main/hash.h b/mesalib/src/mesa/main/hash.h index b34f32848..e3e8f492e 100644 --- a/mesalib/src/mesa/main/hash.h +++ b/mesalib/src/mesa/main/hash.h @@ -45,6 +45,15 @@ extern void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *da extern void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key); +extern void _mesa_HashLockMutex(struct _mesa_HashTable *table); + +extern void _mesa_HashUnlockMutex(struct _mesa_HashTable *table); + +extern void *_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key); + +extern void _mesa_HashInsertLocked(struct _mesa_HashTable *table, + GLuint key, void *data); + extern void _mesa_HashDeleteAll(struct _mesa_HashTable *table, void (*callback)(GLuint key, void *data, void *userData), diff --git a/mesalib/src/mesa/main/imports.h b/mesalib/src/mesa/main/imports.h index 17a9bd099..af780b249 100644 --- a/mesalib/src/mesa/main/imports.h +++ b/mesalib/src/mesa/main/imports.h @@ -126,7 +126,8 @@ typedef union { GLfloat f; GLint i; GLuint u; } fi_type; #define atanhf(f) ((float) atanh(f)) #endif -#if defined(_MSC_VER) && (_MSC_VER < 1800) /* Not req'd on VS2013 and above */ +#if defined(_MSC_VER) +#if _MSC_VER < 1800 /* Not req'd on VS2013 and above */ static inline float truncf(float x) { return x < 0.0f ? ceilf(x) : floorf(x); } static inline float exp2f(float x) { return powf(2.0f, x); } static inline float log2f(float x) { return logf(x) * 1.442695041f; } @@ -135,6 +136,7 @@ static inline float acoshf(float x) { return logf(x + sqrtf(x * x - 1.0f)); } static inline float atanhf(float x) { return (logf(1.0f + x) - logf(1.0f - x)) / 2.0f; } static inline int isblank(int ch) { return ch == ' ' || ch == '\t'; } #define strtoll(p, e, b) _strtoi64(p, e, b) +#endif /* _MSC_VER < 1800 */ #define strcasecmp(s1, s2) _stricmp(s1, s2) #endif /*@}*/ diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index 5fbfffe98..917d071a2 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -1195,6 +1195,8 @@ struct gl_texture_object GLuint Name; /**< the user-visible texture object ID */ GLchar *Label; /**< GL_KHR_debug */ GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */ + gl_texture_index TargetIndex; /**< The gl_texture_unit::CurrentTex index. + Only valid when Target is valid. */ struct gl_sampler_object Sampler; @@ -1368,6 +1370,9 @@ 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; }; @@ -2432,6 +2437,15 @@ struct gl_shader struct glsl_symbol_table *symbols; bool uses_builtin_functions; + bool uses_gl_fragcoord; + bool redeclares_gl_fragcoord; + bool ARB_fragment_coord_conventions_enable; + + /** + * Fragment shader state from GLSL 1.50 layout qualifiers. + */ + bool origin_upper_left; + bool pixel_center_integer; /** * Geometry shader state from GLSL 1.50 layout qualifiers. @@ -2593,17 +2607,6 @@ struct gl_shader_program */ GLboolean BinaryRetreivableHint; - /** - * Flags that the linker should not reject the program if it lacks - * a vertex or fragment shader. GLES2 doesn't allow separate - * shader objects, and would reject them. However, we internally - * build separate shader objects for fixed function programs, which - * we use for drivers/common/meta.c and for handling - * _mesa_update_state with no program bound (for example in - * glClear()). - */ - GLboolean InternalSeparateShader; - /** * Indicates whether program can be bound for individual pipeline stages * using UseProgramStages after it is next linked. @@ -2757,6 +2760,11 @@ struct gl_shader_program * \c NULL. */ struct gl_shader *_LinkedShaders[MESA_SHADER_STAGES]; + + /* True if any of the fragment shaders attached to this program use: + * #extension ARB_fragment_coord_conventions: enable + */ + GLboolean ARB_fragment_coord_conventions_enable; }; @@ -2790,9 +2798,7 @@ struct gl_pipeline_object /** * Programs used for rendering * - * There is a separate program set for each shader stage. If - * GL_EXT_separate_shader_objects is not supported, each of these must point - * to \c NULL or to the same program. + * There is a separate program set for each shader stage. */ struct gl_shader_program *CurrentProgram[MESA_SHADER_STAGES]; @@ -3521,7 +3527,6 @@ struct gl_extensions GLboolean ARB_point_sprite; GLboolean ARB_sample_shading; GLboolean ARB_seamless_cube_map; - GLboolean ARB_separate_shader_objects; GLboolean ARB_shader_atomic_counters; GLboolean ARB_shader_bit_encoding; GLboolean ARB_shader_image_load_store; @@ -3547,6 +3552,7 @@ struct gl_extensions GLboolean ARB_texture_mirror_clamp_to_edge; GLboolean ARB_texture_multisample; GLboolean ARB_texture_non_power_of_two; + GLboolean ARB_texture_stencil8; GLboolean ARB_texture_query_levels; GLboolean ARB_texture_query_lod; GLboolean ARB_texture_rg; @@ -3577,7 +3583,6 @@ struct gl_extensions GLboolean EXT_pixel_buffer_object; GLboolean EXT_point_parameters; GLboolean EXT_provoking_vertex; - GLboolean EXT_separate_shader_objects; GLboolean EXT_shader_integer_mix; GLboolean EXT_stencil_two_side; GLboolean EXT_texture3D; @@ -3608,6 +3613,7 @@ struct gl_extensions GLboolean ATI_texture_env_combine3; GLboolean ATI_fragment_shader; GLboolean ATI_separate_stencil; + GLboolean INTEL_performance_query; GLboolean MESA_pack_invert; GLboolean MESA_ycbcr_texture; GLboolean NV_conditional_render; diff --git a/mesalib/src/mesa/main/performance_monitor.c b/mesalib/src/mesa/main/performance_monitor.c index e62f77012..21b9423e0 100644 --- a/mesalib/src/mesa/main/performance_monitor.c +++ b/mesalib/src/mesa/main/performance_monitor.c @@ -137,6 +137,46 @@ get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id) return &group_obj->Counters[id]; } +/* For INTEL_performance_query, query id 0 is reserved to be invalid. We use + * index to Groups array + 1 as the query id. Same applies to counter id. + */ +static inline GLuint +queryid_to_index(GLuint queryid) +{ + return queryid - 1; +} + +static inline GLuint +index_to_queryid(GLuint index) +{ + return index + 1; +} + +static inline bool +queryid_valid(const struct gl_context *ctx, GLuint queryid) +{ + return get_group(ctx, queryid_to_index(queryid)) != NULL; +} + +static inline GLuint +counterid_to_index(GLuint counterid) +{ + return counterid - 1; +} + +static inline GLuint +index_to_counterid(GLuint index) +{ + return index + 1; +} + +static inline bool +counterid_valid(const struct gl_perf_monitor_group *group_obj, + GLuint counterid) +{ + return get_counter(group_obj, counterid_to_index(counterid)) != NULL; +} + /*****************************************************************************/ void GLAPIENTRY @@ -639,3 +679,577 @@ _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c) return 0; } } + +extern void GLAPIENTRY +_mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId) +{ + GET_CURRENT_CONTEXT(ctx); + unsigned numGroups; + + /* The GL_INTEL_performance_query spec says: + * + * "If queryId pointer is equal to 0, INVALID_VALUE error is generated." + */ + if (!queryId) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetFirstPerfQueryIdINTEL(queryId == NULL)"); + return; + } + + numGroups = ctx->PerfMonitor.NumGroups; + + /* The GL_INTEL_performance_query spec says: + * + * "If the given hardware platform doesn't support any performance + * queries, then the value of 0 is returned and INVALID_OPERATION error + * is raised." + */ + if (numGroups == 0) { + *queryId = 0; + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFirstPerfQueryIdINTEL(no queries supported)"); + return; + } + + *queryId = index_to_queryid(0); +} + +extern void GLAPIENTRY +_mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId) +{ + GET_CURRENT_CONTEXT(ctx); + + /* The GL_INTEL_performance_query spec says: + * + * "The result is passed in location pointed by nextQueryId. If query + * identified by queryId is the last query available the value of 0 is + * returned. If the specified performance query identifier is invalid + * then INVALID_VALUE error is generated. If nextQueryId pointer is + * equal to 0, an INVALID_VALUE error is generated. Whenever error is + * generated, the value of 0 is returned." + */ + + if (!nextQueryId) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetNextPerfQueryIdINTEL(nextQueryId == NULL)"); + return; + } + + if (!queryid_valid(ctx, queryId)) { + *nextQueryId = 0; + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetNextPerfQueryIdINTEL(invalid query)"); + return; + } + + ++queryId; + + if (!queryid_valid(ctx, queryId)) { + *nextQueryId = 0; + } else { + *nextQueryId = queryId; + } +} + +extern void GLAPIENTRY +_mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId) +{ + GET_CURRENT_CONTEXT(ctx); + unsigned i; + + /* The GL_INTEL_performance_query spec says: + * + * "If queryName does not reference a valid query name, an INVALID_VALUE + * error is generated." + */ + if (!queryName) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfQueryIdByNameINTEL(queryName == NULL)"); + return; + } + + /* The specification does not state that this produces an error. */ + if (!queryId) { + _mesa_warning(ctx, "glGetPerfQueryIdByNameINTEL(queryId == NULL)"); + return; + } + + for (i = 0; i < ctx->PerfMonitor.NumGroups; ++i) { + const struct gl_perf_monitor_group *group_obj = get_group(ctx, i); + if (strcmp(group_obj->Name, queryName) == 0) { + *queryId = index_to_queryid(i); + return; + } + } + + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfQueryIdByNameINTEL(invalid query name)"); +} + +extern void GLAPIENTRY +_mesa_GetPerfQueryInfoINTEL(GLuint queryId, + GLuint queryNameLength, char *queryName, + GLuint *dataSize, GLuint *noCounters, + GLuint *noActiveInstances, + GLuint *capsMask) +{ + GET_CURRENT_CONTEXT(ctx); + unsigned i; + + const struct gl_perf_monitor_group *group_obj = + get_group(ctx, queryid_to_index(queryId)); + + if (group_obj == NULL) { + /* The GL_INTEL_performance_query spec says: + * + * "If queryId does not reference a valid query type, an + * INVALID_VALUE error is generated." + */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfQueryInfoINTEL(invalid query)"); + return; + } + + if (queryName) { + strncpy(queryName, group_obj->Name, queryNameLength); + + /* No specification given about whether the string needs to be + * zero-terminated. Zero-terminate the string always as we don't + * otherwise communicate the length of the returned string. + */ + if (queryNameLength > 0) { + queryName[queryNameLength - 1] = '\0'; + } + } + + if (dataSize) { + unsigned size = 0; + for (i = 0; i < group_obj->NumCounters; ++i) { + /* What we get from the driver is group id (uint32_t) + counter id + * (uint32_t) + value. + */ + size += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]); + } + *dataSize = size; + } + + if (noCounters) { + *noCounters = group_obj->NumCounters; + } + + /* The GL_INTEL_performance_query spec says: + * + * "-- the actual number of already created query instances in + * maxInstances location" + * + * 1) Typo in the specification, should be noActiveInstances. + * 2) Another typo in the specification, maxInstances parameter is not listed + * in the declaration of this function in the list of new functions. + */ + if (noActiveInstances) { + *noActiveInstances = _mesa_HashNumEntries(ctx->PerfMonitor.Monitors); + } + + if (capsMask) { + /* TODO: This information not yet available in the monitor structs. For + * now, we hardcode SINGLE_CONTEXT, since that's what the implementation + * currently tries very hard to do. + */ + *capsMask = GL_PERFQUERY_SINGLE_CONTEXT_INTEL; + } +} + +extern void GLAPIENTRY +_mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId, + GLuint counterNameLength, char *counterName, + GLuint counterDescLength, char *counterDesc, + GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, + GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue) +{ + GET_CURRENT_CONTEXT(ctx); + + const struct gl_perf_monitor_group *group_obj; + const struct gl_perf_monitor_counter *counter_obj; + unsigned counterIndex; + unsigned i; + + group_obj = get_group(ctx, queryid_to_index(queryId)); + + /* The GL_INTEL_performance_query spec says: + * + * "If the pair of queryId and counterId does not reference a valid + * counter, an INVALID_VALUE error is generated." + */ + if (group_obj == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfCounterInfoINTEL(invalid queryId)"); + return; + } + + counterIndex = counterid_to_index(counterId); + counter_obj = get_counter(group_obj, counterIndex); + + if (counter_obj == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfCounterInfoINTEL(invalid counterId)"); + return; + } + + if (counterName) { + strncpy(counterName, counter_obj->Name, counterNameLength); + + /* No specification given about whether the string needs to be + * zero-terminated. Zero-terminate the string always as we don't + * otherwise communicate the length of the returned string. + */ + if (counterNameLength > 0) { + counterName[counterNameLength - 1] = '\0'; + } + } + + if (counterDesc) { + /* TODO: No separate description text at the moment. We pass the name + * again for the moment. + */ + strncpy(counterDesc, counter_obj->Name, counterDescLength); + + /* No specification given about whether the string needs to be + * zero-terminated. Zero-terminate the string always as we don't + * otherwise communicate the length of the returned string. + */ + if (counterDescLength > 0) { + counterDesc[counterDescLength - 1] = '\0'; + } + } + + if (counterOffset) { + unsigned offset = 0; + for (i = 0; i < counterIndex; ++i) { + /* What we get from the driver is group id (uint32_t) + counter id + * (uint32_t) + value. + */ + offset += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]); + } + *counterOffset = 2 * sizeof(uint32_t) + offset; + } + + if (counterDataSize) { + *counterDataSize = _mesa_perf_monitor_counter_size(counter_obj); + } + + if (counterTypeEnum) { + /* TODO: Different counter types (semantic type, not data type) not + * supported as of yet. + */ + *counterTypeEnum = GL_PERFQUERY_COUNTER_RAW_INTEL; + } + + if (counterDataTypeEnum) { + switch (counter_obj->Type) { + case GL_FLOAT: + case GL_PERCENTAGE_AMD: + *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL; + break; + case GL_UNSIGNED_INT: + *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL; + break; + case GL_UNSIGNED_INT64_AMD: + *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL; + break; + default: + assert(!"Should not get here: invalid counter type"); + return; + } + } + + if (rawCounterMaxValue) { + /* This value is (implicitly) specified to be used only with + * GL_PERFQUERY_COUNTER_RAW_INTEL counters. When semantic types for + * counters are added, that needs to be checked. + */ + + /* The GL_INTEL_performance_query spec says: + * + * "for some raw counters for which the maximal value is + * deterministic, the maximal value of the counter in 1 second is + * returned in the location pointed by rawCounterMaxValue, otherwise, + * the location is written with the value of 0." + * + * The maximum value reported by the driver at the moment is not with + * these semantics, so write 0 always to be safe. + */ + *rawCounterMaxValue = 0; + } +} + +extern void GLAPIENTRY +_mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLuint group; + const struct gl_perf_monitor_group *group_obj; + struct gl_perf_monitor_object *m; + unsigned i; + + /* This is not specified in the extension, but is the only sane thing to + * do. + */ + if (queryHandle == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCreatePerfQueryINTEL(queryHandle == NULL)"); + return; + } + + group = queryid_to_index(queryId); + group_obj = get_group(ctx, group); + + /* The GL_INTEL_performance_query spec says: + * + * "If queryId does not reference a valid query type, an INVALID_VALUE + * error is generated." + */ + if (group_obj == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCreatePerfQueryINTEL(invalid queryId)"); + return; + } + + /* The query object created here is the counterpart of a `monitor' in + * AMD_performance_monitor. This call is equivalent to calling + * GenPerfMonitorsAMD and SelectPerfMonitorCountersAMD with a list of all + * counters in a group. + */ + + /* We keep the monitor ids contiguous */ + first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, 1); + if (!first) { + /* The GL_INTEL_performance_query spec says: + * + * "If the query instance cannot be created due to exceeding the + * number of allowed instances or driver fails query creation due to + * an insufficient memory reason, an OUT_OF_MEMORY error is + * generated, and the location pointed by queryHandle returns NULL." + */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreatePerfQueryINTEL"); + return; + } + + m = new_performance_monitor(ctx, first); + _mesa_HashInsert(ctx->PerfMonitor.Monitors, first, m); + *queryHandle = first; + + ctx->Driver.ResetPerfMonitor(ctx, m); + + for (i = 0; i < group_obj->NumCounters; ++i) { + ++m->ActiveGroups[group]; + /* Counters are a continuous range of integers, 0 to NumCounters (excl), + * so i is the counter value to use here. + */ + BITSET_SET(m->ActiveCounters[group], i); + } +} + +extern void GLAPIENTRY +_mesa_DeletePerfQueryINTEL(GLuint queryHandle) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_perf_monitor_object *m; + + /* The queryHandle is the counterpart to AMD_performance_monitor's monitor + * id. + */ + m = lookup_monitor(ctx, queryHandle); + + /* The GL_INTEL_performance_query spec says: + * + * "If a query handle doesn't reference a previously created performance + * query instance, an INVALID_VALUE error is generated." + */ + if (m == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDeletePerfQueryINTEL(invalid queryHandle)"); + return; + } + + /* Let the driver stop the monitor if it's active. */ + if (m->Active) { + ctx->Driver.ResetPerfMonitor(ctx, m); + m->Ended = false; + } + + _mesa_HashRemove(ctx->PerfMonitor.Monitors, queryHandle); + ralloc_free(m->ActiveGroups); + ralloc_free(m->ActiveCounters); + ctx->Driver.DeletePerfMonitor(ctx, m); +} + +extern void GLAPIENTRY +_mesa_BeginPerfQueryINTEL(GLuint queryHandle) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_perf_monitor_object *m; + + /* The queryHandle is the counterpart to AMD_performance_monitor's monitor + * id. + */ + + m = lookup_monitor(ctx, queryHandle); + + /* The GL_INTEL_performance_query spec says: + * + * "If a query handle doesn't reference a previously created performance + * query instance, an INVALID_VALUE error is generated." + */ + if (m == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBeginPerfQueryINTEL(invalid queryHandle)"); + return; + } + + /* The GL_INTEL_performance_query spec says: + * + * "Note that some query types, they cannot be collected in the same + * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if + * they refer to queries of such different types. In such case + * INVALID_OPERATION error is generated." + * + * We also generate an INVALID_OPERATION error if the driver can't begin + * monitoring for its own reasons, and for nesting the same query. + */ + if (m->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBeginPerfQueryINTEL(already active)"); + return; + } + + if (ctx->Driver.BeginPerfMonitor(ctx, m)) { + m->Active = true; + m->Ended = false; + } else { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBeginPerfQueryINTEL(driver unable to begin monitoring)"); + } +} + +extern void GLAPIENTRY +_mesa_EndPerfQueryINTEL(GLuint queryHandle) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_perf_monitor_object *m; + + /* The queryHandle is the counterpart to AMD_performance_monitor's monitor + * id. + */ + + m = lookup_monitor(ctx, queryHandle); + + /* The GL_INTEL_performance_query spec says: + * + * "If a performance query is not currently started, an + * INVALID_OPERATION error will be generated." + * + * The specification doesn't state that an invalid handle would be an + * INVALID_VALUE error. Regardless, query for such a handle will not be + * started, so we generate an INVALID_OPERATION in that case too. + */ + if (m == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndPerfQueryINTEL(invalid queryHandle)"); + return; + } + + if (!m->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndPerfQueryINTEL(not active)"); + return; + } + + ctx->Driver.EndPerfMonitor(ctx, m); + + m->Active = false; + m->Ended = true; +} + +extern void GLAPIENTRY +_mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags, + GLsizei dataSize, void *data, GLuint *bytesWritten) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_perf_monitor_object *m; + bool result_available; + + /* The GL_INTEL_performance_query spec says: + * + * "If bytesWritten or data pointers are NULL then an INVALID_VALUE + * error is generated." + */ + if (!bytesWritten || !data) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfQueryDataINTEL(bytesWritten or data is NULL)"); + return; + } + + /* The queryHandle is the counterpart to AMD_performance_monitor's monitor + * id. + */ + + m = lookup_monitor(ctx, queryHandle); + + /* The specification doesn't state that an invalid handle generates an + * error. We could interpret that to mean the case should be handled as + * "measurement not ready for this query", but what should be done if + * `flags' equals PERFQUERY_WAIT_INTEL? + * + * To resolve this, we just generate an INVALID_VALUE from an invalid query + * handle. + */ + if (m == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetPerfQueryDataINTEL(invalid queryHandle)"); + return; + } + + /* We need at least enough room for a single value. */ + if (dataSize < sizeof(GLuint)) { + *bytesWritten = 0; + return; + } + + /* The GL_INTEL_performance_query spec says: + * + * "The call may end without returning any data if they are not ready + * for reading as the measurement session is still pending (the + * EndPerfQueryINTEL() command processing is not finished by + * hardware). In this case location pointed by the bytesWritten + * parameter will be set to 0." + * + * If EndPerfQueryINTEL() is not called at all, we follow this. + */ + if (!m->Ended) { + *bytesWritten = 0; + return; + } + + result_available = ctx->Driver.IsPerfMonitorResultAvailable(ctx, m); + + if (!result_available) { + if (flags == GL_PERFQUERY_FLUSH_INTEL) { + ctx->Driver.Flush(ctx); + } else if (flags == GL_PERFQUERY_WAIT_INTEL) { + /* Assume Finish() is both enough and not too much to wait for + * results. If results are still not available after Finish(), the + * later code automatically bails out with 0 for bytesWritten. + */ + ctx->Driver.Finish(ctx); + result_available = + ctx->Driver.IsPerfMonitorResultAvailable(ctx, m); + } + } + + if (result_available) { + ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, (GLint*)bytesWritten); + } else { + *bytesWritten = 0; + } +} diff --git a/mesalib/src/mesa/main/performance_monitor.h b/mesalib/src/mesa/main/performance_monitor.h index 76234e5c1..7b311e4e0 100644 --- a/mesalib/src/mesa/main/performance_monitor.h +++ b/mesalib/src/mesa/main/performance_monitor.h @@ -23,7 +23,8 @@ /** * \file performance_monitor.h - * Core Mesa support for the AMD_performance_monitor extension. + * Core Mesa support for the AMD_performance_monitor extension and the + * INTEL_performance_query extension. */ #pragma once @@ -85,4 +86,44 @@ _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, unsigned _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *); + +extern void GLAPIENTRY +_mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId); + +extern void GLAPIENTRY +_mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId); + +extern void GLAPIENTRY +_mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId); + +extern void GLAPIENTRY +_mesa_GetPerfQueryInfoINTEL(GLuint queryId, + GLuint queryNameLength, char *queryName, + GLuint *dataSize, GLuint *noCounters, + GLuint *noActiveInstances, + GLuint *capsMask); + +extern void GLAPIENTRY +_mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId, + GLuint counterNameLength, char *counterName, + GLuint counterDescLength, char *counterDesc, + GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, + GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); + +extern void GLAPIENTRY +_mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle); + +extern void GLAPIENTRY +_mesa_DeletePerfQueryINTEL(GLuint queryHandle); + +extern void GLAPIENTRY +_mesa_BeginPerfQueryINTEL(GLuint queryHandle); + +extern void GLAPIENTRY +_mesa_EndPerfQueryINTEL(GLuint queryHandle); + +extern void GLAPIENTRY +_mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags, + GLsizei dataSize, void *data, GLuint *bytesWritten); + #endif diff --git a/mesalib/src/mesa/main/pipelineobj.c b/mesalib/src/mesa/main/pipelineobj.c index f55251e06..90c1d005f 100644 --- a/mesalib/src/mesa/main/pipelineobj.c +++ b/mesalib/src/mesa/main/pipelineobj.c @@ -412,8 +412,15 @@ _mesa_BindProgramPipeline(GLuint pipeline) newObj->EverBound = GL_TRUE; } + _mesa_bind_pipeline(ctx, newObj); +} + +void +_mesa_bind_pipeline(struct gl_context *ctx, + struct gl_pipeline_object *pipe) +{ /* First bind the Pipeline to pipeline binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current, newObj); + _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current, pipe); /* Section 2.11.3 (Program Objects) of the OpenGL 4.1 spec says: * @@ -424,11 +431,11 @@ _mesa_BindProgramPipeline(GLuint pipeline) * considered current." */ if (&ctx->Shader != ctx->_Shader) { - if (pipeline) { + if (pipe != NULL) { /* Bound the pipeline to the current program and * restore the pipeline state */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, newObj); + _mesa_reference_pipeline_object(ctx, &ctx->_Shader, pipe); } else { /* Unbind the pipeline */ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, diff --git a/mesalib/src/mesa/main/pipelineobj.h b/mesalib/src/mesa/main/pipelineobj.h index ceaf4f14c..7285a78f1 100644 --- a/mesalib/src/mesa/main/pipelineobj.h +++ b/mesalib/src/mesa/main/pipelineobj.h @@ -59,6 +59,10 @@ _mesa_reference_pipeline_object(struct gl_context *ctx, _mesa_reference_pipeline_object_(ctx, ptr, obj); } +extern void +_mesa_bind_pipeline(struct gl_context *ctx, + struct gl_pipeline_object *pipe); + extern GLboolean _mesa_validate_program_pipeline(struct gl_context * ctx, struct gl_pipeline_object *pipe, GLboolean IsBound); diff --git a/mesalib/src/mesa/main/samplerobj.c b/mesalib/src/mesa/main/samplerobj.c index 4900d5256..18a14d89a 100644 --- a/mesalib/src/mesa/main/samplerobj.c +++ b/mesalib/src/mesa/main/samplerobj.c @@ -51,6 +51,28 @@ _mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name) } +static inline void +begin_samplerobj_lookups(struct gl_context *ctx) +{ + _mesa_HashLockMutex(ctx->Shared->SamplerObjects); +} + + +static inline void +end_samplerobj_lookups(struct gl_context *ctx) +{ + _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects); +} + + +static inline struct gl_sampler_object * +lookup_samplerobj_locked(struct gl_context *ctx, GLuint name) +{ + return (struct gl_sampler_object *) + _mesa_HashLookupLocked(ctx->Shared->SamplerObjects, name); +} + + /** * Handle reference counting. */ @@ -285,6 +307,105 @@ _mesa_BindSampler(GLuint unit, GLuint sampler) } +void GLAPIENTRY +_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if + is + * greater than the number of texture image units supported by + * the implementation." + */ + if (first + count > ctx->Const.MaxCombinedTextureImageUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindSamplers(first=%u + count=%d > the value of " + "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)", + first, count, ctx->Const.MaxCombinedTextureImageUnits); + return; + } + + FLUSH_VERTICES(ctx, 0); + + if (samplers) { + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by + * a command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require + * a first pass to scan the entire list of bound objects for + * errors and then a second pass to actually perform the + * bindings. Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding + * point is not updated and an error will be generated. However, + * other binding points in the same command will be updated if + * their parameters are valid and no other error occurs." + */ + + begin_samplerobj_lookups(ctx); + + for (i = 0; i < count; i++) { + const GLuint unit = first + i; + struct gl_sampler_object * const currentSampler = + ctx->Texture.Unit[unit].Sampler; + struct gl_sampler_object *sampObj; + + if (samplers[i] != 0) { + if (currentSampler && currentSampler->Name == samplers[i]) + sampObj = currentSampler; + else + sampObj = lookup_samplerobj_locked(ctx, samplers[i]); + + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if any value + * in is not zero or the name of an existing + * sampler object (per binding)." + */ + if (!sampObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindSamplers(samplers[%d]=%u is not zero or " + "the name of an existing sampler object)", + i, samplers[i]); + continue; + } + } else { + sampObj = NULL; + } + + /* Bind the new sampler */ + if (sampObj != currentSampler) { + _mesa_reference_sampler_object(ctx, + &ctx->Texture.Unit[unit].Sampler, + sampObj); + ctx->NewState |= _NEW_TEXTURE; + } + } + + end_samplerobj_lookups(ctx); + } else { + /* Unbind all samplers in the range through +-1 */ + for (i = 0; i < count; i++) { + const GLuint unit = first + i; + + if (ctx->Texture.Unit[unit].Sampler) { + _mesa_reference_sampler_object(ctx, + &ctx->Texture.Unit[unit].Sampler, + NULL); + ctx->NewState |= _NEW_TEXTURE; + } + } + } +} + + /** * Check if a coordinate wrap mode is legal. * \return GL_TRUE if legal, GL_FALSE otherwise diff --git a/mesalib/src/mesa/main/samplerobj.h b/mesalib/src/mesa/main/samplerobj.h index c72b1cd8d..7d80b383d 100644 --- a/mesalib/src/mesa/main/samplerobj.h +++ b/mesalib/src/mesa/main/samplerobj.h @@ -81,6 +81,8 @@ _mesa_IsSampler(GLuint sampler); void GLAPIENTRY _mesa_BindSampler(GLuint unit, GLuint sampler); void GLAPIENTRY +_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers); +void GLAPIENTRY _mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param); void GLAPIENTRY _mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); diff --git a/mesalib/src/mesa/main/shader_query.cpp b/mesalib/src/mesa/main/shader_query.cpp index f66c11733..36d1d9cc0 100644 --- a/mesalib/src/mesa/main/shader_query.cpp +++ b/mesalib/src/mesa/main/shader_query.cpp @@ -153,6 +153,63 @@ _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index, _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); } +/* Locations associated with shader variables (array or non-array) can be + * queried using its base name or using the base name appended with the + * valid array index. For example, in case of below vertex shader, valid + * queries can be made to know the location of "xyz", "array", "array[0]", + * "array[1]", "array[2]" and "array[3]". In this example index reurned + * will be 0, 0, 0, 1, 2, 3 respectively. + * + * [Vertex Shader] + * layout(location=0) in vec4 xyz; + * layout(location=1) in vec4[4] array; + * void main() + * { } + * + * This requirement came up with the addition of ARB_program_interface_query + * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details. + * + * This utility function is used by: + * _mesa_GetAttribLocation + * _mesa_GetFragDataLocation + * _mesa_GetFragDataIndex + * + * Returns 0: + * if the 'name' string matches var->name. + * Returns 'matched index': + * if the 'name' string matches var->name appended with valid array index. + */ +int static inline +get_matching_index(const ir_variable *const var, const char *name) { + unsigned idx = 0; + const char *const paren = strchr(name, '['); + const unsigned len = (paren != NULL) ? paren - name : strlen(name); + + if (paren != NULL) { + if (!var->type->is_array()) + return -1; + + char *endptr; + idx = (unsigned) strtol(paren + 1, &endptr, 10); + const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0; + + /* Validate the sub string representing index in 'name' string */ + if ((idx > 0 && paren[1] == '0') /* leading zeroes */ + || (idx == 0 && idx_len > 1) /* all zeroes */ + || paren[1] == ' ' /* whitespace */ + || endptr[0] != ']' /* closing brace */ + || endptr[1] != '\0' /* null char */ + || idx_len == 0 /* missing index */ + || idx >= var->type->length) /* exceeding array bound */ + return -1; + } + + if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0') + return idx; + + return -1; +} + GLint GLAPIENTRY _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name) { @@ -196,8 +253,10 @@ _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name) || var->data.location < VERT_ATTRIB_GENERIC0) continue; - if (strcmp(var->name, name) == 0) - return var->data.location - VERT_ATTRIB_GENERIC0; + int index = get_matching_index(var, (const char *) name); + + if (index >= 0) + return var->data.location + index - VERT_ATTRIB_GENERIC0; } return -1; @@ -358,7 +417,7 @@ _mesa_GetFragDataIndex(GLuint program, const GLchar *name) || var->data.location < FRAG_RESULT_DATA0) continue; - if (strcmp(var->name, name) == 0) + if (get_matching_index(var, (const char *) name) >= 0) return var->data.index; } @@ -414,8 +473,10 @@ _mesa_GetFragDataLocation(GLuint program, const GLchar *name) || var->data.location < FRAG_RESULT_DATA0) continue; - if (strcmp(var->name, name) == 0) - return var->data.location - FRAG_RESULT_DATA0; + int index = get_matching_index(var, (const char *) name); + + if (index >= 0) + return var->data.location + index - FRAG_RESULT_DATA0; } return -1; diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index 1c8e6b4cf..6f84acd01 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -700,9 +700,6 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param return; } case GL_PROGRAM_SEPARABLE: - if (!ctx->Extensions.ARB_separate_shader_objects) - break; - *params = shProg->SeparateShader; return; default: @@ -795,7 +792,7 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, /** * Set/replace shader source code. A helper function used by - * glShaderSource[ARB] and glCreateShaderProgramEXT. + * glShaderSource[ARB]. */ static void shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) @@ -1548,15 +1545,14 @@ _mesa_UseProgram(GLhandleARB program) shProg = NULL; } - /* The "Dependencies on EXT_separate_shader_objects" section of the - * ARB_separate_shader_object spec says: + /* The ARB_separate_shader_object spec says: * * "The executable code for an individual shader stage is taken from * the current program for that stage. If there is a current program - * object for any shader stage or for uniform updates established by - * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current - * program for that stage (if any) is considered current. Otherwise, - * if there is a bound program pipeline object ..." + * object established by UseProgram, that program is considered current + * for all stages. Otherwise, if there is a bound program pipeline + * object (section 2.14.PPO), the program bound to the appropriate + * stage of the pipeline object is considered current." */ if (program) { /* Attach shader state to the binding point */ @@ -1777,9 +1773,6 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) return; case GL_PROGRAM_SEPARABLE: - if (!ctx->Extensions.ARB_separate_shader_objects) - break; - /* Spec imply that the behavior is the same as ARB_get_program_binary * Chapter 7.3 Program Objects */ @@ -1814,124 +1807,6 @@ _mesa_use_shader_program(struct gl_context *ctx, GLenum type, } -/** - * For GL_EXT_separate_shader_objects - */ -void GLAPIENTRY -_mesa_UseShaderProgramEXT(GLenum type, GLuint program) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg = NULL; - - if (!_mesa_validate_shader_target(ctx, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); - return; - } - - if (_mesa_is_xfb_active_and_unpaused(ctx)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseShaderProgramEXT(transform feedback is active)"); - return; - } - - if (program) { - shProg = _mesa_lookup_shader_program_err(ctx, program, - "glUseShaderProgramEXT"); - if (shProg == NULL) - return; - - if (!shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseShaderProgramEXT(program not linked)"); - return; - } - } - - /* The "Dependencies on EXT_separate_shader_objects" section of the - * ARB_separate_shader_object spec says: - * - * "The executable code for an individual shader stage is taken from - * the current program for that stage. If there is a current program - * object for any shader stage or for uniform updates established by - * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current - * program for that stage (if any) is considered current. Otherwise, - * if there is a bound program pipeline object ..." - */ - if (program) { - /* Attach shader state to the binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader); - /* Update the program */ - _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader); - } else { - /* Must be done first: detach the progam */ - _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader); - - /* Nothing remains current */ - if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] && - !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] && - !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] && - !ctx->Shader.ActiveProgram) { - - /* Unattach shader_state binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, - ctx->Pipeline.Default); - - /* If a pipeline was bound, rebind it */ - if (ctx->Pipeline.Current) { - _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name); - } - } - } -} - - -/** - * For GL_EXT_separate_shader_objects - */ -void GLAPIENTRY -_mesa_ActiveProgramEXT(GLuint program) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg = (program != 0) - ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT") - : NULL; - - /* The "Dependencies on EXT_separate_shader_objects" section of the - * ARB_separate_shader_object spec says: - * - * "The executable code for an individual shader stage is taken from - * the current program for that stage. If there is a current program - * object for any shader stage or for uniform updates established by - * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current - * program for that stage (if any) is considered current. Otherwise, - * if there is a bound program pipeline object ..." - */ - if (shProg != NULL) { - /* Attach shader state to the binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader); - _mesa_active_program(ctx, shProg, "glActiveProgramEXT"); - } else { - /* Must be done first: unset the current active progam */ - _mesa_active_program(ctx, shProg, "glActiveProgramEXT"); - - /* Nothing remains current */ - if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] && - !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] && - !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] && - !ctx->Shader.ActiveProgram) { - - /* Unattach shader_state binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default); - /* If a pipeline was bound, rebind it */ - if (ctx->Pipeline.Current) { - _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name); - } - } - } - - return; -} - static GLuint _mesa_create_shader_program(struct gl_context* ctx, GLboolean separate, GLenum type, GLsizei count, const GLchar* const *strings) @@ -2016,23 +1891,8 @@ _mesa_copy_linked_program_data(gl_shader_stage type, } } - -/** - * For GL_EXT_separate_shader_objects - */ -GLuint GLAPIENTRY -_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string) -{ - GET_CURRENT_CONTEXT(ctx); - - return _mesa_create_shader_program(ctx, GL_FALSE, type, 1, &string); -} - /** * ARB_separate_shader_objects: Compile & Link Program - * - * Basically the same as _mesa_CreateShaderProgramEXT but with support of - * multiple strings and sets the SeparateShader flag to true. */ GLuint GLAPIENTRY _mesa_CreateShaderProgramv(GLenum type, GLsizei count, diff --git a/mesalib/src/mesa/main/shaderimage.c b/mesalib/src/mesa/main/shaderimage.c index d1e752d3d..9e62f4294 100644 --- a/mesalib/src/mesa/main/shaderimage.c +++ b/mesalib/src/mesa/main/shaderimage.c @@ -33,6 +33,7 @@ #include "context.h" #include "texobj.h" #include "teximage.h" +#include "enums.h" /* * Define endian-invariant aliases for some mesa formats that are @@ -478,6 +479,148 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, layer, access, format); } +void GLAPIENTRY +_mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) +{ + GET_CURRENT_CONTEXT(ctx); + int i; + + if (!ctx->Extensions.ARB_shader_image_load_store) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures()"); + return; + } + + if (first + count > ctx->Const.MaxImageUnits) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if + + * is greater than the number of image units supported by + * the implementation." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindImageTextures(first=%u + count=%d > the value of " + "GL_MAX_IMAGE_UNITS=%u)", + first, count, ctx->Const.MaxImageUnits); + return; + } + + /* Assume that at least one binding will be changed */ + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by + * a command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require + * a first pass to scan the entire list of bound objects for + * errors and then a second pass to actually perform the + * bindings. Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding + * point is not updated and an error will be generated. However, + * other binding points in the same command will be updated if + * their parameters are valid and no other error occurs." + */ + + _mesa_begin_texture_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_image_unit *u = &ctx->ImageUnits[first + i]; + const GLuint texture = textures ? textures[i] : 0; + + if (texture != 0) { + struct gl_texture_object *texObj; + struct gl_texture_image *image; + mesa_format actualFormat; + + if (!u->TexObj || u->TexObj->Name != texture) { + texObj = _mesa_lookup_texture_locked(ctx, texture); + if (!texObj) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if any value + * in is not zero or the name of an existing + * texture object (per binding)." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindImageTextures(textures[%d]=%u " + "is not zero or the name of an existing texture " + "object)", i, texture); + continue; + } + } else { + texObj = u->TexObj; + } + + image = texObj->Image[0][0]; + + if (!image || image->Width == 0 || image->Height == 0 || image->Depth == 0) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if the width, + * height, or depth of the level zero texture image of + * any texture in is zero (per binding)." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindImageTextures(the width, height or depth " + "of the level zero texture image of " + "textures[%d]=%u is zero)", i, texture); + continue; + } + + actualFormat = get_image_format(image->InternalFormat); + + if (actualFormat == MESA_FORMAT_NONE) { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if the internal + * format of the level zero texture image of any texture + * in is not found in table 8.33 (per binding)." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindImageTextures(the internal format %s of " + "the level zero texture image of textures[%d]=%u " + "is not supported)", + _mesa_lookup_enum_by_nr(image->InternalFormat), + i, texture); + continue; + } + + /* Update the texture binding */ + _mesa_reference_texobj(&u->TexObj, texObj); + u->Level = 0; + u->Layered = _mesa_tex_target_is_layered(texObj->Target); + u->Layer = 0; + u->Access = GL_READ_WRITE; + u->Format = image->InternalFormat; + u->_ActualFormat = actualFormat; + u->_Valid = validate_image_unit(ctx, u); + } else { + /* Unbind the texture from the unit */ + _mesa_reference_texobj(&u->TexObj, NULL); + u->Level = 0; + u->Layered = GL_FALSE; + u->Layer = 0; + u->Access = GL_READ_ONLY; + u->Format = GL_R8; + u->_ActualFormat = MESA_FORMAT_R_UNORM8; + u->_Valid = GL_FALSE; + } + + /* Pass the BindImageTexture call down to the device driver */ + if (ctx->Driver.BindImageTexture) + ctx->Driver.BindImageTexture(ctx, u, u->TexObj, u->Level, u->Layered, + u->Layer, u->Access, u->Format); + } + + _mesa_end_texture_lookups(ctx); +} + void GLAPIENTRY _mesa_MemoryBarrier(GLbitfield barriers) { diff --git a/mesalib/src/mesa/main/shaderimage.h b/mesalib/src/mesa/main/shaderimage.h index aaecc5d29..733ac7747 100644 --- a/mesalib/src/mesa/main/shaderimage.h +++ b/mesalib/src/mesa/main/shaderimage.h @@ -45,6 +45,9 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +void GLAPIENTRY +_mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures); + void GLAPIENTRY _mesa_MemoryBarrier(GLbitfield barriers); diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index 2beb0abe6..1ac707d13 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -131,8 +131,8 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, GLint img, row; assert(format == GL_DEPTH_STENCIL); - assert(type == GL_UNSIGNED_INT_24_8); - /* XXX type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV is not handled yet */ + assert(type == GL_UNSIGNED_INT_24_8 || + type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); for (img = 0; img < depth; img++) { GLubyte *srcMap; @@ -149,11 +149,10 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); - /* Unpack from texture's format to GL's z24_s8 layout */ - _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat, - width, - (const GLuint *) src, - dest); + _mesa_unpack_depth_stencil_row(texImage->TexFormat, + width, + (const GLuint *) src, + type, dest); if (ctx->Pack.SwapBytes) { _mesa_swap4((GLuint *) dest, width); } @@ -838,6 +837,11 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } + else if (_mesa_is_stencil_format(format) + && !ctx->Extensions.ARB_texture_stencil8) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)"); + return GL_TRUE; + } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c index 85246c8ab..2a82c2d4e 100644 --- a/mesalib/src/mesa/main/texobj.c +++ b/mesalib/src/mesa/main/texobj.c @@ -61,6 +61,27 @@ _mesa_lookup_texture(struct gl_context *ctx, GLuint id) } +void +_mesa_begin_texture_lookups(struct gl_context *ctx) +{ + _mesa_HashLockMutex(ctx->Shared->TexObjects); +} + + +void +_mesa_end_texture_lookups(struct gl_context *ctx) +{ + _mesa_HashUnlockMutex(ctx->Shared->TexObjects); +} + + +struct gl_texture_object * +_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id) +{ + return (struct gl_texture_object *) + _mesa_HashLookupLocked(ctx->Shared->TexObjects, id); +} + /** * Allocate and initialize a new texture object. But don't put it into the @@ -260,6 +281,7 @@ _mesa_copy_texture_object( struct gl_texture_object *dest, const struct gl_texture_object *src ) { dest->Target = src->Target; + dest->TargetIndex = src->TargetIndex; dest->Name = src->Name; dest->Priority = src->Priority; dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0]; @@ -1092,17 +1114,20 @@ static void unbind_texobj_from_texunits(struct gl_context *ctx, struct gl_texture_object *texObj) { - GLuint u, tex; + const gl_texture_index index = texObj->TargetIndex; + GLuint u; + + if (texObj->Target == 0) + return; for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) { struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - if (texObj == unit->CurrentTex[tex]) { - _mesa_reference_texobj(&unit->CurrentTex[tex], - ctx->Shared->DefaultTex[tex]); - ASSERT(unit->CurrentTex[tex]); - break; - } + + if (texObj == unit->CurrentTex[index]) { + /* Bind the default texture for this unit/target */ + _mesa_reference_texobj(&unit->CurrentTex[index], + ctx->Shared->DefaultTex[index]); + unit->_BoundTextures &= ~(1 << index); } } } @@ -1126,6 +1151,28 @@ unbind_texobj_from_image_units(struct gl_context *ctx, } } +/** + * Unbinds all textures bound to the given texture image unit. + */ +static void +unbind_textures_from_unit(struct gl_context *ctx, GLuint unit) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + while (texUnit->_BoundTextures) { + const GLuint index = ffs(texUnit->_BoundTextures) - 1; + struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index]; + + _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj); + + /* Pass BindTexture call to device driver */ + if (ctx->Driver.BindTexture) + ctx->Driver.BindTexture(ctx, unit, 0, texObj); + + texUnit->_BoundTextures &= ~(1 << index); + ctx->NewState |= _NEW_TEXTURE; + } +} /** * Delete named textures. @@ -1327,6 +1374,7 @@ _mesa_BindTexture( GLenum target, GLuint texName ) mtx_unlock(&ctx->Shared->Mutex); } newTexObj->Target = target; + newTexObj->TargetIndex = targetIndex; } assert(valid_texture_object(newTexObj)); @@ -1357,9 +1405,118 @@ _mesa_BindTexture( GLenum target, GLuint texName ) ctx->Texture.CurrentUnit + 1); ASSERT(texUnit->CurrentTex[targetIndex]); + if (texName != 0) + texUnit->_BoundTextures |= (1 << targetIndex); + else + texUnit->_BoundTextures &= ~(1 << targetIndex); + /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) - ctx->Driver.BindTexture(ctx, target, newTexObj); + ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj); +} + + +void GLAPIENTRY +_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if + + * is greater than the number of texture image units supported + * by the implementation." + */ + if (first + count > ctx->Const.MaxCombinedTextureImageUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindTextures(first=%u + count=%d > the value of " + "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)", + first, count, ctx->Const.MaxCombinedTextureImageUnits); + return; + } + + /* Flush before changing bindings */ + FLUSH_VERTICES(ctx, 0); + + ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed, + first + count); + + if (textures) { + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by + * a command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require + * a first pass to scan the entire list of bound objects for + * errors and then a second pass to actually perform the + * bindings. Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding + * point is not updated and an error will be generated. However, + * other binding points in the same command will be updated if + * their parameters are valid and no other error occurs." + */ + + _mesa_begin_texture_lookups(ctx); + + for (i = 0; i < count; i++) { + if (textures[i] != 0) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i]; + struct gl_texture_object *current = texUnit->_Current; + struct gl_texture_object *texObj; + + if (current && current->Name == textures[i]) + texObj = current; + else + texObj = _mesa_lookup_texture_locked(ctx, textures[i]); + + if (texObj && texObj->Target != 0) { + const gl_texture_index targetIndex = texObj->TargetIndex; + + if (texUnit->CurrentTex[targetIndex] != texObj) { + /* Do the actual binding. The refcount on the previously + * bound texture object will be decremented. It will be + * deleted if the count hits zero. + */ + _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], + texObj); + + texUnit->_BoundTextures |= (1 << targetIndex); + ctx->NewState |= _NEW_TEXTURE; + + /* Pass the BindTexture call to the device driver */ + if (ctx->Driver.BindTexture) + ctx->Driver.BindTexture(ctx, first + i, + texObj->Target, texObj); + } + } else { + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if any value + * in is not zero or the name of an existing + * texture object (per binding)." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindTextures(textures[%d]=%u is not zero " + "or the name of an existing texture object)", + i, textures[i]); + } + } else { + unbind_textures_from_unit(ctx, first + i); + } + } + + _mesa_end_texture_lookups(ctx); + } else { + /* Unbind all textures in the range through +-1 */ + for (i = 0; i < count; i++) + unbind_textures_from_unit(ctx, first + i); + } } diff --git a/mesalib/src/mesa/main/texobj.h b/mesalib/src/mesa/main/texobj.h index a9de73fff..b1b7a3027 100644 --- a/mesalib/src/mesa/main/texobj.h +++ b/mesalib/src/mesa/main/texobj.h @@ -46,6 +46,15 @@ extern struct gl_texture_object * _mesa_lookup_texture(struct gl_context *ctx, GLuint id); +extern void +_mesa_begin_texture_lookups(struct gl_context *ctx); + +extern void +_mesa_end_texture_lookups(struct gl_context *ctx); + +extern struct gl_texture_object * +_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id); + extern struct gl_texture_object * _mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target ); @@ -176,6 +185,10 @@ extern void GLAPIENTRY _mesa_BindTexture( GLenum target, GLuint texture ); +extern void GLAPIENTRY +_mesa_BindTextures( GLuint first, GLsizei count, const GLuint *textures ); + + extern void GLAPIENTRY _mesa_PrioritizeTextures( GLsizei n, const GLuint *textures, const GLclampf *priorities ); diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c index 91b290691..19508cf39 100644 --- a/mesalib/src/mesa/main/texstate.c +++ b/mesalib/src/mesa/main/texstate.c @@ -113,6 +113,7 @@ _mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst ) MAX2(dst->Texture.NumCurrentTexUsed, u + 1); } } + dst->Texture.Unit[u]._BoundTextures = src->Texture.Unit[u]._BoundTextures; _mesa_unlock_context_textures(dst); } } @@ -877,6 +878,8 @@ init_texture_unit( struct gl_context *ctx, GLuint unit ) _mesa_reference_texobj(&texUnit->CurrentTex[tex], ctx->Shared->DefaultTex[tex]); } + + texUnit->_BoundTextures = 0; } diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index d9096abf3..764214669 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -2473,74 +2473,71 @@ _mesa_texstore_z24_s8(TEXSTORE_PARAMS) const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); GLint img, row; + GLuint *depth = malloc(srcWidth * sizeof(GLuint)); + GLubyte *stencil = malloc(srcWidth * sizeof(GLubyte)); ASSERT(dstFormat == MESA_FORMAT_S8_UINT_Z24_UNORM); ASSERT(srcFormat == GL_DEPTH_STENCIL_EXT || srcFormat == GL_DEPTH_COMPONENT || srcFormat == GL_STENCIL_INDEX); - ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT || srcType == GL_UNSIGNED_INT_24_8_EXT); + ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT || + srcType == GL_UNSIGNED_INT_24_8_EXT || + srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); - if (srcFormat == GL_DEPTH_COMPONENT || - srcFormat == GL_STENCIL_INDEX) { - GLuint *depth = malloc(srcWidth * sizeof(GLuint)); - GLubyte *stencil = malloc(srcWidth * sizeof(GLubyte)); + if (!depth || !stencil) { + free(depth); + free(stencil); + return GL_FALSE; + } - if (!depth || !stencil) { - free(depth); - free(stencil); - return GL_FALSE; - } + /* In case we only upload depth we need to preserve the stencil */ + for (img = 0; img < srcDepth; img++) { + GLuint *dstRow = (GLuint *) dstSlices[img]; + const GLubyte *src + = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, + srcWidth, srcHeight, + srcFormat, srcType, + img, 0, 0); + for (row = 0; row < srcHeight; row++) { + GLint i; + GLboolean keepdepth = GL_FALSE, keepstencil = GL_FALSE; - /* In case we only upload depth we need to preserve the stencil */ - for (img = 0; img < srcDepth; img++) { - GLuint *dstRow = (GLuint *) dstSlices[img]; - const GLubyte *src - = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, - srcWidth, srcHeight, - srcFormat, srcType, - img, 0, 0); - for (row = 0; row < srcHeight; row++) { - GLint i; - GLboolean keepdepth = GL_FALSE, keepstencil = GL_FALSE; + if (srcFormat == GL_DEPTH_COMPONENT) { /* preserve stencil */ + keepstencil = GL_TRUE; + } + else if (srcFormat == GL_STENCIL_INDEX) { /* preserve depth */ + keepdepth = GL_TRUE; + } - if (srcFormat == GL_DEPTH_COMPONENT) { /* preserve stencil */ - keepstencil = GL_TRUE; - } - else if (srcFormat == GL_STENCIL_INDEX) { /* preserve depth */ - keepdepth = GL_TRUE; - } + if (keepdepth == GL_FALSE) + /* the 24 depth bits will be in the low position: */ + _mesa_unpack_depth_span(ctx, srcWidth, + GL_UNSIGNED_INT, /* dst type */ + keepstencil ? depth : dstRow, /* dst addr */ + depthScale, + srcType, src, srcPacking); - if (keepdepth == GL_FALSE) - /* the 24 depth bits will be in the low position: */ - _mesa_unpack_depth_span(ctx, srcWidth, - GL_UNSIGNED_INT, /* dst type */ - keepstencil ? depth : dstRow, /* dst addr */ - depthScale, - srcType, src, srcPacking); - - if (keepstencil == GL_FALSE) - /* get the 8-bit stencil values */ - _mesa_unpack_stencil_span(ctx, srcWidth, - GL_UNSIGNED_BYTE, /* dst type */ - stencil, /* dst addr */ - srcType, src, srcPacking, - ctx->_ImageTransferState); - - for (i = 0; i < srcWidth; i++) { - if (keepstencil) - dstRow[i] = depth[i] << 8 | (dstRow[i] & 0x000000FF); - else - dstRow[i] = (dstRow[i] & 0xFFFFFF00) | (stencil[i] & 0xFF); - } + if (keepstencil == GL_FALSE) + /* get the 8-bit stencil values */ + _mesa_unpack_stencil_span(ctx, srcWidth, + GL_UNSIGNED_BYTE, /* dst type */ + stencil, /* dst addr */ + srcType, src, srcPacking, + ctx->_ImageTransferState); - src += srcRowStride; - dstRow += dstRowStride / sizeof(GLuint); + for (i = 0; i < srcWidth; i++) { + if (keepstencil) + dstRow[i] = depth[i] << 8 | (dstRow[i] & 0x000000FF); + else + dstRow[i] = (dstRow[i] & 0xFFFFFF00) | (stencil[i] & 0xFF); } + src += srcRowStride; + dstRow += dstRowStride / sizeof(GLuint); } - - free(depth); - free(stencil); } + + free(depth); + free(stencil); return GL_TRUE; } @@ -2563,7 +2560,8 @@ _mesa_texstore_s8_z24(TEXSTORE_PARAMS) srcFormat == GL_DEPTH_COMPONENT || srcFormat == GL_STENCIL_INDEX); ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT || - srcType == GL_UNSIGNED_INT_24_8_EXT); + srcType == GL_UNSIGNED_INT_24_8_EXT || + srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); depth = malloc(srcWidth * sizeof(GLuint)); stencil = malloc(srcWidth * sizeof(GLubyte)); @@ -3417,49 +3415,47 @@ _mesa_texstore_r11_g11_b10f(TEXSTORE_PARAMS) static GLboolean _mesa_texstore_z32f_x24s8(TEXSTORE_PARAMS) { + GLint img, row; + const GLint srcRowStride + = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) + / sizeof(uint64_t); + ASSERT(dstFormat == MESA_FORMAT_Z32_FLOAT_S8X24_UINT); ASSERT(srcFormat == GL_DEPTH_STENCIL || srcFormat == GL_DEPTH_COMPONENT || srcFormat == GL_STENCIL_INDEX); ASSERT(srcFormat != GL_DEPTH_STENCIL || + srcType == GL_UNSIGNED_INT_24_8 || srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); - if (srcFormat == GL_DEPTH_COMPONENT || - srcFormat == GL_STENCIL_INDEX) { - GLint img, row; - const GLint srcRowStride - = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) - / sizeof(uint64_t); + /* In case we only upload depth we need to preserve the stencil */ + for (img = 0; img < srcDepth; img++) { + uint64_t *dstRow = (uint64_t *) dstSlices[img]; + const uint64_t *src + = (const uint64_t *) _mesa_image_address(dims, srcPacking, srcAddr, + srcWidth, srcHeight, + srcFormat, srcType, + img, 0, 0); + for (row = 0; row < srcHeight; row++) { + /* The unpack functions with: + * dstType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV + * only write their own dword, so the other dword (stencil + * or depth) is preserved. */ + if (srcFormat != GL_STENCIL_INDEX) + _mesa_unpack_depth_span(ctx, srcWidth, + GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ + dstRow, /* dst addr */ + ~0U, srcType, src, srcPacking); - /* In case we only upload depth we need to preserve the stencil */ - for (img = 0; img < srcDepth; img++) { - uint64_t *dstRow = (uint64_t *) dstSlices[img]; - const uint64_t *src - = (const uint64_t *) _mesa_image_address(dims, srcPacking, srcAddr, - srcWidth, srcHeight, - srcFormat, srcType, - img, 0, 0); - for (row = 0; row < srcHeight; row++) { - /* The unpack functions with: - * dstType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV - * only write their own dword, so the other dword (stencil - * or depth) is preserved. */ - if (srcFormat != GL_STENCIL_INDEX) - _mesa_unpack_depth_span(ctx, srcWidth, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ - dstRow, /* dst addr */ - ~0U, srcType, src, srcPacking); - - if (srcFormat != GL_DEPTH_COMPONENT) - _mesa_unpack_stencil_span(ctx, srcWidth, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ - dstRow, /* dst addr */ - srcType, src, srcPacking, - ctx->_ImageTransferState); + if (srcFormat != GL_DEPTH_COMPONENT) + _mesa_unpack_stencil_span(ctx, srcWidth, + GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ + dstRow, /* dst addr */ + srcType, src, srcPacking, + ctx->_ImageTransferState); - src += srcRowStride; - dstRow += dstRowStride / sizeof(uint64_t); - } + src += srcRowStride; + dstRow += dstRowStride / sizeof(uint64_t); } } return GL_TRUE; diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c index abeb25e87..a73746335 100644 --- a/mesalib/src/mesa/main/transformfeedback.c +++ b/mesalib/src/mesa/main/transformfeedback.c @@ -32,7 +32,6 @@ #include "buffers.h" -#include "bufferobj.h" #include "context.h" #include "hash.h" #include "macros.h" @@ -533,14 +532,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index, bufObj); /* The per-attribute binding point */ - _mesa_reference_buffer_object(ctx, - &obj->Buffers[index], - bufObj); - - obj->BufferNames[index] = bufObj->Name; - - obj->Offset[index] = offset; - obj->RequestedSize[index] = size; + _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size); } diff --git a/mesalib/src/mesa/main/transformfeedback.h b/mesalib/src/mesa/main/transformfeedback.h index 7aecd66a7..87f4080e0 100644 --- a/mesalib/src/mesa/main/transformfeedback.h +++ b/mesalib/src/mesa/main/transformfeedback.h @@ -27,6 +27,7 @@ #define TRANSFORM_FEEDBACK_H #include +#include "bufferobj.h" #include "compiler.h" #include "glheader.h" #include "mtypes.h" @@ -127,4 +128,17 @@ extern bool _mesa_transform_feedback_is_using_program(struct gl_context *ctx, struct gl_shader_program *shProg); +static inline void +_mesa_set_transform_feedback_binding(struct gl_context *ctx, + struct gl_transform_feedback_object *tfObj, GLuint index, + struct gl_buffer_object *bufObj, + GLintptr offset, GLsizeiptr size) +{ + _mesa_reference_buffer_object(ctx, &tfObj->Buffers[index], bufObj); + + tfObj->BufferNames[index] = bufObj->Name; + tfObj->Offset[index] = offset; + tfObj->RequestedSize[index] = size; +} + #endif /* TRANSFORM_FEEDBACK_H */ diff --git a/mesalib/src/mesa/main/uniforms.h b/mesalib/src/mesa/main/uniforms.h index c8b555cbe..10518dcbb 100644 --- a/mesalib/src/mesa/main/uniforms.h +++ b/mesalib/src/mesa/main/uniforms.h @@ -319,7 +319,7 @@ struct gl_builtin_uniform_element { struct gl_builtin_uniform_desc { const char *name; - struct gl_builtin_uniform_element *elements; + const struct gl_builtin_uniform_element *elements; unsigned int num_elements; }; diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c index 66a3ef119..46956efb5 100644 --- a/mesalib/src/mesa/main/varray.c +++ b/mesalib/src/mesa/main/varray.c @@ -784,13 +784,7 @@ static const GLfloat * get_current_attrib(struct gl_context *ctx, GLuint index, const char *function) { if (index == 0) { - /* In OpenGL 3.1 attribute 0 becomes non-magic, just like in OpenGL ES - * 2.0. Note that we cannot just check for API_OPENGL_CORE here because - * that will erroneously allow this usage in a 3.0 forward-compatible - * context too. - */ - if ((ctx->API != API_OPENGL_CORE || ctx->Version < 31) - && ctx->API != API_OPENGLES2) { + if (_mesa_attr_zero_aliases_vertex(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(index==0)", function); return NULL; } @@ -1445,6 +1439,126 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, } +void GLAPIENTRY +_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, + const GLintptr *offsets, const GLsizei *strides) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object * const vao = ctx->Array.VAO; + GLuint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no + * vertex array object is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.VAO == ctx->Array.DefaultVAO) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindVertexBuffers(No array object bound)"); + return; + } + + /* The ARB_multi_bind spec says: + * + * "An INVALID_OPERATION error is generated if + + * is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS." + */ + if (first + count > ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindVertexBuffers(first=%u + count=%d > the value of " + "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)", + first, count, ctx->Const.MaxVertexAttribBindings); + return; + } + + if (!buffers) { + /** + * The ARB_multi_bind spec says: + * + * "If is NULL, each affected vertex buffer binding point + * from through +-1 will be reset to have no + * bound buffer object. In this case, the offsets and strides + * associated with the binding points are set to default values, + * ignoring and ." + */ + struct gl_buffer_object *vbo = ctx->Shared->NullBufferObj; + + for (i = 0; i < count; i++) + bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo, 0, 16); + + return; + } + + /* Note that the error semantics for multi-bind commands differ from + * those of other GL commands. + * + * The Issues section in the ARB_multi_bind spec says: + * + * "(11) Typically, OpenGL specifies that if an error is generated by + * a command, that command has no effect. This is somewhat + * unfortunate for multi-bind commands, because it would require + * a first pass to scan the entire list of bound objects for + * errors and then a second pass to actually perform the + * bindings. Should we have different error semantics? + * + * RESOLVED: Yes. In this specification, when the parameters for + * one of the binding points are invalid, that binding + * point is not updated and an error will be generated. However, + * other binding points in the same command will be updated if + * their parameters are valid and no other error occurs." + */ + + _mesa_begin_bufferobj_lookups(ctx); + + for (i = 0; i < count; i++) { + struct gl_buffer_object *vbo; + + /* The ARB_multi_bind spec says: + * + * "An INVALID_VALUE error is generated if any value in + * or is negative (per binding)." + */ + if (offsets[i] < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(offsets[%u]=%lldd < 0)", + i, (long long int) offsets[i]); + continue; + } + + if (strides[i] < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(strides[%u]=%lld < 0)", + i, (long long int) strides[i]); + continue; + } + + if (buffers[i]) { + struct gl_vertex_buffer_binding *binding = + &vao->VertexBinding[VERT_ATTRIB_GENERIC(first + i)]; + + if (buffers[i] == binding->BufferObj->Name) + vbo = binding->BufferObj; + else + vbo = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, + "glBindVertexBuffers"); + + if (!vbo) + continue; + } else { + vbo = ctx->Shared->NullBufferObj; + } + + bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo, + offsets[i], strides[i]); + } + + _mesa_end_bufferobj_lookups(ctx); +} + + void GLAPIENTRY _mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, GLboolean normalized, GLuint relativeOffset) diff --git a/mesalib/src/mesa/main/varray.h b/mesalib/src/mesa/main/varray.h index bc820ed23..f94ebac99 100644 --- a/mesalib/src/mesa/main/varray.h +++ b/mesalib/src/mesa/main/varray.h @@ -106,6 +106,22 @@ _mesa_update_client_array(struct gl_context *ctx, _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj); } +static inline bool +_mesa_attr_zero_aliases_vertex(struct gl_context *ctx) +{ + const bool is_forward_compatible_context = + ctx->Const.ContextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT; + + /* In OpenGL 3.1 attribute 0 becomes non-magic, just like in OpenGL ES + * 2.0. Note that we cannot just check for API_OPENGL_COMPAT here because + * that will erroneously allow this usage in a 3.0 forward-compatible + * context too. + */ + return (ctx->API == API_OPENGLES + || (ctx->API == API_OPENGL_COMPAT + && !is_forward_compatible_context)); +} + extern void GLAPIENTRY _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); @@ -290,6 +306,10 @@ extern void GLAPIENTRY _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, GLsizei stride); +extern void GLAPIENTRY +_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, + const GLintptr *offsets, const GLsizei *strides); + extern void GLAPIENTRY _mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, GLboolean normalized, GLuint relativeOffset); -- cgit v1.2.3 From ae06feae7876db47ff0e1fde40cf4a324a412037 Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 11 May 2014 17:40:10 +0200 Subject: mesa git update 11 May 2014 mesa commit 83b4ec03e77645c537d540a12253b3492bad4b59 --- mesalib/src/mesa/main/fbobject.c | 2 ++ mesalib/src/mesa/main/shaderapi.c | 5 +++++ mesalib/src/mesa/main/teximage.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'mesalib/src/mesa/main') diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index ca16ae1ec..97538bc7b 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -1058,6 +1058,8 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, if (att->Layered) { if (att_tex_target == GL_TEXTURE_CUBE_MAP) att_layer_count = 6; + else if (att_tex_target == GL_TEXTURE_1D_ARRAY) + att_layer_count = att->Renderbuffer->Height; else att_layer_count = att->Renderbuffer->Depth; } else { diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index 6f84acd01..28739daeb 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -1879,6 +1879,11 @@ _mesa_copy_linked_program_data(gl_shader_stage type, dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive; } break; + case MESA_SHADER_FRAGMENT: { + struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst; + dst_fp->FragDepthLayout = src->FragDepthLayout; + } + break; case MESA_SHADER_COMPUTE: { struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst; int i; diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index c7f301cbd..845ba8014 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -3024,7 +3024,7 @@ _mesa_choose_texture_format(struct gl_context *ctx, } /* choose format from scratch */ - f = ctx->Driver.ChooseTextureFormat(ctx, texObj->Target, internalFormat, + f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat, format, type); ASSERT(f != MESA_FORMAT_NONE); return f; -- cgit v1.2.3