Example #1
0
/**
 * Called by glUniformMatrix*() functions.
 * Note: cols=2, rows=4  ==>  array[2] of vec4
 */
extern "C" void
_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
		     GLuint cols, GLuint rows,
                     GLint location, GLsizei count,
                     GLboolean transpose,
                     const GLvoid *values, enum glsl_base_type basicType)
{
   unsigned offset;
   unsigned vectors;
   unsigned components;
   unsigned elements;
   int size_mul;
   struct gl_uniform_storage *const uni =
      validate_uniform_parameters(ctx, shProg, location, count,
                                  &offset, "glUniformMatrix");
   if (uni == NULL)
      return;

   if (!uni->type->is_matrix()) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(non-matrix uniform)");
      return;
   }

   assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE);
   size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;

   assert(!uni->type->is_sampler());
   vectors = uni->type->matrix_columns;
   components = uni->type->vector_elements;

   /* Verify that the types are compatible.  This is greatly simplified for
    * matrices because they can only have a float base type.
    */
   if (vectors != cols || components != rows) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(matrix size mismatch)");
      return;
   }

   /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE.
    * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml
    */
   if (transpose) {
      if (ctx->API == API_OPENGLES2 && ctx->Version < 30) {
	 _mesa_error(ctx, GL_INVALID_VALUE,
		     "glUniformMatrix(matrix transpose is not GL_FALSE)");
	 return;
      }
   }

   /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec
    * says:
    *
    *     "If any of the following conditions occur, an INVALID_OPERATION
    *     error is generated by the Uniform* commands, and no uniform values
    *     are changed:
    *
    *     ...
    *
    *     - if the uniform declared in the shader is not of type boolean and
    *       the type indicated in the name of the Uniform* command used does
    *       not match the type of the uniform"
    *
    * There are no Boolean matrix types, so we do not need to allow
    * GLSL_TYPE_BOOL here (as _mesa_uniform does).
    */
   if (uni->type->base_type != basicType) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)",
                  cols, rows, uni->name, location,
                  glsl_type_name(uni->type->base_type),
                  glsl_type_name(basicType));
      return;
   }

   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
      log_uniform(values, uni->type->base_type, components, vectors, count,
		  bool(transpose), shProg, location, uni);
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   elements = components * vectors;

   if (!transpose) {
      memcpy(&uni->storage[elements * offset], values,
	     sizeof(uni->storage[0]) * elements * count * size_mul);
   } else if (basicType == GLSL_TYPE_FLOAT) {
      /* Copy and transpose the matrix.
       */
      const float *src = (const float *)values;
      float *dst = &uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   } else {
      assert(basicType == GLSL_TYPE_DOUBLE);
      const double *src = (const double *)values;
      double *dst = (double *)&uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
Example #2
0
/**
 * Called by glUniformMatrix*() functions.
 * Note: cols=2, rows=4  ==>  array[2] of vec4
 */
extern "C" void
_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
		     GLuint cols, GLuint rows,
                     GLint location, GLsizei count,
                     GLboolean transpose, const GLfloat *values)
{
   unsigned loc, offset;
   unsigned vectors;
   unsigned components;
   unsigned elements;
   struct gl_uniform_storage *uni;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (!validate_uniform_parameters(ctx, shProg, location, count,
				    &loc, &offset, "glUniformMatrix", false))
      return;

   uni = &shProg->UniformStorage[loc];
   if (!uni->type->is_matrix()) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(non-matrix uniform)");
      return;
   }

   assert(!uni->type->is_sampler());
   vectors = uni->type->matrix_columns;
   components = uni->type->vector_elements;

   /* Verify that the types are compatible.  This is greatly simplified for
    * matrices because they can only have a float base type.
    */
   if (vectors != cols || components != rows) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(matrix size mismatch)");
      return;
   }

   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
      log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count,
		  bool(transpose), shProg, location, uni);
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      if (offset >= uni->array_elements)
	 return;

      count = MIN2(count, (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   elements = components * vectors;

   if (!transpose) {
      memcpy(&uni->storage[elements * offset], values,
	     sizeof(uni->storage[0]) * elements * count);
   } else {
      /* Copy and transpose the matrix.
       */
      const float *src = values;
      float *dst = &uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
Example #3
0
/**
 * Called via glUniform*() functions.
 */
extern "C" void
_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
	      GLint location, GLsizei count,
              const GLvoid *values,
              enum glsl_base_type basicType,
              unsigned src_components)
{
   unsigned offset;
   int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;

   struct gl_uniform_storage *const uni =
      validate_uniform_parameters(ctx, shProg, location, count,
                                  &offset, "glUniform");
   if (uni == NULL)
      return;

   if (uni->type->is_matrix()) {
      /* Can't set matrix uniforms (like mat4) with glUniform */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(uniform \"%s\"@%d is matrix)",
                  src_components, uni->name, location);
      return;
   }

   /* Verify that the types are compatible.
    */
   const unsigned components = uni->type->is_sampler()
      ? 1 : uni->type->vector_elements;

   if (components != src_components) {
      /* glUniformN() must match float/vecN type */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(\"%s\"@%u has %u components, not %u)",
                  src_components, uni->name, location,
                  components, src_components);
      return;
   }

   bool match;
   switch (uni->type->base_type) {
   case GLSL_TYPE_BOOL:
      match = (basicType != GLSL_TYPE_DOUBLE);
      break;
   case GLSL_TYPE_SAMPLER:
      match = (basicType == GLSL_TYPE_INT);
      break;
   case GLSL_TYPE_IMAGE:
      match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx));
      break;
   default:
      match = (basicType == uni->type->base_type);
      break;
   }

   if (!match) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(\"%s\"@%d is %s, not %s)",
                  src_components, uni->name, location,
                  glsl_type_name(uni->type->base_type),
                  glsl_type_name(basicType));
      return;
   }

   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
      log_uniform(values, basicType, components, 1, count,
		  false, shProg, location, uni);
   }

   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
    *
    *     "Setting a sampler's value to i selects texture image unit number
    *     i. The values of i range from zero to the implementation- dependent
    *     maximum supported number of texture image units."
    *
    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
    * the PDF) says:
    *
    *     "Error         Description                    Offending command
    *                                                   ignored?
    *     ...
    *     INVALID_VALUE  Numeric argument out of range  Yes"
    *
    * Based on that, when an invalid sampler is specified, we generate a
    * GL_INVALID_VALUE error and ignore the command.
    */
   if (uni->type->is_sampler()) {
      for (int i = 0; i < count; i++) {
	 const unsigned texUnit = ((unsigned *) values)[i];

         /* check that the sampler (tex unit index) is legal */
         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid sampler/tex unit index for "
			"uniform %d)",
                        location);
            return;
         }
      }
   }

   if (uni->type->is_image()) {
      for (int i = 0; i < count; i++) {
         const int unit = ((GLint *) values)[i];

         /* check that the image unit is legal */
         if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid image unit index for uniform %d)",
                        location);
            return;
         }
      }
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   if (!uni->type->is_boolean()) {
      memcpy(&uni->storage[size_mul * components * offset], values,
	     sizeof(uni->storage[0]) * components * count * size_mul);
   } else {
      const union gl_constant_value *src =
	 (const union gl_constant_value *) values;
      union gl_constant_value *dst = &uni->storage[components * offset];
      const unsigned elems = components * count;

      for (unsigned i = 0; i < elems; i++) {
	 if (basicType == GLSL_TYPE_FLOAT) {
            dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0;
	 } else {
            dst[i].i = src[i].i != 0    ? ctx->Const.UniformBooleanTrue : 0;
	 }
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);

   /* If the uniform is a sampler, do the extra magic necessary to propagate
    * the changes through.
    */
   if (uni->type->is_sampler()) {
      bool flushed = false;
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
	 struct gl_shader *const sh = shProg->_LinkedShaders[i];

	 /* If the shader stage doesn't use the sampler uniform, skip this.
	  */
	 if (sh == NULL || !uni->sampler[i].active)
	    continue;

         for (int j = 0; j < count; j++) {
            sh->SamplerUnits[uni->sampler[i].index + offset + j] =
               ((unsigned *) values)[j];
         }

	 struct gl_program *const prog = sh->Program;

	 assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits));

	 /* Determine if any of the samplers used by this shader stage have
	  * been modified.
	  */
	 bool changed = false;
	 for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) {
	    if ((sh->active_samplers & (1U << j)) != 0
		&& (prog->SamplerUnits[j] != sh->SamplerUnits[j])) {
	       changed = true;
	       break;
	    }
	 }

	 if (changed) {
	    if (!flushed) {
	       FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
	       flushed = true;
	    }

	    memcpy(prog->SamplerUnits,
		   sh->SamplerUnits,
		   sizeof(sh->SamplerUnits));

	    _mesa_update_shader_textures_used(shProg, prog);
            if (ctx->Driver.SamplerUniformChange)
	       ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
	 }
      }
   }

   /* If the uniform is an image, update the mapping from image
    * uniforms to image units present in the shader data structure.
    */
   if (uni->type->is_image()) {
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
	 if (uni->image[i].active) {
            struct gl_shader *sh = shProg->_LinkedShaders[i];

            for (int j = 0; j < count; j++)
               sh->ImageUnits[uni->image[i].index + offset + j] =
                  ((GLint *) values)[j];
         }
      }

      ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
   }
}
Example #4
0
/**
 * Called via glUniform*() functions.
 */
extern "C" void
_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
	      GLint location, GLsizei count,
              const GLvoid *values, GLenum type)
{
   unsigned loc, offset;
   unsigned components;
   unsigned src_components;
   enum glsl_base_type basicType;
   struct gl_uniform_storage *uni;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (!validate_uniform_parameters(ctx, shProg, location, count,
				    &loc, &offset, "glUniform", false))
      return;

   uni = &shProg->UniformStorage[loc];

   /* Verify that the types are compatible.
    */
   switch (type) {
   case GL_FLOAT:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 1;
      break;
   case GL_FLOAT_VEC2:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 2;
      break;
   case GL_FLOAT_VEC3:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 3;
      break;
   case GL_FLOAT_VEC4:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 4;
      break;
   case GL_UNSIGNED_INT:
      basicType = GLSL_TYPE_UINT;
      src_components = 1;
      break;
   case GL_UNSIGNED_INT_VEC2:
      basicType = GLSL_TYPE_UINT;
      src_components = 2;
      break;
   case GL_UNSIGNED_INT_VEC3:
      basicType = GLSL_TYPE_UINT;
      src_components = 3;
      break;
   case GL_UNSIGNED_INT_VEC4:
      basicType = GLSL_TYPE_UINT;
      src_components = 4;
      break;
   case GL_INT:
      basicType = GLSL_TYPE_INT;
      src_components = 1;
      break;
   case GL_INT_VEC2:
      basicType = GLSL_TYPE_INT;
      src_components = 2;
      break;
   case GL_INT_VEC3:
      basicType = GLSL_TYPE_INT;
      src_components = 3;
      break;
   case GL_INT_VEC4:
      basicType = GLSL_TYPE_INT;
      src_components = 4;
      break;
   case GL_BOOL:
   case GL_BOOL_VEC2:
   case GL_BOOL_VEC3:
   case GL_BOOL_VEC4:
   case GL_FLOAT_MAT2:
   case GL_FLOAT_MAT2x3:
   case GL_FLOAT_MAT2x4:
   case GL_FLOAT_MAT3x2:
   case GL_FLOAT_MAT3:
   case GL_FLOAT_MAT3x4:
   case GL_FLOAT_MAT4x2:
   case GL_FLOAT_MAT4x3:
   case GL_FLOAT_MAT4:
   default:
      _mesa_problem(NULL, "Invalid type in %s", __func__);
      return;
   }

   if (uni->type->is_sampler()) {
      components = 1;
   } else {
      components = uni->type->vector_elements;
   }

   bool match;
   switch (uni->type->base_type) {
   case GLSL_TYPE_BOOL:
      match = true;
      break;
   case GLSL_TYPE_SAMPLER:
      match = (basicType == GLSL_TYPE_INT);
      break;
   default:
      match = (basicType == uni->type->base_type);
      break;
   }

   if (uni->type->is_matrix() || components != src_components || !match) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
      return;
   }

   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
      log_uniform(values, basicType, components, 1, count,
		  false, shProg, location, uni);
   }

   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
    *
    *     "Setting a sampler's value to i selects texture image unit number
    *     i. The values of i range from zero to the implementation- dependent
    *     maximum supported number of texture image units."
    *
    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
    * the PDF) says:
    *
    *     "Error         Description                    Offending command
    *                                                   ignored?
    *     ...
    *     INVALID_VALUE  Numeric argument out of range  Yes"
    *
    * Based on that, when an invalid sampler is specified, we generate a
    * GL_INVALID_VALUE error and ignore the command.
    */
   if (uni->type->is_sampler()) {
      int i;

      for (i = 0; i < count; i++) {
	 const unsigned texUnit = ((unsigned *) values)[i];

         /* check that the sampler (tex unit index) is legal */
         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid sampler/tex unit index for "
			"uniform %d)",
                        location);
            return;
         }
      }
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      if (offset >= uni->array_elements)
	 return;

      count = MIN2(count, (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   if (!uni->type->is_boolean()) {
      memcpy(&uni->storage[components * offset], values,
	     sizeof(uni->storage[0]) * components * count);
   } else {
      const union gl_constant_value *src =
	 (const union gl_constant_value *) values;
      union gl_constant_value *dst = &uni->storage[components * offset];
      const unsigned elems = components * count;
      unsigned i;

      for (i = 0; i < elems; i++) {
	 if (basicType == GLSL_TYPE_FLOAT) {
	    dst[i].i = src[i].f != 0.0f ? 1 : 0;
	 } else {
	    dst[i].i = src[i].i != 0    ? 1 : 0;
	 }
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);

   /* If the uniform is a sampler, do the extra magic necessary to propagate
    * the changes through.
    */
   if (uni->type->is_sampler()) {
      int i;

      for (i = 0; i < count; i++) {
	 shProg->SamplerUnits[uni->sampler + offset + i] =
	    ((unsigned *) values)[i];
      }

      bool flushed = false;
      for (i = 0; i < MESA_SHADER_TYPES; i++) {
	 struct gl_program *prog;

	 if (shProg->_LinkedShaders[i] == NULL)
	    continue;

	 prog = shProg->_LinkedShaders[i]->Program;

	 /* If the shader stage doesn't use any samplers, don't bother
	  * checking if any samplers have changed.
	  */
	 if (prog->SamplersUsed == 0)
	    continue;

	 assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits));

	 /* Determine if any of the samplers used by this shader stage have
	  * been modified.
	  */
	 bool changed = false;
	 for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) {
	    if ((prog->SamplersUsed & (1U << j)) != 0
		&& (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) {
	       changed = true;
	       break;
	    }
	 }

	 if (changed) {
	    if (!flushed) {
	       FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
	       flushed = true;
	    }

	    memcpy(prog->SamplerUnits,
		   shProg->SamplerUnits,
		   sizeof(shProg->SamplerUnits));

	    _mesa_update_shader_textures_used(prog);
	    (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog);
	 }
      }
   }
}