mesa: Implement glBindSamplers
authorFredrik Höglund <fredrik@kde.org>
Fri, 15 Nov 2013 18:41:11 +0000 (19:41 +0100)
committerFredrik Höglund <fredrik@kde.org>
Fri, 2 May 2014 00:53:25 +0000 (02:53 +0200)
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/mesa/main/samplerobj.c

index 575724049ab6bf46be1c2dac647d46ac0f885888..18a14d89a5d8e1f26c66a384c60df59f39c0b556 100644 (file)
@@ -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.
  */
@@ -288,6 +310,99 @@ _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 <first> + <count> 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 <count> 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 <samplers> 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 <first> through <first>+<count>-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;
+         }
+      }
+   }
 }