1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 2004-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci * Copyright (C) 2009-2010  VMware, Inc.  All Rights Reserved.
6bf215546Sopenharmony_ci * Copyright © 2010, 2011 Intel Corporation
7bf215546Sopenharmony_ci *
8bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
9bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
10bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
11bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
13bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
16bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include <stdlib.h>
28bf215546Sopenharmony_ci#include <inttypes.h>  /* for PRIx64 macro */
29bf215546Sopenharmony_ci#include <math.h>
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "main/context.h"
32bf215546Sopenharmony_ci#include "main/draw_validate.h"
33bf215546Sopenharmony_ci#include "main/shaderapi.h"
34bf215546Sopenharmony_ci#include "main/shaderobj.h"
35bf215546Sopenharmony_ci#include "main/uniforms.h"
36bf215546Sopenharmony_ci#include "compiler/glsl/ir.h"
37bf215546Sopenharmony_ci#include "compiler/glsl/ir_uniform.h"
38bf215546Sopenharmony_ci#include "compiler/glsl/glsl_parser_extras.h"
39bf215546Sopenharmony_ci#include "compiler/glsl/program.h"
40bf215546Sopenharmony_ci#include "util/bitscan.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#include "state_tracker/st_context.h"
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/* This is one of the few glGet that can be called from the app thread safely.
45bf215546Sopenharmony_ci * Only these conditions must be met:
46bf215546Sopenharmony_ci * - There are no unfinished glLinkProgram and glDeleteProgram calls
47bf215546Sopenharmony_ci *   for the program object. This assures that the program object is immutable.
48bf215546Sopenharmony_ci * - glthread=true for GL errors to be passed to the driver thread safely
49bf215546Sopenharmony_ci *
50bf215546Sopenharmony_ci * Program objects can be looked up from any thread because they are part
51bf215546Sopenharmony_ci * of the multi-context shared state.
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_ciextern "C" void
54bf215546Sopenharmony_ci_mesa_GetActiveUniform_impl(GLuint program, GLuint index,
55bf215546Sopenharmony_ci                            GLsizei maxLength, GLsizei *length, GLint *size,
56bf215546Sopenharmony_ci                            GLenum *type, GLcharARB *nameOut, bool glthread)
57bf215546Sopenharmony_ci{
58bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
59bf215546Sopenharmony_ci   struct gl_shader_program *shProg;
60bf215546Sopenharmony_ci   struct gl_program_resource *res;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   if (maxLength < 0) {
63bf215546Sopenharmony_ci      _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread,
64bf215546Sopenharmony_ci                                "glGetActiveUniform(maxLength < 0)");
65bf215546Sopenharmony_ci      return;
66bf215546Sopenharmony_ci   }
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   shProg = _mesa_lookup_shader_program_err_glthread(ctx, program, glthread,
69bf215546Sopenharmony_ci                                                     "glGetActiveUniform");
70bf215546Sopenharmony_ci   if (!shProg)
71bf215546Sopenharmony_ci      return;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg,
74bf215546Sopenharmony_ci                                           GL_UNIFORM, index);
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   if (!res) {
77bf215546Sopenharmony_ci      _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread,
78bf215546Sopenharmony_ci                                "glGetActiveUniform(index)");
79bf215546Sopenharmony_ci      return;
80bf215546Sopenharmony_ci   }
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   if (nameOut)
83bf215546Sopenharmony_ci      _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength,
84bf215546Sopenharmony_ci                                      length, nameOut, glthread,
85bf215546Sopenharmony_ci                                      "glGetActiveUniform");
86bf215546Sopenharmony_ci   if (type)
87bf215546Sopenharmony_ci      _mesa_program_resource_prop((struct gl_shader_program *) shProg,
88bf215546Sopenharmony_ci                                  res, index, GL_TYPE, (GLint*) type,
89bf215546Sopenharmony_ci                                  glthread, "glGetActiveUniform");
90bf215546Sopenharmony_ci   if (size)
91bf215546Sopenharmony_ci      _mesa_program_resource_prop((struct gl_shader_program *) shProg,
92bf215546Sopenharmony_ci                                  res, index, GL_ARRAY_SIZE, (GLint*) size,
93bf215546Sopenharmony_ci                                  glthread, "glGetActiveUniform");
94bf215546Sopenharmony_ci}
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ciextern "C" void GLAPIENTRY
97bf215546Sopenharmony_ci_mesa_GetActiveUniform(GLuint program, GLuint index,
98bf215546Sopenharmony_ci                       GLsizei maxLength, GLsizei *length, GLint *size,
99bf215546Sopenharmony_ci                       GLenum *type, GLcharARB *nameOut)
100bf215546Sopenharmony_ci{
101bf215546Sopenharmony_ci   _mesa_GetActiveUniform_impl(program, index, maxLength, length, size,
102bf215546Sopenharmony_ci                               type, nameOut, false);
103bf215546Sopenharmony_ci}
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_cistatic GLenum
106bf215546Sopenharmony_ciresource_prop_from_uniform_prop(GLenum uni_prop)
107bf215546Sopenharmony_ci{
108bf215546Sopenharmony_ci   switch (uni_prop) {
109bf215546Sopenharmony_ci   case GL_UNIFORM_TYPE:
110bf215546Sopenharmony_ci      return GL_TYPE;
111bf215546Sopenharmony_ci   case GL_UNIFORM_SIZE:
112bf215546Sopenharmony_ci      return GL_ARRAY_SIZE;
113bf215546Sopenharmony_ci   case GL_UNIFORM_NAME_LENGTH:
114bf215546Sopenharmony_ci      return GL_NAME_LENGTH;
115bf215546Sopenharmony_ci   case GL_UNIFORM_BLOCK_INDEX:
116bf215546Sopenharmony_ci      return GL_BLOCK_INDEX;
117bf215546Sopenharmony_ci   case GL_UNIFORM_OFFSET:
118bf215546Sopenharmony_ci      return GL_OFFSET;
119bf215546Sopenharmony_ci   case GL_UNIFORM_ARRAY_STRIDE:
120bf215546Sopenharmony_ci      return GL_ARRAY_STRIDE;
121bf215546Sopenharmony_ci   case GL_UNIFORM_MATRIX_STRIDE:
122bf215546Sopenharmony_ci      return GL_MATRIX_STRIDE;
123bf215546Sopenharmony_ci   case GL_UNIFORM_IS_ROW_MAJOR:
124bf215546Sopenharmony_ci      return GL_IS_ROW_MAJOR;
125bf215546Sopenharmony_ci   case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX:
126bf215546Sopenharmony_ci      return GL_ATOMIC_COUNTER_BUFFER_INDEX;
127bf215546Sopenharmony_ci   default:
128bf215546Sopenharmony_ci      return 0;
129bf215546Sopenharmony_ci   }
130bf215546Sopenharmony_ci}
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ciextern "C" void GLAPIENTRY
133bf215546Sopenharmony_ci_mesa_GetActiveUniformsiv(GLuint program,
134bf215546Sopenharmony_ci			  GLsizei uniformCount,
135bf215546Sopenharmony_ci			  const GLuint *uniformIndices,
136bf215546Sopenharmony_ci			  GLenum pname,
137bf215546Sopenharmony_ci			  GLint *params)
138bf215546Sopenharmony_ci{
139bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
140bf215546Sopenharmony_ci   struct gl_shader_program *shProg;
141bf215546Sopenharmony_ci   struct gl_program_resource *res;
142bf215546Sopenharmony_ci   GLenum res_prop;
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   if (uniformCount < 0) {
145bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
146bf215546Sopenharmony_ci		  "glGetActiveUniformsiv(uniformCount < 0)");
147bf215546Sopenharmony_ci      return;
148bf215546Sopenharmony_ci   }
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
151bf215546Sopenharmony_ci   if (!shProg)
152bf215546Sopenharmony_ci      return;
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   res_prop = resource_prop_from_uniform_prop(pname);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   /* We need to first verify that each entry exists as active uniform. If
157bf215546Sopenharmony_ci    * not, generate error and do not cause any other side effects.
158bf215546Sopenharmony_ci    *
159bf215546Sopenharmony_ci    * In the case of and error condition, Page 16 (section 2.3.1 Errors)
160bf215546Sopenharmony_ci    * of the OpenGL 4.5 spec says:
161bf215546Sopenharmony_ci    *
162bf215546Sopenharmony_ci    *     "If the generating command modifies values through a pointer argu-
163bf215546Sopenharmony_ci    *     ment, no change is made to these values."
164bf215546Sopenharmony_ci    */
165bf215546Sopenharmony_ci   for (int i = 0; i < uniformCount; i++) {
166bf215546Sopenharmony_ci      if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM,
167bf215546Sopenharmony_ci                                              uniformIndices[i])) {
168bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)");
169bf215546Sopenharmony_ci         return;
170bf215546Sopenharmony_ci      }
171bf215546Sopenharmony_ci   }
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   for (int i = 0; i < uniformCount; i++) {
174bf215546Sopenharmony_ci      res = _mesa_program_resource_find_index(shProg, GL_UNIFORM,
175bf215546Sopenharmony_ci                                              uniformIndices[i]);
176bf215546Sopenharmony_ci      if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i],
177bf215546Sopenharmony_ci                                       res_prop, &params[i],
178bf215546Sopenharmony_ci                                       false, "glGetActiveUniformsiv"))
179bf215546Sopenharmony_ci         break;
180bf215546Sopenharmony_ci   }
181bf215546Sopenharmony_ci}
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_cistatic struct gl_uniform_storage *
184bf215546Sopenharmony_civalidate_uniform_parameters(GLint location, GLsizei count,
185bf215546Sopenharmony_ci                            unsigned *array_index,
186bf215546Sopenharmony_ci                            struct gl_context *ctx,
187bf215546Sopenharmony_ci                            struct gl_shader_program *shProg,
188bf215546Sopenharmony_ci                            const char *caller)
189bf215546Sopenharmony_ci{
190bf215546Sopenharmony_ci   if (shProg == NULL) {
191bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
192bf215546Sopenharmony_ci      return NULL;
193bf215546Sopenharmony_ci   }
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec:
196bf215546Sopenharmony_ci    *
197bf215546Sopenharmony_ci    *     "If a negative number is provided where an argument of type sizei or
198bf215546Sopenharmony_ci    *     sizeiptr is specified, the error INVALID_VALUE is generated."
199bf215546Sopenharmony_ci    */
200bf215546Sopenharmony_ci   if (count < 0) {
201bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller);
202bf215546Sopenharmony_ci      return NULL;
203bf215546Sopenharmony_ci   }
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   /* Check that the given location is in bounds of uniform remap table.
206bf215546Sopenharmony_ci    * Unlinked programs will have NumUniformRemapTable == 0, so we can take
207bf215546Sopenharmony_ci    * the shProg->data->LinkStatus check out of the main path.
208bf215546Sopenharmony_ci    */
209bf215546Sopenharmony_ci   if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) {
210bf215546Sopenharmony_ci      if (!shProg->data->LinkStatus)
211bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
212bf215546Sopenharmony_ci                     caller);
213bf215546Sopenharmony_ci      else
214bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
215bf215546Sopenharmony_ci                     caller, location);
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci      return NULL;
218bf215546Sopenharmony_ci   }
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   if (location == -1) {
221bf215546Sopenharmony_ci      if (!shProg->data->LinkStatus)
222bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
223bf215546Sopenharmony_ci                     caller);
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci      return NULL;
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
229bf215546Sopenharmony_ci    *
230bf215546Sopenharmony_ci    *     "If any of the following conditions occur, an INVALID_OPERATION
231bf215546Sopenharmony_ci    *     error is generated by the Uniform* commands, and no uniform values
232bf215546Sopenharmony_ci    *     are changed:
233bf215546Sopenharmony_ci    *
234bf215546Sopenharmony_ci    *     ...
235bf215546Sopenharmony_ci    *
236bf215546Sopenharmony_ci    *         - if no variable with a location of location exists in the
237bf215546Sopenharmony_ci    *           program object currently in use and location is not -1,
238bf215546Sopenharmony_ci    *         - if count is greater than one, and the uniform declared in the
239bf215546Sopenharmony_ci    *           shader is not an array variable,
240bf215546Sopenharmony_ci    */
241bf215546Sopenharmony_ci   if (location < -1 || !shProg->UniformRemapTable[location]) {
242bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
243bf215546Sopenharmony_ci                  caller, location);
244bf215546Sopenharmony_ci      return NULL;
245bf215546Sopenharmony_ci   }
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   /* If the driver storage pointer in remap table is -1, we ignore silently.
248bf215546Sopenharmony_ci    *
249bf215546Sopenharmony_ci    * GL_ARB_explicit_uniform_location spec says:
250bf215546Sopenharmony_ci    *     "What happens if Uniform* is called with an explicitly defined
251bf215546Sopenharmony_ci    *     uniform location, but that uniform is deemed inactive by the
252bf215546Sopenharmony_ci    *     linker?
253bf215546Sopenharmony_ci    *
254bf215546Sopenharmony_ci    *     RESOLVED: The call is ignored for inactive uniform variables and
255bf215546Sopenharmony_ci    *     no error is generated."
256bf215546Sopenharmony_ci    *
257bf215546Sopenharmony_ci    */
258bf215546Sopenharmony_ci   if (shProg->UniformRemapTable[location] ==
259bf215546Sopenharmony_ci       INACTIVE_UNIFORM_EXPLICIT_LOCATION)
260bf215546Sopenharmony_ci      return NULL;
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location];
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   /* Even though no location is assigned to a built-in uniform and this
265bf215546Sopenharmony_ci    * function should already have returned NULL, this test makes it explicit
266bf215546Sopenharmony_ci    * that we are not allowing to update the value of a built-in.
267bf215546Sopenharmony_ci    */
268bf215546Sopenharmony_ci   if (uni->builtin)
269bf215546Sopenharmony_ci      return NULL;
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   if (uni->array_elements == 0) {
272bf215546Sopenharmony_ci      if (count > 1) {
273bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
274bf215546Sopenharmony_ci                     "%s(count = %u for non-array \"%s\"@%d)",
275bf215546Sopenharmony_ci                     caller, count, uni->name.string, location);
276bf215546Sopenharmony_ci         return NULL;
277bf215546Sopenharmony_ci      }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci      assert((location - uni->remap_location) == 0);
280bf215546Sopenharmony_ci      *array_index = 0;
281bf215546Sopenharmony_ci   } else {
282bf215546Sopenharmony_ci      /* The array index specified by the uniform location is just the uniform
283bf215546Sopenharmony_ci       * location minus the base location of of the uniform.
284bf215546Sopenharmony_ci       */
285bf215546Sopenharmony_ci      *array_index = location - uni->remap_location;
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci      /* If the uniform is an array, check that array_index is in bounds.
288bf215546Sopenharmony_ci       * array_index is unsigned so no need to check for less than zero.
289bf215546Sopenharmony_ci       */
290bf215546Sopenharmony_ci      if (*array_index >= uni->array_elements) {
291bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
292bf215546Sopenharmony_ci                     caller, location);
293bf215546Sopenharmony_ci         return NULL;
294bf215546Sopenharmony_ci      }
295bf215546Sopenharmony_ci   }
296bf215546Sopenharmony_ci   return uni;
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci/**
300bf215546Sopenharmony_ci * Called via glGetUniform[fiui]v() to get the current value of a uniform.
301bf215546Sopenharmony_ci */
302bf215546Sopenharmony_ciextern "C" void
303bf215546Sopenharmony_ci_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
304bf215546Sopenharmony_ci		  GLsizei bufSize, enum glsl_base_type returnType,
305bf215546Sopenharmony_ci		  GLvoid *paramsOut)
306bf215546Sopenharmony_ci{
307bf215546Sopenharmony_ci   struct gl_shader_program *shProg =
308bf215546Sopenharmony_ci      _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
309bf215546Sopenharmony_ci   unsigned offset;
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   struct gl_uniform_storage *const uni =
312bf215546Sopenharmony_ci      validate_uniform_parameters(location, 1, &offset,
313bf215546Sopenharmony_ci                                  ctx, shProg, "glGetUniform");
314bf215546Sopenharmony_ci   if (uni == NULL) {
315bf215546Sopenharmony_ci      /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
316bf215546Sopenharmony_ci       * spec says:
317bf215546Sopenharmony_ci       *
318bf215546Sopenharmony_ci       *     "The error INVALID_OPERATION is generated if program has not been
319bf215546Sopenharmony_ci       *     linked successfully, or if location is not a valid location for
320bf215546Sopenharmony_ci       *     program."
321bf215546Sopenharmony_ci       *
322bf215546Sopenharmony_ci       * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec
323bf215546Sopenharmony_ci       * says:
324bf215546Sopenharmony_ci       *
325bf215546Sopenharmony_ci       *     "If the value of location is -1, the Uniform* commands will
326bf215546Sopenharmony_ci       *     silently ignore the data passed in, and the current uniform
327bf215546Sopenharmony_ci       *     values will not be changed."
328bf215546Sopenharmony_ci       *
329bf215546Sopenharmony_ci       * Allowing -1 for the location parameter of glUniform allows
330bf215546Sopenharmony_ci       * applications to avoid error paths in the case that, for example, some
331bf215546Sopenharmony_ci       * uniform variable is removed by the compiler / linker after
332bf215546Sopenharmony_ci       * optimization.  In this case, the new value of the uniform is dropped
333bf215546Sopenharmony_ci       * on the floor.  For the case of glGetUniform, there is nothing
334bf215546Sopenharmony_ci       * sensible to do for a location of -1.
335bf215546Sopenharmony_ci       *
336bf215546Sopenharmony_ci       * If the location was -1, validate_unfirom_parameters will return NULL
337bf215546Sopenharmony_ci       * without raising an error.  Raise the error here.
338bf215546Sopenharmony_ci       */
339bf215546Sopenharmony_ci      if (location == -1) {
340bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)",
341bf215546Sopenharmony_ci                     location);
342bf215546Sopenharmony_ci      }
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci      return;
345bf215546Sopenharmony_ci   }
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   {
348bf215546Sopenharmony_ci      unsigned elements = uni->type->components();
349bf215546Sopenharmony_ci      unsigned components = uni->type->vector_elements;
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci      const int rmul = glsl_base_type_is_64bit(returnType) ? 2 : 1;
352bf215546Sopenharmony_ci      int dmul = (uni->type->is_64bit()) ? 2 : 1;
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci      if ((uni->type->is_sampler() || uni->type->is_image()) &&
355bf215546Sopenharmony_ci          !uni->is_bindless) {
356bf215546Sopenharmony_ci         /* Non-bindless samplers/images are represented using unsigned integer
357bf215546Sopenharmony_ci          * 32-bit, while bindless handles are 64-bit.
358bf215546Sopenharmony_ci          */
359bf215546Sopenharmony_ci         dmul = 1;
360bf215546Sopenharmony_ci      }
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci      /* Calculate the source base address *BEFORE* modifying elements to
363bf215546Sopenharmony_ci       * account for the size of the user's buffer.
364bf215546Sopenharmony_ci       */
365bf215546Sopenharmony_ci      const union gl_constant_value *src;
366bf215546Sopenharmony_ci      if (ctx->Const.PackedDriverUniformStorage &&
367bf215546Sopenharmony_ci          (uni->is_bindless || !uni->type->contains_opaque())) {
368bf215546Sopenharmony_ci         unsigned dword_elements = elements;
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci         /* 16-bit uniforms are packed. */
371bf215546Sopenharmony_ci         if (glsl_base_type_is_16bit(uni->type->base_type)) {
372bf215546Sopenharmony_ci            dword_elements = DIV_ROUND_UP(components, 2) *
373bf215546Sopenharmony_ci                             uni->type->matrix_columns;
374bf215546Sopenharmony_ci         }
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci         src = (gl_constant_value *) uni->driver_storage[0].data +
377bf215546Sopenharmony_ci            (offset * dword_elements * dmul);
378bf215546Sopenharmony_ci      } else {
379bf215546Sopenharmony_ci         src = &uni->storage[offset * elements * dmul];
380bf215546Sopenharmony_ci      }
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci      assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT ||
383bf215546Sopenharmony_ci             returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE ||
384bf215546Sopenharmony_ci             returnType == GLSL_TYPE_UINT64 || returnType == GLSL_TYPE_INT64);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci      /* doubles have a different size than the other 3 types */
387bf215546Sopenharmony_ci      unsigned bytes = sizeof(src[0]) * elements * rmul;
388bf215546Sopenharmony_ci      if (bufSize < 0 || bytes > (unsigned) bufSize) {
389bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
390bf215546Sopenharmony_ci                     "glGetnUniform*vARB(out of bounds: bufSize is %d,"
391bf215546Sopenharmony_ci                     " but %u bytes are required)", bufSize, bytes);
392bf215546Sopenharmony_ci         return;
393bf215546Sopenharmony_ci      }
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci      /* If the return type and the uniform's native type are "compatible,"
396bf215546Sopenharmony_ci       * just memcpy the data.  If the types are not compatible, perform a
397bf215546Sopenharmony_ci       * slower convert-and-copy process.
398bf215546Sopenharmony_ci       */
399bf215546Sopenharmony_ci      if (returnType == uni->type->base_type ||
400bf215546Sopenharmony_ci          ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) &&
401bf215546Sopenharmony_ci           (uni->type->is_sampler() || uni->type->is_image())) ||
402bf215546Sopenharmony_ci          (returnType == GLSL_TYPE_UINT64 && uni->is_bindless)) {
403bf215546Sopenharmony_ci         memcpy(paramsOut, src, bytes);
404bf215546Sopenharmony_ci      } else {
405bf215546Sopenharmony_ci         union gl_constant_value *const dst =
406bf215546Sopenharmony_ci            (union gl_constant_value *) paramsOut;
407bf215546Sopenharmony_ci         /* This code could be optimized by putting the loop inside the switch
408bf215546Sopenharmony_ci          * statements.  However, this is not expected to be
409bf215546Sopenharmony_ci          * performance-critical code.
410bf215546Sopenharmony_ci          */
411bf215546Sopenharmony_ci         for (unsigned i = 0; i < elements; i++) {
412bf215546Sopenharmony_ci            int sidx = i * dmul;
413bf215546Sopenharmony_ci            int didx = i * rmul;
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci            if (glsl_base_type_is_16bit(uni->type->base_type)) {
416bf215546Sopenharmony_ci               unsigned column = i / components;
417bf215546Sopenharmony_ci               unsigned row = i % components;
418bf215546Sopenharmony_ci               sidx = column * align(components, 2) + row;
419bf215546Sopenharmony_ci            }
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci            switch (returnType) {
422bf215546Sopenharmony_ci            case GLSL_TYPE_FLOAT:
423bf215546Sopenharmony_ci               switch (uni->type->base_type) {
424bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16:
425bf215546Sopenharmony_ci                  dst[didx].f = _mesa_half_to_float(((uint16_t*)src)[sidx]);
426bf215546Sopenharmony_ci                  break;
427bf215546Sopenharmony_ci               case GLSL_TYPE_UINT:
428bf215546Sopenharmony_ci                  dst[didx].f = (float) src[sidx].u;
429bf215546Sopenharmony_ci                  break;
430bf215546Sopenharmony_ci               case GLSL_TYPE_INT:
431bf215546Sopenharmony_ci               case GLSL_TYPE_SAMPLER:
432bf215546Sopenharmony_ci               case GLSL_TYPE_IMAGE:
433bf215546Sopenharmony_ci                  dst[didx].f = (float) src[sidx].i;
434bf215546Sopenharmony_ci                  break;
435bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL:
436bf215546Sopenharmony_ci                  dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
437bf215546Sopenharmony_ci                  break;
438bf215546Sopenharmony_ci               case GLSL_TYPE_DOUBLE: {
439bf215546Sopenharmony_ci                  double tmp;
440bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].f, sizeof(tmp));
441bf215546Sopenharmony_ci                  dst[didx].f = tmp;
442bf215546Sopenharmony_ci                  break;
443bf215546Sopenharmony_ci               }
444bf215546Sopenharmony_ci               case GLSL_TYPE_UINT64: {
445bf215546Sopenharmony_ci                  uint64_t tmp;
446bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].u, sizeof(tmp));
447bf215546Sopenharmony_ci                  dst[didx].f = tmp;
448bf215546Sopenharmony_ci                  break;
449bf215546Sopenharmony_ci                }
450bf215546Sopenharmony_ci               case GLSL_TYPE_INT64: {
451bf215546Sopenharmony_ci                  uint64_t tmp;
452bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].i, sizeof(tmp));
453bf215546Sopenharmony_ci                  dst[didx].f = tmp;
454bf215546Sopenharmony_ci                  break;
455bf215546Sopenharmony_ci               }
456bf215546Sopenharmony_ci               default:
457bf215546Sopenharmony_ci                  assert(!"Should not get here.");
458bf215546Sopenharmony_ci                  break;
459bf215546Sopenharmony_ci               }
460bf215546Sopenharmony_ci               break;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci            case GLSL_TYPE_DOUBLE:
463bf215546Sopenharmony_ci               switch (uni->type->base_type) {
464bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16: {
465bf215546Sopenharmony_ci                  double f = _mesa_half_to_float(((uint16_t*)src)[sidx]);
466bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &f, sizeof(f));
467bf215546Sopenharmony_ci                  break;
468bf215546Sopenharmony_ci               }
469bf215546Sopenharmony_ci               case GLSL_TYPE_UINT: {
470bf215546Sopenharmony_ci                  double tmp = src[sidx].u;
471bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
472bf215546Sopenharmony_ci                  break;
473bf215546Sopenharmony_ci               }
474bf215546Sopenharmony_ci               case GLSL_TYPE_INT:
475bf215546Sopenharmony_ci               case GLSL_TYPE_SAMPLER:
476bf215546Sopenharmony_ci               case GLSL_TYPE_IMAGE: {
477bf215546Sopenharmony_ci                  double tmp = src[sidx].i;
478bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
479bf215546Sopenharmony_ci                  break;
480bf215546Sopenharmony_ci               }
481bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL: {
482bf215546Sopenharmony_ci                  double tmp = src[sidx].i ? 1.0 : 0.0;
483bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
484bf215546Sopenharmony_ci                  break;
485bf215546Sopenharmony_ci               }
486bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT: {
487bf215546Sopenharmony_ci                  double tmp = src[sidx].f;
488bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
489bf215546Sopenharmony_ci                  break;
490bf215546Sopenharmony_ci               }
491bf215546Sopenharmony_ci               case GLSL_TYPE_UINT64: {
492bf215546Sopenharmony_ci                  uint64_t tmpu;
493bf215546Sopenharmony_ci                  double tmp;
494bf215546Sopenharmony_ci                  memcpy(&tmpu, &src[sidx].u, sizeof(tmpu));
495bf215546Sopenharmony_ci                  tmp = tmpu;
496bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
497bf215546Sopenharmony_ci                  break;
498bf215546Sopenharmony_ci               }
499bf215546Sopenharmony_ci               case GLSL_TYPE_INT64: {
500bf215546Sopenharmony_ci                  int64_t tmpi;
501bf215546Sopenharmony_ci                  double tmp;
502bf215546Sopenharmony_ci                  memcpy(&tmpi, &src[sidx].i, sizeof(tmpi));
503bf215546Sopenharmony_ci                  tmp = tmpi;
504bf215546Sopenharmony_ci                  memcpy(&dst[didx].f, &tmp, sizeof(tmp));
505bf215546Sopenharmony_ci                  break;
506bf215546Sopenharmony_ci               }
507bf215546Sopenharmony_ci               default:
508bf215546Sopenharmony_ci                  assert(!"Should not get here.");
509bf215546Sopenharmony_ci                  break;
510bf215546Sopenharmony_ci               }
511bf215546Sopenharmony_ci               break;
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci            case GLSL_TYPE_INT:
514bf215546Sopenharmony_ci               switch (uni->type->base_type) {
515bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT:
516bf215546Sopenharmony_ci                  /* While the GL 3.2 core spec doesn't explicitly
517bf215546Sopenharmony_ci                   * state how conversion of float uniforms to integer
518bf215546Sopenharmony_ci                   * values works, in section 6.2 "State Tables" on
519bf215546Sopenharmony_ci                   * page 267 it says:
520bf215546Sopenharmony_ci                   *
521bf215546Sopenharmony_ci                   *     "Unless otherwise specified, when floating
522bf215546Sopenharmony_ci                   *      point state is returned as integer values or
523bf215546Sopenharmony_ci                   *      integer state is returned as floating-point
524bf215546Sopenharmony_ci                   *      values it is converted in the fashion
525bf215546Sopenharmony_ci                   *      described in section 6.1.2"
526bf215546Sopenharmony_ci                   *
527bf215546Sopenharmony_ci                   * That section, on page 248, says:
528bf215546Sopenharmony_ci                   *
529bf215546Sopenharmony_ci                   *     "If GetIntegerv or GetInteger64v are called,
530bf215546Sopenharmony_ci                   *      a floating-point value is rounded to the
531bf215546Sopenharmony_ci                   *      nearest integer..."
532bf215546Sopenharmony_ci                   */
533bf215546Sopenharmony_ci                  dst[didx].i = (int64_t) roundf(src[sidx].f);
534bf215546Sopenharmony_ci                  break;
535bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16:
536bf215546Sopenharmony_ci                  dst[didx].i =
537bf215546Sopenharmony_ci                     (int64_t)roundf(_mesa_half_to_float(((uint16_t*)src)[sidx]));
538bf215546Sopenharmony_ci                  break;
539bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL:
540bf215546Sopenharmony_ci                  dst[didx].i = src[sidx].i ? 1 : 0;
541bf215546Sopenharmony_ci                  break;
542bf215546Sopenharmony_ci               case GLSL_TYPE_UINT:
543bf215546Sopenharmony_ci                  dst[didx].i = MIN2(src[sidx].i, INT_MAX);
544bf215546Sopenharmony_ci                  break;
545bf215546Sopenharmony_ci               case GLSL_TYPE_DOUBLE: {
546bf215546Sopenharmony_ci                  double tmp;
547bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].f, sizeof(tmp));
548bf215546Sopenharmony_ci                  dst[didx].i = (int64_t) round(tmp);
549bf215546Sopenharmony_ci                  break;
550bf215546Sopenharmony_ci               }
551bf215546Sopenharmony_ci               case GLSL_TYPE_UINT64: {
552bf215546Sopenharmony_ci                  uint64_t tmp;
553bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].u, sizeof(tmp));
554bf215546Sopenharmony_ci                  dst[didx].i = tmp;
555bf215546Sopenharmony_ci                  break;
556bf215546Sopenharmony_ci               }
557bf215546Sopenharmony_ci               case GLSL_TYPE_INT64: {
558bf215546Sopenharmony_ci                  int64_t tmp;
559bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].i, sizeof(tmp));
560bf215546Sopenharmony_ci                  dst[didx].i = tmp;
561bf215546Sopenharmony_ci                  break;
562bf215546Sopenharmony_ci               }
563bf215546Sopenharmony_ci               default:
564bf215546Sopenharmony_ci                  assert(!"Should not get here.");
565bf215546Sopenharmony_ci                  break;
566bf215546Sopenharmony_ci               }
567bf215546Sopenharmony_ci               break;
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci            case GLSL_TYPE_UINT:
570bf215546Sopenharmony_ci               switch (uni->type->base_type) {
571bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT:
572bf215546Sopenharmony_ci                  /* The spec isn't terribly clear how to handle negative
573bf215546Sopenharmony_ci                   * values with an unsigned return type.
574bf215546Sopenharmony_ci                   *
575bf215546Sopenharmony_ci                   * GL 4.5 section 2.2.2 ("Data Conversions for State
576bf215546Sopenharmony_ci                   * Query Commands") says:
577bf215546Sopenharmony_ci                   *
578bf215546Sopenharmony_ci                   * "If a value is so large in magnitude that it cannot be
579bf215546Sopenharmony_ci                   *  represented by the returned data type, then the nearest
580bf215546Sopenharmony_ci                   *  value representable using the requested type is
581bf215546Sopenharmony_ci                   *  returned."
582bf215546Sopenharmony_ci                   */
583bf215546Sopenharmony_ci                  dst[didx].u = src[sidx].f < 0.0f ?
584bf215546Sopenharmony_ci                     0u : (uint32_t) roundf(src[sidx].f);
585bf215546Sopenharmony_ci                  break;
586bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16: {
587bf215546Sopenharmony_ci                  float f = _mesa_half_to_float(((uint16_t*)src)[sidx]);
588bf215546Sopenharmony_ci                  dst[didx].u = f < 0.0f ? 0u : (uint32_t)roundf(f);
589bf215546Sopenharmony_ci                  break;
590bf215546Sopenharmony_ci               }
591bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL:
592bf215546Sopenharmony_ci                  dst[didx].i = src[sidx].i ? 1 : 0;
593bf215546Sopenharmony_ci                  break;
594bf215546Sopenharmony_ci               case GLSL_TYPE_INT:
595bf215546Sopenharmony_ci                  dst[didx].i = MAX2(src[sidx].i, 0);
596bf215546Sopenharmony_ci                  break;
597bf215546Sopenharmony_ci               case GLSL_TYPE_DOUBLE: {
598bf215546Sopenharmony_ci                  double tmp;
599bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].f, sizeof(tmp));
600bf215546Sopenharmony_ci                  dst[didx].u = tmp < 0.0 ? 0u : (uint32_t) round(tmp);
601bf215546Sopenharmony_ci                  break;
602bf215546Sopenharmony_ci               }
603bf215546Sopenharmony_ci               case GLSL_TYPE_UINT64: {
604bf215546Sopenharmony_ci                  uint64_t tmp;
605bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].u, sizeof(tmp));
606bf215546Sopenharmony_ci                  dst[didx].i = MIN2(tmp, INT_MAX);
607bf215546Sopenharmony_ci                  break;
608bf215546Sopenharmony_ci               }
609bf215546Sopenharmony_ci               case GLSL_TYPE_INT64: {
610bf215546Sopenharmony_ci                  int64_t tmp;
611bf215546Sopenharmony_ci                  memcpy(&tmp, &src[sidx].i, sizeof(tmp));
612bf215546Sopenharmony_ci                  dst[didx].i = MAX2(tmp, 0);
613bf215546Sopenharmony_ci                  break;
614bf215546Sopenharmony_ci               }
615bf215546Sopenharmony_ci               default:
616bf215546Sopenharmony_ci                  unreachable("invalid uniform type");
617bf215546Sopenharmony_ci               }
618bf215546Sopenharmony_ci               break;
619bf215546Sopenharmony_ci
620bf215546Sopenharmony_ci            case GLSL_TYPE_INT64:
621bf215546Sopenharmony_ci               switch (uni->type->base_type) {
622bf215546Sopenharmony_ci               case GLSL_TYPE_UINT: {
623bf215546Sopenharmony_ci                  uint64_t tmp = src[sidx].u;
624bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
625bf215546Sopenharmony_ci                  break;
626bf215546Sopenharmony_ci               }
627bf215546Sopenharmony_ci               case GLSL_TYPE_INT:
628bf215546Sopenharmony_ci               case GLSL_TYPE_SAMPLER:
629bf215546Sopenharmony_ci               case GLSL_TYPE_IMAGE: {
630bf215546Sopenharmony_ci                  int64_t tmp = src[sidx].i;
631bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
632bf215546Sopenharmony_ci                  break;
633bf215546Sopenharmony_ci               }
634bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL: {
635bf215546Sopenharmony_ci                  int64_t tmp = src[sidx].i ? 1.0f : 0.0f;
636bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
637bf215546Sopenharmony_ci                  break;
638bf215546Sopenharmony_ci               }
639bf215546Sopenharmony_ci               case GLSL_TYPE_UINT64: {
640bf215546Sopenharmony_ci                  uint64_t u64;
641bf215546Sopenharmony_ci                  memcpy(&u64, &src[sidx].u, sizeof(u64));
642bf215546Sopenharmony_ci                  int64_t tmp = MIN2(u64, INT_MAX);
643bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
644bf215546Sopenharmony_ci                  break;
645bf215546Sopenharmony_ci               }
646bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT: {
647bf215546Sopenharmony_ci                  int64_t tmp = (int64_t) roundf(src[sidx].f);
648bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
649bf215546Sopenharmony_ci                  break;
650bf215546Sopenharmony_ci               }
651bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16: {
652bf215546Sopenharmony_ci                  float f = _mesa_half_to_float(((uint16_t*)src)[sidx]);
653bf215546Sopenharmony_ci                  int64_t tmp = (int64_t) roundf(f);
654bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
655bf215546Sopenharmony_ci                  break;
656bf215546Sopenharmony_ci               }
657bf215546Sopenharmony_ci               case GLSL_TYPE_DOUBLE: {
658bf215546Sopenharmony_ci                  double d;
659bf215546Sopenharmony_ci                  memcpy(&d, &src[sidx].f, sizeof(d));
660bf215546Sopenharmony_ci                  int64_t tmp = (int64_t) round(d);
661bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
662bf215546Sopenharmony_ci                  break;
663bf215546Sopenharmony_ci               }
664bf215546Sopenharmony_ci               default:
665bf215546Sopenharmony_ci                  assert(!"Should not get here.");
666bf215546Sopenharmony_ci                  break;
667bf215546Sopenharmony_ci               }
668bf215546Sopenharmony_ci               break;
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci            case GLSL_TYPE_UINT64:
671bf215546Sopenharmony_ci               switch (uni->type->base_type) {
672bf215546Sopenharmony_ci               case GLSL_TYPE_UINT: {
673bf215546Sopenharmony_ci                  uint64_t tmp = src[sidx].u;
674bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
675bf215546Sopenharmony_ci                  break;
676bf215546Sopenharmony_ci               }
677bf215546Sopenharmony_ci               case GLSL_TYPE_INT:
678bf215546Sopenharmony_ci               case GLSL_TYPE_SAMPLER:
679bf215546Sopenharmony_ci               case GLSL_TYPE_IMAGE: {
680bf215546Sopenharmony_ci                  int64_t tmp = MAX2(src[sidx].i, 0);
681bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
682bf215546Sopenharmony_ci                  break;
683bf215546Sopenharmony_ci               }
684bf215546Sopenharmony_ci               case GLSL_TYPE_BOOL: {
685bf215546Sopenharmony_ci                  int64_t tmp = src[sidx].i ? 1.0f : 0.0f;
686bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
687bf215546Sopenharmony_ci                  break;
688bf215546Sopenharmony_ci               }
689bf215546Sopenharmony_ci               case GLSL_TYPE_INT64: {
690bf215546Sopenharmony_ci                  uint64_t i64;
691bf215546Sopenharmony_ci                  memcpy(&i64, &src[sidx].i, sizeof(i64));
692bf215546Sopenharmony_ci                  uint64_t tmp = MAX2(i64, 0);
693bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
694bf215546Sopenharmony_ci                  break;
695bf215546Sopenharmony_ci               }
696bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT: {
697bf215546Sopenharmony_ci                  uint64_t tmp = src[sidx].f < 0.0f ?
698bf215546Sopenharmony_ci                     0ull : (uint64_t) roundf(src[sidx].f);
699bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
700bf215546Sopenharmony_ci                  break;
701bf215546Sopenharmony_ci               }
702bf215546Sopenharmony_ci               case GLSL_TYPE_FLOAT16: {
703bf215546Sopenharmony_ci                  float f = _mesa_half_to_float(((uint16_t*)src)[sidx]);
704bf215546Sopenharmony_ci                  uint64_t tmp = f < 0.0f ? 0ull : (uint64_t) roundf(f);
705bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
706bf215546Sopenharmony_ci                  break;
707bf215546Sopenharmony_ci               }
708bf215546Sopenharmony_ci               case GLSL_TYPE_DOUBLE: {
709bf215546Sopenharmony_ci                  double d;
710bf215546Sopenharmony_ci                  memcpy(&d, &src[sidx].f, sizeof(d));
711bf215546Sopenharmony_ci                  uint64_t tmp = (d < 0.0) ? 0ull : (uint64_t) round(d);
712bf215546Sopenharmony_ci                  memcpy(&dst[didx].u, &tmp, sizeof(tmp));
713bf215546Sopenharmony_ci                  break;
714bf215546Sopenharmony_ci               }
715bf215546Sopenharmony_ci               default:
716bf215546Sopenharmony_ci                  assert(!"Should not get here.");
717bf215546Sopenharmony_ci                  break;
718bf215546Sopenharmony_ci               }
719bf215546Sopenharmony_ci               break;
720bf215546Sopenharmony_ci
721bf215546Sopenharmony_ci            default:
722bf215546Sopenharmony_ci               assert(!"Should not get here.");
723bf215546Sopenharmony_ci               break;
724bf215546Sopenharmony_ci            }
725bf215546Sopenharmony_ci         }
726bf215546Sopenharmony_ci      }
727bf215546Sopenharmony_ci   }
728bf215546Sopenharmony_ci}
729bf215546Sopenharmony_ci
730bf215546Sopenharmony_cistatic void
731bf215546Sopenharmony_cilog_uniform(const void *values, enum glsl_base_type basicType,
732bf215546Sopenharmony_ci	    unsigned rows, unsigned cols, unsigned count,
733bf215546Sopenharmony_ci	    bool transpose,
734bf215546Sopenharmony_ci	    const struct gl_shader_program *shProg,
735bf215546Sopenharmony_ci	    GLint location,
736bf215546Sopenharmony_ci	    const struct gl_uniform_storage *uni)
737bf215546Sopenharmony_ci{
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   const union gl_constant_value *v = (const union gl_constant_value *) values;
740bf215546Sopenharmony_ci   const unsigned elems = rows * cols * count;
741bf215546Sopenharmony_ci   const char *const extra = (cols == 1) ? "uniform" : "uniform matrix";
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci   printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", "
744bf215546Sopenharmony_ci	  "transpose = %s) to: ",
745bf215546Sopenharmony_ci	  shProg->Name, extra, uni->name.string, location, uni->type->name,
746bf215546Sopenharmony_ci	  transpose ? "true" : "false");
747bf215546Sopenharmony_ci   for (unsigned i = 0; i < elems; i++) {
748bf215546Sopenharmony_ci      if (i != 0 && ((i % rows) == 0))
749bf215546Sopenharmony_ci	 printf(", ");
750bf215546Sopenharmony_ci
751bf215546Sopenharmony_ci      switch (basicType) {
752bf215546Sopenharmony_ci      case GLSL_TYPE_UINT:
753bf215546Sopenharmony_ci	 printf("%u ", v[i].u);
754bf215546Sopenharmony_ci	 break;
755bf215546Sopenharmony_ci      case GLSL_TYPE_INT:
756bf215546Sopenharmony_ci	 printf("%d ", v[i].i);
757bf215546Sopenharmony_ci	 break;
758bf215546Sopenharmony_ci      case GLSL_TYPE_UINT64: {
759bf215546Sopenharmony_ci         uint64_t tmp;
760bf215546Sopenharmony_ci         memcpy(&tmp, &v[i * 2].u, sizeof(tmp));
761bf215546Sopenharmony_ci         printf("%" PRIu64 " ", tmp);
762bf215546Sopenharmony_ci         break;
763bf215546Sopenharmony_ci      }
764bf215546Sopenharmony_ci      case GLSL_TYPE_INT64: {
765bf215546Sopenharmony_ci         int64_t tmp;
766bf215546Sopenharmony_ci         memcpy(&tmp, &v[i * 2].u, sizeof(tmp));
767bf215546Sopenharmony_ci         printf("%" PRId64 " ", tmp);
768bf215546Sopenharmony_ci         break;
769bf215546Sopenharmony_ci      }
770bf215546Sopenharmony_ci      case GLSL_TYPE_FLOAT:
771bf215546Sopenharmony_ci	 printf("%g ", v[i].f);
772bf215546Sopenharmony_ci	 break;
773bf215546Sopenharmony_ci      case GLSL_TYPE_DOUBLE: {
774bf215546Sopenharmony_ci         double tmp;
775bf215546Sopenharmony_ci         memcpy(&tmp, &v[i * 2].f, sizeof(tmp));
776bf215546Sopenharmony_ci         printf("%g ", tmp);
777bf215546Sopenharmony_ci         break;
778bf215546Sopenharmony_ci      }
779bf215546Sopenharmony_ci      default:
780bf215546Sopenharmony_ci	 assert(!"Should not get here.");
781bf215546Sopenharmony_ci	 break;
782bf215546Sopenharmony_ci      }
783bf215546Sopenharmony_ci   }
784bf215546Sopenharmony_ci   printf("\n");
785bf215546Sopenharmony_ci   fflush(stdout);
786bf215546Sopenharmony_ci}
787bf215546Sopenharmony_ci
788bf215546Sopenharmony_ci#if 0
789bf215546Sopenharmony_cistatic void
790bf215546Sopenharmony_cilog_program_parameters(const struct gl_shader_program *shProg)
791bf215546Sopenharmony_ci{
792bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
793bf215546Sopenharmony_ci      if (shProg->_LinkedShaders[i] == NULL)
794bf215546Sopenharmony_ci	 continue;
795bf215546Sopenharmony_ci
796bf215546Sopenharmony_ci      const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program;
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci      printf("Program %d %s shader parameters:\n",
799bf215546Sopenharmony_ci             shProg->Name, _mesa_shader_stage_to_string(i));
800bf215546Sopenharmony_ci      for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) {
801bf215546Sopenharmony_ci         unsigned pvo = prog->Parameters->ParameterValueOffset[j];
802bf215546Sopenharmony_ci         printf("%s: %u %p %f %f %f %f\n",
803bf215546Sopenharmony_ci		prog->Parameters->Parameters[j].Name,
804bf215546Sopenharmony_ci                pvo,
805bf215546Sopenharmony_ci                prog->Parameters->ParameterValues + pvo,
806bf215546Sopenharmony_ci                prog->Parameters->ParameterValues[pvo].f,
807bf215546Sopenharmony_ci                prog->Parameters->ParameterValues[pvo + 1].f,
808bf215546Sopenharmony_ci                prog->Parameters->ParameterValues[pvo + 2].f,
809bf215546Sopenharmony_ci                prog->Parameters->ParameterValues[pvo + 3].f);
810bf215546Sopenharmony_ci      }
811bf215546Sopenharmony_ci   }
812bf215546Sopenharmony_ci   fflush(stdout);
813bf215546Sopenharmony_ci}
814bf215546Sopenharmony_ci#endif
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_ci/**
817bf215546Sopenharmony_ci * Propagate some values from uniform backing storage to driver storage
818bf215546Sopenharmony_ci *
819bf215546Sopenharmony_ci * Values propagated from uniform backing storage to driver storage
820bf215546Sopenharmony_ci * have all format / type conversions previously requested by the
821bf215546Sopenharmony_ci * driver applied.  This function is most often called by the
822bf215546Sopenharmony_ci * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f,
823bf215546Sopenharmony_ci * etc.
824bf215546Sopenharmony_ci *
825bf215546Sopenharmony_ci * \param uni          Uniform whose data is to be propagated to driver storage
826bf215546Sopenharmony_ci * \param array_index  If \c uni is an array, this is the element of
827bf215546Sopenharmony_ci *                     the array to be propagated.
828bf215546Sopenharmony_ci * \param count        Number of array elements to propagate.
829bf215546Sopenharmony_ci */
830bf215546Sopenharmony_ciextern "C" void
831bf215546Sopenharmony_ci_mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
832bf215546Sopenharmony_ci					   unsigned array_index,
833bf215546Sopenharmony_ci					   unsigned count)
834bf215546Sopenharmony_ci{
835bf215546Sopenharmony_ci   unsigned i;
836bf215546Sopenharmony_ci
837bf215546Sopenharmony_ci   const unsigned components = uni->type->vector_elements;
838bf215546Sopenharmony_ci   const unsigned vectors = uni->type->matrix_columns;
839bf215546Sopenharmony_ci   const int dmul = uni->type->is_64bit() ? 2 : 1;
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_ci   /* Store the data in the driver's requested type in the driver's storage
842bf215546Sopenharmony_ci    * areas.
843bf215546Sopenharmony_ci    */
844bf215546Sopenharmony_ci   unsigned src_vector_byte_stride = components * 4 * dmul;
845bf215546Sopenharmony_ci
846bf215546Sopenharmony_ci   for (i = 0; i < uni->num_driver_storage; i++) {
847bf215546Sopenharmony_ci      struct gl_uniform_driver_storage *const store = &uni->driver_storage[i];
848bf215546Sopenharmony_ci      uint8_t *dst = (uint8_t *) store->data;
849bf215546Sopenharmony_ci      const unsigned extra_stride =
850bf215546Sopenharmony_ci	 store->element_stride - (vectors * store->vector_stride);
851bf215546Sopenharmony_ci      const uint8_t *src =
852bf215546Sopenharmony_ci	 (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i);
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci#if 0
855bf215546Sopenharmony_ci      printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u "
856bf215546Sopenharmony_ci	     "extra_stride=%u\n",
857bf215546Sopenharmony_ci	     __func__, dst, array_index, components,
858bf215546Sopenharmony_ci	     vectors, count, store->vector_stride, extra_stride);
859bf215546Sopenharmony_ci#endif
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci      dst += array_index * store->element_stride;
862bf215546Sopenharmony_ci
863bf215546Sopenharmony_ci      switch (store->format) {
864bf215546Sopenharmony_ci      case uniform_native: {
865bf215546Sopenharmony_ci	 unsigned j;
866bf215546Sopenharmony_ci	 unsigned v;
867bf215546Sopenharmony_ci
868bf215546Sopenharmony_ci	 if (src_vector_byte_stride == store->vector_stride) {
869bf215546Sopenharmony_ci	    if (extra_stride) {
870bf215546Sopenharmony_ci	       for (j = 0; j < count; j++) {
871bf215546Sopenharmony_ci	          memcpy(dst, src, src_vector_byte_stride * vectors);
872bf215546Sopenharmony_ci	          src += src_vector_byte_stride * vectors;
873bf215546Sopenharmony_ci	          dst += store->vector_stride * vectors;
874bf215546Sopenharmony_ci
875bf215546Sopenharmony_ci	          dst += extra_stride;
876bf215546Sopenharmony_ci	       }
877bf215546Sopenharmony_ci	    } else {
878bf215546Sopenharmony_ci	       /* Unigine Heaven benchmark gets here */
879bf215546Sopenharmony_ci	       memcpy(dst, src, src_vector_byte_stride * vectors * count);
880bf215546Sopenharmony_ci	       src += src_vector_byte_stride * vectors * count;
881bf215546Sopenharmony_ci	       dst += store->vector_stride * vectors * count;
882bf215546Sopenharmony_ci	    }
883bf215546Sopenharmony_ci	 } else {
884bf215546Sopenharmony_ci	    for (j = 0; j < count; j++) {
885bf215546Sopenharmony_ci	       for (v = 0; v < vectors; v++) {
886bf215546Sopenharmony_ci	          memcpy(dst, src, src_vector_byte_stride);
887bf215546Sopenharmony_ci	          src += src_vector_byte_stride;
888bf215546Sopenharmony_ci	          dst += store->vector_stride;
889bf215546Sopenharmony_ci	       }
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci	       dst += extra_stride;
892bf215546Sopenharmony_ci	    }
893bf215546Sopenharmony_ci	 }
894bf215546Sopenharmony_ci	 break;
895bf215546Sopenharmony_ci      }
896bf215546Sopenharmony_ci
897bf215546Sopenharmony_ci      case uniform_int_float: {
898bf215546Sopenharmony_ci	 const int *isrc = (const int *) src;
899bf215546Sopenharmony_ci	 unsigned j;
900bf215546Sopenharmony_ci	 unsigned v;
901bf215546Sopenharmony_ci	 unsigned c;
902bf215546Sopenharmony_ci
903bf215546Sopenharmony_ci	 for (j = 0; j < count; j++) {
904bf215546Sopenharmony_ci	    for (v = 0; v < vectors; v++) {
905bf215546Sopenharmony_ci	       for (c = 0; c < components; c++) {
906bf215546Sopenharmony_ci		  ((float *) dst)[c] = (float) *isrc;
907bf215546Sopenharmony_ci		  isrc++;
908bf215546Sopenharmony_ci	       }
909bf215546Sopenharmony_ci
910bf215546Sopenharmony_ci	       dst += store->vector_stride;
911bf215546Sopenharmony_ci	    }
912bf215546Sopenharmony_ci
913bf215546Sopenharmony_ci	    dst += extra_stride;
914bf215546Sopenharmony_ci	 }
915bf215546Sopenharmony_ci	 break;
916bf215546Sopenharmony_ci      }
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci      default:
919bf215546Sopenharmony_ci	 assert(!"Should not get here.");
920bf215546Sopenharmony_ci	 break;
921bf215546Sopenharmony_ci      }
922bf215546Sopenharmony_ci   }
923bf215546Sopenharmony_ci}
924bf215546Sopenharmony_ci
925bf215546Sopenharmony_ci
926bf215546Sopenharmony_cistatic void
927bf215546Sopenharmony_ciassociate_uniform_storage(struct gl_context *ctx,
928bf215546Sopenharmony_ci                          struct gl_shader_program *shader_program,
929bf215546Sopenharmony_ci                          struct gl_program *prog)
930bf215546Sopenharmony_ci{
931bf215546Sopenharmony_ci   struct gl_program_parameter_list *params = prog->Parameters;
932bf215546Sopenharmony_ci   gl_shader_stage shader_type = prog->info.stage;
933bf215546Sopenharmony_ci
934bf215546Sopenharmony_ci   _mesa_disallow_parameter_storage_realloc(params);
935bf215546Sopenharmony_ci
936bf215546Sopenharmony_ci   /* After adding each uniform to the parameter list, connect the storage for
937bf215546Sopenharmony_ci    * the parameter with the tracking structure used by the API for the
938bf215546Sopenharmony_ci    * uniform.
939bf215546Sopenharmony_ci    */
940bf215546Sopenharmony_ci   unsigned last_location = unsigned(~0);
941bf215546Sopenharmony_ci   for (unsigned i = 0; i < params->NumParameters; i++) {
942bf215546Sopenharmony_ci      if (params->Parameters[i].Type != PROGRAM_UNIFORM)
943bf215546Sopenharmony_ci         continue;
944bf215546Sopenharmony_ci
945bf215546Sopenharmony_ci      unsigned location = params->Parameters[i].UniformStorageIndex;
946bf215546Sopenharmony_ci
947bf215546Sopenharmony_ci      struct gl_uniform_storage *storage =
948bf215546Sopenharmony_ci         &shader_program->data->UniformStorage[location];
949bf215546Sopenharmony_ci
950bf215546Sopenharmony_ci      /* Do not associate any uniform storage to built-in uniforms */
951bf215546Sopenharmony_ci      if (storage->builtin)
952bf215546Sopenharmony_ci         continue;
953bf215546Sopenharmony_ci
954bf215546Sopenharmony_ci      if (location != last_location) {
955bf215546Sopenharmony_ci         enum gl_uniform_driver_format format = uniform_native;
956bf215546Sopenharmony_ci         unsigned columns = 0;
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci         int dmul;
959bf215546Sopenharmony_ci         if (ctx->Const.PackedDriverUniformStorage && !prog->info.use_legacy_math_rules) {
960bf215546Sopenharmony_ci            dmul = storage->type->vector_elements * sizeof(float);
961bf215546Sopenharmony_ci         } else {
962bf215546Sopenharmony_ci            dmul = 4 * sizeof(float);
963bf215546Sopenharmony_ci         }
964bf215546Sopenharmony_ci
965bf215546Sopenharmony_ci         switch (storage->type->base_type) {
966bf215546Sopenharmony_ci         case GLSL_TYPE_UINT64:
967bf215546Sopenharmony_ci            if (storage->type->vector_elements > 2)
968bf215546Sopenharmony_ci               dmul *= 2;
969bf215546Sopenharmony_ci            FALLTHROUGH;
970bf215546Sopenharmony_ci         case GLSL_TYPE_UINT:
971bf215546Sopenharmony_ci         case GLSL_TYPE_UINT16:
972bf215546Sopenharmony_ci         case GLSL_TYPE_UINT8:
973bf215546Sopenharmony_ci            assert(ctx->Const.NativeIntegers);
974bf215546Sopenharmony_ci            format = uniform_native;
975bf215546Sopenharmony_ci            columns = 1;
976bf215546Sopenharmony_ci            break;
977bf215546Sopenharmony_ci         case GLSL_TYPE_INT64:
978bf215546Sopenharmony_ci            if (storage->type->vector_elements > 2)
979bf215546Sopenharmony_ci               dmul *= 2;
980bf215546Sopenharmony_ci            FALLTHROUGH;
981bf215546Sopenharmony_ci         case GLSL_TYPE_INT:
982bf215546Sopenharmony_ci         case GLSL_TYPE_INT16:
983bf215546Sopenharmony_ci         case GLSL_TYPE_INT8:
984bf215546Sopenharmony_ci            format =
985bf215546Sopenharmony_ci               (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float;
986bf215546Sopenharmony_ci            columns = 1;
987bf215546Sopenharmony_ci            break;
988bf215546Sopenharmony_ci         case GLSL_TYPE_DOUBLE:
989bf215546Sopenharmony_ci            if (storage->type->vector_elements > 2)
990bf215546Sopenharmony_ci               dmul *= 2;
991bf215546Sopenharmony_ci            FALLTHROUGH;
992bf215546Sopenharmony_ci         case GLSL_TYPE_FLOAT:
993bf215546Sopenharmony_ci         case GLSL_TYPE_FLOAT16:
994bf215546Sopenharmony_ci            format = uniform_native;
995bf215546Sopenharmony_ci            columns = storage->type->matrix_columns;
996bf215546Sopenharmony_ci            break;
997bf215546Sopenharmony_ci         case GLSL_TYPE_BOOL:
998bf215546Sopenharmony_ci            format = uniform_native;
999bf215546Sopenharmony_ci            columns = 1;
1000bf215546Sopenharmony_ci            break;
1001bf215546Sopenharmony_ci         case GLSL_TYPE_SAMPLER:
1002bf215546Sopenharmony_ci         case GLSL_TYPE_TEXTURE:
1003bf215546Sopenharmony_ci         case GLSL_TYPE_IMAGE:
1004bf215546Sopenharmony_ci         case GLSL_TYPE_SUBROUTINE:
1005bf215546Sopenharmony_ci            format = uniform_native;
1006bf215546Sopenharmony_ci            columns = 1;
1007bf215546Sopenharmony_ci            break;
1008bf215546Sopenharmony_ci         case GLSL_TYPE_ATOMIC_UINT:
1009bf215546Sopenharmony_ci         case GLSL_TYPE_ARRAY:
1010bf215546Sopenharmony_ci         case GLSL_TYPE_VOID:
1011bf215546Sopenharmony_ci         case GLSL_TYPE_STRUCT:
1012bf215546Sopenharmony_ci         case GLSL_TYPE_ERROR:
1013bf215546Sopenharmony_ci         case GLSL_TYPE_INTERFACE:
1014bf215546Sopenharmony_ci         case GLSL_TYPE_FUNCTION:
1015bf215546Sopenharmony_ci            assert(!"Should not get here.");
1016bf215546Sopenharmony_ci            break;
1017bf215546Sopenharmony_ci         }
1018bf215546Sopenharmony_ci
1019bf215546Sopenharmony_ci         unsigned pvo = params->Parameters[i].ValueOffset;
1020bf215546Sopenharmony_ci         _mesa_uniform_attach_driver_storage(storage, dmul * columns, dmul,
1021bf215546Sopenharmony_ci                                             format,
1022bf215546Sopenharmony_ci                                             &params->ParameterValues[pvo]);
1023bf215546Sopenharmony_ci
1024bf215546Sopenharmony_ci         /* When a bindless sampler/image is bound to a texture/image unit, we
1025bf215546Sopenharmony_ci          * have to overwrite the constant value by the resident handle
1026bf215546Sopenharmony_ci          * directly in the constant buffer before the next draw. One solution
1027bf215546Sopenharmony_ci          * is to keep track a pointer to the base of the data.
1028bf215546Sopenharmony_ci          */
1029bf215546Sopenharmony_ci         if (storage->is_bindless && (prog->sh.NumBindlessSamplers ||
1030bf215546Sopenharmony_ci                                      prog->sh.NumBindlessImages)) {
1031bf215546Sopenharmony_ci            unsigned array_elements = MAX2(1, storage->array_elements);
1032bf215546Sopenharmony_ci
1033bf215546Sopenharmony_ci            for (unsigned j = 0; j < array_elements; ++j) {
1034bf215546Sopenharmony_ci               unsigned unit = storage->opaque[shader_type].index + j;
1035bf215546Sopenharmony_ci
1036bf215546Sopenharmony_ci               if (storage->type->without_array()->is_sampler()) {
1037bf215546Sopenharmony_ci                  assert(unit >= 0 && unit < prog->sh.NumBindlessSamplers);
1038bf215546Sopenharmony_ci                  prog->sh.BindlessSamplers[unit].data =
1039bf215546Sopenharmony_ci                     &params->ParameterValues[pvo] + 4 * j;
1040bf215546Sopenharmony_ci               } else if (storage->type->without_array()->is_image()) {
1041bf215546Sopenharmony_ci                  assert(unit >= 0 && unit < prog->sh.NumBindlessImages);
1042bf215546Sopenharmony_ci                  prog->sh.BindlessImages[unit].data =
1043bf215546Sopenharmony_ci                     &params->ParameterValues[pvo] + 4 * j;
1044bf215546Sopenharmony_ci               }
1045bf215546Sopenharmony_ci            }
1046bf215546Sopenharmony_ci         }
1047bf215546Sopenharmony_ci
1048bf215546Sopenharmony_ci         /* After attaching the driver's storage to the uniform, propagate any
1049bf215546Sopenharmony_ci          * data from the linker's backing store.  This will cause values from
1050bf215546Sopenharmony_ci          * initializers in the source code to be copied over.
1051bf215546Sopenharmony_ci          */
1052bf215546Sopenharmony_ci         unsigned array_elements = MAX2(1, storage->array_elements);
1053bf215546Sopenharmony_ci         if (ctx->Const.PackedDriverUniformStorage && !prog->info.use_legacy_math_rules &&
1054bf215546Sopenharmony_ci             (storage->is_bindless || !storage->type->contains_opaque())) {
1055bf215546Sopenharmony_ci            const int dmul = storage->type->is_64bit() ? 2 : 1;
1056bf215546Sopenharmony_ci            const unsigned components =
1057bf215546Sopenharmony_ci               storage->type->vector_elements *
1058bf215546Sopenharmony_ci               storage->type->matrix_columns;
1059bf215546Sopenharmony_ci
1060bf215546Sopenharmony_ci            for (unsigned s = 0; s < storage->num_driver_storage; s++) {
1061bf215546Sopenharmony_ci               gl_constant_value *uni_storage = (gl_constant_value *)
1062bf215546Sopenharmony_ci                  storage->driver_storage[s].data;
1063bf215546Sopenharmony_ci               memcpy(uni_storage, storage->storage,
1064bf215546Sopenharmony_ci                      sizeof(storage->storage[0]) * components *
1065bf215546Sopenharmony_ci                      array_elements * dmul);
1066bf215546Sopenharmony_ci            }
1067bf215546Sopenharmony_ci         } else {
1068bf215546Sopenharmony_ci            _mesa_propagate_uniforms_to_driver_storage(storage, 0,
1069bf215546Sopenharmony_ci                                                       array_elements);
1070bf215546Sopenharmony_ci         }
1071bf215546Sopenharmony_ci
1072bf215546Sopenharmony_ci	      last_location = location;
1073bf215546Sopenharmony_ci      }
1074bf215546Sopenharmony_ci   }
1075bf215546Sopenharmony_ci}
1076bf215546Sopenharmony_ci
1077bf215546Sopenharmony_ci
1078bf215546Sopenharmony_civoid
1079bf215546Sopenharmony_ci_mesa_ensure_and_associate_uniform_storage(struct gl_context *ctx,
1080bf215546Sopenharmony_ci                              struct gl_shader_program *shader_program,
1081bf215546Sopenharmony_ci                              struct gl_program *prog, unsigned required_space)
1082bf215546Sopenharmony_ci{
1083bf215546Sopenharmony_ci   /* Avoid reallocation of the program parameter list, because the uniform
1084bf215546Sopenharmony_ci    * storage is only associated with the original parameter list.
1085bf215546Sopenharmony_ci    */
1086bf215546Sopenharmony_ci   _mesa_reserve_parameter_storage(prog->Parameters, required_space,
1087bf215546Sopenharmony_ci                                   required_space);
1088bf215546Sopenharmony_ci
1089bf215546Sopenharmony_ci   /* This has to be done last.  Any operation the can cause
1090bf215546Sopenharmony_ci    * prog->ParameterValues to get reallocated (e.g., anything that adds a
1091bf215546Sopenharmony_ci    * program constant) has to happen before creating this linkage.
1092bf215546Sopenharmony_ci    */
1093bf215546Sopenharmony_ci   associate_uniform_storage(ctx, shader_program, prog);
1094bf215546Sopenharmony_ci}
1095bf215546Sopenharmony_ci
1096bf215546Sopenharmony_ci
1097bf215546Sopenharmony_ci/**
1098bf215546Sopenharmony_ci * Return printable string for a given GLSL_TYPE_x
1099bf215546Sopenharmony_ci */
1100bf215546Sopenharmony_cistatic const char *
1101bf215546Sopenharmony_ciglsl_type_name(enum glsl_base_type type)
1102bf215546Sopenharmony_ci{
1103bf215546Sopenharmony_ci   switch (type) {
1104bf215546Sopenharmony_ci   case GLSL_TYPE_UINT:
1105bf215546Sopenharmony_ci      return "uint";
1106bf215546Sopenharmony_ci   case GLSL_TYPE_INT:
1107bf215546Sopenharmony_ci      return "int";
1108bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT:
1109bf215546Sopenharmony_ci      return "float";
1110bf215546Sopenharmony_ci   case GLSL_TYPE_DOUBLE:
1111bf215546Sopenharmony_ci      return "double";
1112bf215546Sopenharmony_ci   case GLSL_TYPE_UINT64:
1113bf215546Sopenharmony_ci      return "uint64";
1114bf215546Sopenharmony_ci   case GLSL_TYPE_INT64:
1115bf215546Sopenharmony_ci      return "int64";
1116bf215546Sopenharmony_ci   case GLSL_TYPE_BOOL:
1117bf215546Sopenharmony_ci      return "bool";
1118bf215546Sopenharmony_ci   case GLSL_TYPE_SAMPLER:
1119bf215546Sopenharmony_ci      return "sampler";
1120bf215546Sopenharmony_ci   case GLSL_TYPE_IMAGE:
1121bf215546Sopenharmony_ci      return "image";
1122bf215546Sopenharmony_ci   case GLSL_TYPE_ATOMIC_UINT:
1123bf215546Sopenharmony_ci      return "atomic_uint";
1124bf215546Sopenharmony_ci   case GLSL_TYPE_STRUCT:
1125bf215546Sopenharmony_ci      return "struct";
1126bf215546Sopenharmony_ci   case GLSL_TYPE_INTERFACE:
1127bf215546Sopenharmony_ci      return "interface";
1128bf215546Sopenharmony_ci   case GLSL_TYPE_ARRAY:
1129bf215546Sopenharmony_ci      return "array";
1130bf215546Sopenharmony_ci   case GLSL_TYPE_VOID:
1131bf215546Sopenharmony_ci      return "void";
1132bf215546Sopenharmony_ci   case GLSL_TYPE_ERROR:
1133bf215546Sopenharmony_ci      return "error";
1134bf215546Sopenharmony_ci   default:
1135bf215546Sopenharmony_ci      return "other";
1136bf215546Sopenharmony_ci   }
1137bf215546Sopenharmony_ci}
1138bf215546Sopenharmony_ci
1139bf215546Sopenharmony_ci
1140bf215546Sopenharmony_cistatic struct gl_uniform_storage *
1141bf215546Sopenharmony_civalidate_uniform(GLint location, GLsizei count, const GLvoid *values,
1142bf215546Sopenharmony_ci                 unsigned *offset, struct gl_context *ctx,
1143bf215546Sopenharmony_ci                 struct gl_shader_program *shProg,
1144bf215546Sopenharmony_ci                 enum glsl_base_type basicType, unsigned src_components)
1145bf215546Sopenharmony_ci{
1146bf215546Sopenharmony_ci   struct gl_uniform_storage *const uni =
1147bf215546Sopenharmony_ci      validate_uniform_parameters(location, count, offset,
1148bf215546Sopenharmony_ci                                  ctx, shProg, "glUniform");
1149bf215546Sopenharmony_ci   if (uni == NULL)
1150bf215546Sopenharmony_ci      return NULL;
1151bf215546Sopenharmony_ci
1152bf215546Sopenharmony_ci   if (uni->type->is_matrix()) {
1153bf215546Sopenharmony_ci      /* Can't set matrix uniforms (like mat4) with glUniform */
1154bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1155bf215546Sopenharmony_ci                  "glUniform%u(uniform \"%s\"@%d is matrix)",
1156bf215546Sopenharmony_ci                  src_components, uni->name.string, location);
1157bf215546Sopenharmony_ci      return NULL;
1158bf215546Sopenharmony_ci   }
1159bf215546Sopenharmony_ci
1160bf215546Sopenharmony_ci   /* Verify that the types are compatible. */
1161bf215546Sopenharmony_ci   const unsigned components = uni->type->vector_elements;
1162bf215546Sopenharmony_ci
1163bf215546Sopenharmony_ci   if (components != src_components) {
1164bf215546Sopenharmony_ci      /* glUniformN() must match float/vecN type */
1165bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1166bf215546Sopenharmony_ci                  "glUniform%u(\"%s\"@%u has %u components, not %u)",
1167bf215546Sopenharmony_ci                  src_components, uni->name.string, location,
1168bf215546Sopenharmony_ci                  components, src_components);
1169bf215546Sopenharmony_ci      return NULL;
1170bf215546Sopenharmony_ci   }
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_ci   bool match;
1173bf215546Sopenharmony_ci   switch (uni->type->base_type) {
1174bf215546Sopenharmony_ci   case GLSL_TYPE_BOOL:
1175bf215546Sopenharmony_ci      match = (basicType != GLSL_TYPE_DOUBLE);
1176bf215546Sopenharmony_ci      break;
1177bf215546Sopenharmony_ci   case GLSL_TYPE_SAMPLER:
1178bf215546Sopenharmony_ci      match = (basicType == GLSL_TYPE_INT);
1179bf215546Sopenharmony_ci      break;
1180bf215546Sopenharmony_ci   case GLSL_TYPE_IMAGE:
1181bf215546Sopenharmony_ci      match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx));
1182bf215546Sopenharmony_ci      break;
1183bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT16:
1184bf215546Sopenharmony_ci      match = basicType == GLSL_TYPE_FLOAT;
1185bf215546Sopenharmony_ci      break;
1186bf215546Sopenharmony_ci   default:
1187bf215546Sopenharmony_ci      match = (basicType == uni->type->base_type);
1188bf215546Sopenharmony_ci      break;
1189bf215546Sopenharmony_ci   }
1190bf215546Sopenharmony_ci
1191bf215546Sopenharmony_ci   if (!match) {
1192bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1193bf215546Sopenharmony_ci                  "glUniform%u(\"%s\"@%d is %s, not %s)",
1194bf215546Sopenharmony_ci                  src_components, uni->name.string, location,
1195bf215546Sopenharmony_ci                  glsl_type_name(uni->type->base_type),
1196bf215546Sopenharmony_ci                  glsl_type_name(basicType));
1197bf215546Sopenharmony_ci      return NULL;
1198bf215546Sopenharmony_ci   }
1199bf215546Sopenharmony_ci
1200bf215546Sopenharmony_ci   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
1201bf215546Sopenharmony_ci      log_uniform(values, basicType, components, 1, count,
1202bf215546Sopenharmony_ci                  false, shProg, location, uni);
1203bf215546Sopenharmony_ci   }
1204bf215546Sopenharmony_ci
1205bf215546Sopenharmony_ci   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
1206bf215546Sopenharmony_ci    *
1207bf215546Sopenharmony_ci    *     "Setting a sampler's value to i selects texture image unit number
1208bf215546Sopenharmony_ci    *     i. The values of i range from zero to the implementation- dependent
1209bf215546Sopenharmony_ci    *     maximum supported number of texture image units."
1210bf215546Sopenharmony_ci    *
1211bf215546Sopenharmony_ci    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
1212bf215546Sopenharmony_ci    * the PDF) says:
1213bf215546Sopenharmony_ci    *
1214bf215546Sopenharmony_ci    *     "Error         Description                    Offending command
1215bf215546Sopenharmony_ci    *                                                   ignored?
1216bf215546Sopenharmony_ci    *     ...
1217bf215546Sopenharmony_ci    *     INVALID_VALUE  Numeric argument out of range  Yes"
1218bf215546Sopenharmony_ci    *
1219bf215546Sopenharmony_ci    * Based on that, when an invalid sampler is specified, we generate a
1220bf215546Sopenharmony_ci    * GL_INVALID_VALUE error and ignore the command.
1221bf215546Sopenharmony_ci    */
1222bf215546Sopenharmony_ci   if (uni->type->is_sampler()) {
1223bf215546Sopenharmony_ci      for (int i = 0; i < count; i++) {
1224bf215546Sopenharmony_ci         const unsigned texUnit = ((unsigned *) values)[i];
1225bf215546Sopenharmony_ci
1226bf215546Sopenharmony_ci         /* check that the sampler (tex unit index) is legal */
1227bf215546Sopenharmony_ci         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
1228bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1229bf215546Sopenharmony_ci                        "glUniform1i(invalid sampler/tex unit index for "
1230bf215546Sopenharmony_ci                        "uniform %d)", location);
1231bf215546Sopenharmony_ci            return NULL;
1232bf215546Sopenharmony_ci         }
1233bf215546Sopenharmony_ci      }
1234bf215546Sopenharmony_ci      /* We need to reset the validate flag on changes to samplers in case
1235bf215546Sopenharmony_ci       * two different sampler types are set to the same texture unit.
1236bf215546Sopenharmony_ci       */
1237bf215546Sopenharmony_ci      ctx->_Shader->Validated = ctx->_Shader->UserValidated = GL_FALSE;
1238bf215546Sopenharmony_ci   }
1239bf215546Sopenharmony_ci
1240bf215546Sopenharmony_ci   if (uni->type->is_image()) {
1241bf215546Sopenharmony_ci      for (int i = 0; i < count; i++) {
1242bf215546Sopenharmony_ci         const int unit = ((GLint *) values)[i];
1243bf215546Sopenharmony_ci
1244bf215546Sopenharmony_ci         /* check that the image unit is legal */
1245bf215546Sopenharmony_ci         if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) {
1246bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1247bf215546Sopenharmony_ci                        "glUniform1i(invalid image unit index for uniform %d)",
1248bf215546Sopenharmony_ci                        location);
1249bf215546Sopenharmony_ci            return NULL;
1250bf215546Sopenharmony_ci         }
1251bf215546Sopenharmony_ci      }
1252bf215546Sopenharmony_ci   }
1253bf215546Sopenharmony_ci
1254bf215546Sopenharmony_ci   return uni;
1255bf215546Sopenharmony_ci}
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_civoid
1258bf215546Sopenharmony_ci_mesa_flush_vertices_for_uniforms(struct gl_context *ctx,
1259bf215546Sopenharmony_ci                                  const struct gl_uniform_storage *uni)
1260bf215546Sopenharmony_ci{
1261bf215546Sopenharmony_ci   /* Opaque uniforms have no storage unless they are bindless */
1262bf215546Sopenharmony_ci   if (!uni->is_bindless && uni->type->contains_opaque()) {
1263bf215546Sopenharmony_ci      /* Samplers flush on demand and ignore redundant updates. */
1264bf215546Sopenharmony_ci      if (!uni->type->is_sampler())
1265bf215546Sopenharmony_ci         FLUSH_VERTICES(ctx, 0, 0);
1266bf215546Sopenharmony_ci      return;
1267bf215546Sopenharmony_ci   }
1268bf215546Sopenharmony_ci
1269bf215546Sopenharmony_ci   uint64_t new_driver_state = 0;
1270bf215546Sopenharmony_ci   unsigned mask = uni->active_shader_mask;
1271bf215546Sopenharmony_ci
1272bf215546Sopenharmony_ci   while (mask) {
1273bf215546Sopenharmony_ci      unsigned index = u_bit_scan(&mask);
1274bf215546Sopenharmony_ci
1275bf215546Sopenharmony_ci      assert(index < MESA_SHADER_STAGES);
1276bf215546Sopenharmony_ci      new_driver_state |= ctx->DriverFlags.NewShaderConstants[index];
1277bf215546Sopenharmony_ci   }
1278bf215546Sopenharmony_ci
1279bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, new_driver_state ? 0 : _NEW_PROGRAM_CONSTANTS, 0);
1280bf215546Sopenharmony_ci   ctx->NewDriverState |= new_driver_state;
1281bf215546Sopenharmony_ci}
1282bf215546Sopenharmony_ci
1283bf215546Sopenharmony_cistatic bool
1284bf215546Sopenharmony_cicopy_uniforms_to_storage(gl_constant_value *storage,
1285bf215546Sopenharmony_ci                         struct gl_uniform_storage *uni,
1286bf215546Sopenharmony_ci                         struct gl_context *ctx, GLsizei count,
1287bf215546Sopenharmony_ci                         const GLvoid *values, const int size_mul,
1288bf215546Sopenharmony_ci                         const unsigned offset, const unsigned components,
1289bf215546Sopenharmony_ci                         enum glsl_base_type basicType, bool flush)
1290bf215546Sopenharmony_ci{
1291bf215546Sopenharmony_ci   const gl_constant_value *src = (const gl_constant_value*)values;
1292bf215546Sopenharmony_ci   bool copy_as_uint64 = uni->is_bindless &&
1293bf215546Sopenharmony_ci                         (uni->type->is_sampler() || uni->type->is_image());
1294bf215546Sopenharmony_ci   bool copy_to_float16 = uni->type->base_type == GLSL_TYPE_FLOAT16;
1295bf215546Sopenharmony_ci
1296bf215546Sopenharmony_ci   if (!uni->type->is_boolean() && !copy_as_uint64 && !copy_to_float16) {
1297bf215546Sopenharmony_ci      unsigned size = sizeof(storage[0]) * components * count * size_mul;
1298bf215546Sopenharmony_ci
1299bf215546Sopenharmony_ci      if (!memcmp(storage, values, size))
1300bf215546Sopenharmony_ci         return false;
1301bf215546Sopenharmony_ci
1302bf215546Sopenharmony_ci      if (flush)
1303bf215546Sopenharmony_ci         _mesa_flush_vertices_for_uniforms(ctx, uni);
1304bf215546Sopenharmony_ci
1305bf215546Sopenharmony_ci      memcpy(storage, values, size);
1306bf215546Sopenharmony_ci      return true;
1307bf215546Sopenharmony_ci   } else if (copy_to_float16) {
1308bf215546Sopenharmony_ci      assert(ctx->Const.PackedDriverUniformStorage);
1309bf215546Sopenharmony_ci      const unsigned dst_components = align(components, 2);
1310bf215546Sopenharmony_ci      uint16_t *dst = (uint16_t*)storage;
1311bf215546Sopenharmony_ci
1312bf215546Sopenharmony_ci      int i = 0;
1313bf215546Sopenharmony_ci      unsigned c = 0;
1314bf215546Sopenharmony_ci
1315bf215546Sopenharmony_ci      if (flush) {
1316bf215546Sopenharmony_ci         /* Find the first element that's different. */
1317bf215546Sopenharmony_ci         for (; i < count; i++) {
1318bf215546Sopenharmony_ci            for (; c < components; c++) {
1319bf215546Sopenharmony_ci               if (dst[c] != _mesa_float_to_half(src[c].f)) {
1320bf215546Sopenharmony_ci                  _mesa_flush_vertices_for_uniforms(ctx, uni);
1321bf215546Sopenharmony_ci                  flush = false;
1322bf215546Sopenharmony_ci                  goto break_loops;
1323bf215546Sopenharmony_ci               }
1324bf215546Sopenharmony_ci            }
1325bf215546Sopenharmony_ci            c = 0;
1326bf215546Sopenharmony_ci            dst += dst_components;
1327bf215546Sopenharmony_ci            src += components;
1328bf215546Sopenharmony_ci         }
1329bf215546Sopenharmony_ci      break_loops:
1330bf215546Sopenharmony_ci         if (flush)
1331bf215546Sopenharmony_ci            return false; /* No change. */
1332bf215546Sopenharmony_ci      }
1333bf215546Sopenharmony_ci
1334bf215546Sopenharmony_ci      /* Set the remaining elements. We know that at least 1 element is
1335bf215546Sopenharmony_ci       * different and that we have flushed.
1336bf215546Sopenharmony_ci       */
1337bf215546Sopenharmony_ci      for (; i < count; i++) {
1338bf215546Sopenharmony_ci         for (; c < components; c++)
1339bf215546Sopenharmony_ci            dst[c] = _mesa_float_to_half(src[c].f);
1340bf215546Sopenharmony_ci
1341bf215546Sopenharmony_ci         c = 0;
1342bf215546Sopenharmony_ci         dst += dst_components;
1343bf215546Sopenharmony_ci         src += components;
1344bf215546Sopenharmony_ci      }
1345bf215546Sopenharmony_ci
1346bf215546Sopenharmony_ci      return true;
1347bf215546Sopenharmony_ci   } else if (copy_as_uint64) {
1348bf215546Sopenharmony_ci      const unsigned elems = components * count;
1349bf215546Sopenharmony_ci      uint64_t *dst = (uint64_t*)storage;
1350bf215546Sopenharmony_ci      unsigned i = 0;
1351bf215546Sopenharmony_ci
1352bf215546Sopenharmony_ci      if (flush) {
1353bf215546Sopenharmony_ci         /* Find the first element that's different. */
1354bf215546Sopenharmony_ci         for (; i < elems; i++) {
1355bf215546Sopenharmony_ci            if (dst[i] != src[i].u) {
1356bf215546Sopenharmony_ci               _mesa_flush_vertices_for_uniforms(ctx, uni);
1357bf215546Sopenharmony_ci               flush = false;
1358bf215546Sopenharmony_ci               break;
1359bf215546Sopenharmony_ci            }
1360bf215546Sopenharmony_ci         }
1361bf215546Sopenharmony_ci         if (flush)
1362bf215546Sopenharmony_ci            return false; /* No change. */
1363bf215546Sopenharmony_ci      }
1364bf215546Sopenharmony_ci
1365bf215546Sopenharmony_ci      /* Set the remaining elements. We know that at least 1 element is
1366bf215546Sopenharmony_ci       * different and that we have flushed.
1367bf215546Sopenharmony_ci       */
1368bf215546Sopenharmony_ci      for (; i < elems; i++)
1369bf215546Sopenharmony_ci         dst[i] = src[i].u;
1370bf215546Sopenharmony_ci
1371bf215546Sopenharmony_ci      return true;
1372bf215546Sopenharmony_ci   } else {
1373bf215546Sopenharmony_ci      const unsigned elems = components * count;
1374bf215546Sopenharmony_ci      gl_constant_value *dst = storage;
1375bf215546Sopenharmony_ci
1376bf215546Sopenharmony_ci      if (basicType == GLSL_TYPE_FLOAT) {
1377bf215546Sopenharmony_ci         unsigned i = 0;
1378bf215546Sopenharmony_ci
1379bf215546Sopenharmony_ci         if (flush) {
1380bf215546Sopenharmony_ci            /* Find the first element that's different. */
1381bf215546Sopenharmony_ci            for (; i < elems; i++) {
1382bf215546Sopenharmony_ci               if (dst[i].u !=
1383bf215546Sopenharmony_ci                   (src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0)) {
1384bf215546Sopenharmony_ci                  _mesa_flush_vertices_for_uniforms(ctx, uni);
1385bf215546Sopenharmony_ci                  flush = false;
1386bf215546Sopenharmony_ci                  break;
1387bf215546Sopenharmony_ci               }
1388bf215546Sopenharmony_ci            }
1389bf215546Sopenharmony_ci            if (flush)
1390bf215546Sopenharmony_ci               return false; /* No change. */
1391bf215546Sopenharmony_ci         }
1392bf215546Sopenharmony_ci
1393bf215546Sopenharmony_ci         /* Set the remaining elements. We know that at least 1 element is
1394bf215546Sopenharmony_ci          * different and that we have flushed.
1395bf215546Sopenharmony_ci          */
1396bf215546Sopenharmony_ci         for (; i < elems; i++)
1397bf215546Sopenharmony_ci            dst[i].u = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0;
1398bf215546Sopenharmony_ci
1399bf215546Sopenharmony_ci         return true;
1400bf215546Sopenharmony_ci      } else {
1401bf215546Sopenharmony_ci         unsigned i = 0;
1402bf215546Sopenharmony_ci
1403bf215546Sopenharmony_ci         if (flush) {
1404bf215546Sopenharmony_ci            /* Find the first element that's different. */
1405bf215546Sopenharmony_ci            for (; i < elems; i++) {
1406bf215546Sopenharmony_ci               if (dst[i].u !=
1407bf215546Sopenharmony_ci                   (src[i].u ? ctx->Const.UniformBooleanTrue : 0)) {
1408bf215546Sopenharmony_ci                  _mesa_flush_vertices_for_uniforms(ctx, uni);
1409bf215546Sopenharmony_ci                  flush = false;
1410bf215546Sopenharmony_ci                  break;
1411bf215546Sopenharmony_ci               }
1412bf215546Sopenharmony_ci            }
1413bf215546Sopenharmony_ci            if (flush)
1414bf215546Sopenharmony_ci               return false; /* No change. */
1415bf215546Sopenharmony_ci         }
1416bf215546Sopenharmony_ci
1417bf215546Sopenharmony_ci         /* Set the remaining elements. We know that at least 1 element is
1418bf215546Sopenharmony_ci          * different and that we have flushed.
1419bf215546Sopenharmony_ci          */
1420bf215546Sopenharmony_ci         for (; i < elems; i++)
1421bf215546Sopenharmony_ci            dst[i].u = src[i].u ? ctx->Const.UniformBooleanTrue : 0;
1422bf215546Sopenharmony_ci
1423bf215546Sopenharmony_ci         return true;
1424bf215546Sopenharmony_ci      }
1425bf215546Sopenharmony_ci   }
1426bf215546Sopenharmony_ci}
1427bf215546Sopenharmony_ci
1428bf215546Sopenharmony_ci
1429bf215546Sopenharmony_ci/**
1430bf215546Sopenharmony_ci * Called via glUniform*() functions.
1431bf215546Sopenharmony_ci */
1432bf215546Sopenharmony_ciextern "C" void
1433bf215546Sopenharmony_ci_mesa_uniform(GLint location, GLsizei count, const GLvoid *values,
1434bf215546Sopenharmony_ci              struct gl_context *ctx, struct gl_shader_program *shProg,
1435bf215546Sopenharmony_ci              enum glsl_base_type basicType, unsigned src_components)
1436bf215546Sopenharmony_ci{
1437bf215546Sopenharmony_ci   unsigned offset;
1438bf215546Sopenharmony_ci   int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1;
1439bf215546Sopenharmony_ci
1440bf215546Sopenharmony_ci   struct gl_uniform_storage *uni;
1441bf215546Sopenharmony_ci   if (_mesa_is_no_error_enabled(ctx)) {
1442bf215546Sopenharmony_ci      /* From Seciton 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec:
1443bf215546Sopenharmony_ci       *
1444bf215546Sopenharmony_ci       *   "If the value of location is -1, the Uniform* commands will
1445bf215546Sopenharmony_ci       *   silently ignore the data passed in, and the current uniform values
1446bf215546Sopenharmony_ci       *   will not be changed.
1447bf215546Sopenharmony_ci       */
1448bf215546Sopenharmony_ci      if (location == -1)
1449bf215546Sopenharmony_ci         return;
1450bf215546Sopenharmony_ci
1451bf215546Sopenharmony_ci      if (location >= (int)shProg->NumUniformRemapTable)
1452bf215546Sopenharmony_ci         return;
1453bf215546Sopenharmony_ci
1454bf215546Sopenharmony_ci      uni = shProg->UniformRemapTable[location];
1455bf215546Sopenharmony_ci      if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
1456bf215546Sopenharmony_ci         return;
1457bf215546Sopenharmony_ci
1458bf215546Sopenharmony_ci      /* The array index specified by the uniform location is just the
1459bf215546Sopenharmony_ci       * uniform location minus the base location of of the uniform.
1460bf215546Sopenharmony_ci       */
1461bf215546Sopenharmony_ci      assert(uni->array_elements > 0 || location == (int)uni->remap_location);
1462bf215546Sopenharmony_ci      offset = location - uni->remap_location;
1463bf215546Sopenharmony_ci   } else {
1464bf215546Sopenharmony_ci      uni = validate_uniform(location, count, values, &offset, ctx, shProg,
1465bf215546Sopenharmony_ci                             basicType, src_components);
1466bf215546Sopenharmony_ci      if (!uni)
1467bf215546Sopenharmony_ci         return;
1468bf215546Sopenharmony_ci   }
1469bf215546Sopenharmony_ci
1470bf215546Sopenharmony_ci   const unsigned components = uni->type->vector_elements;
1471bf215546Sopenharmony_ci
1472bf215546Sopenharmony_ci   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
1473bf215546Sopenharmony_ci    *
1474bf215546Sopenharmony_ci    *     "When loading N elements starting at an arbitrary position k in a
1475bf215546Sopenharmony_ci    *     uniform declared as an array, elements k through k + N - 1 in the
1476bf215546Sopenharmony_ci    *     array will be replaced with the new values. Values for any array
1477bf215546Sopenharmony_ci    *     element that exceeds the highest array element index used, as
1478bf215546Sopenharmony_ci    *     reported by GetActiveUniform, will be ignored by the GL."
1479bf215546Sopenharmony_ci    *
1480bf215546Sopenharmony_ci    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
1481bf215546Sopenharmony_ci    * will have already generated an error.
1482bf215546Sopenharmony_ci    */
1483bf215546Sopenharmony_ci   if (uni->array_elements != 0) {
1484bf215546Sopenharmony_ci      count = MIN2(count, (int) (uni->array_elements - offset));
1485bf215546Sopenharmony_ci   }
1486bf215546Sopenharmony_ci
1487bf215546Sopenharmony_ci   /* Store the data in the "actual type" backing storage for the uniform.
1488bf215546Sopenharmony_ci    */
1489bf215546Sopenharmony_ci   bool ctx_flushed = false;
1490bf215546Sopenharmony_ci   gl_constant_value *storage;
1491bf215546Sopenharmony_ci   if (ctx->Const.PackedDriverUniformStorage &&
1492bf215546Sopenharmony_ci       (uni->is_bindless || !uni->type->contains_opaque())) {
1493bf215546Sopenharmony_ci      for (unsigned s = 0; s < uni->num_driver_storage; s++) {
1494bf215546Sopenharmony_ci         unsigned dword_components = components;
1495bf215546Sopenharmony_ci
1496bf215546Sopenharmony_ci         /* 16-bit uniforms are packed. */
1497bf215546Sopenharmony_ci         if (glsl_base_type_is_16bit(uni->type->base_type))
1498bf215546Sopenharmony_ci            dword_components = DIV_ROUND_UP(dword_components, 2);
1499bf215546Sopenharmony_ci
1500bf215546Sopenharmony_ci         storage = (gl_constant_value *)
1501bf215546Sopenharmony_ci            uni->driver_storage[s].data + (size_mul * offset * dword_components);
1502bf215546Sopenharmony_ci
1503bf215546Sopenharmony_ci         if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul,
1504bf215546Sopenharmony_ci                                      offset, components, basicType, !ctx_flushed))
1505bf215546Sopenharmony_ci            ctx_flushed = true;
1506bf215546Sopenharmony_ci      }
1507bf215546Sopenharmony_ci   } else {
1508bf215546Sopenharmony_ci      storage = &uni->storage[size_mul * components * offset];
1509bf215546Sopenharmony_ci      if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul,
1510bf215546Sopenharmony_ci                                   offset, components, basicType, !ctx_flushed)) {
1511bf215546Sopenharmony_ci         _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
1512bf215546Sopenharmony_ci         ctx_flushed = true;
1513bf215546Sopenharmony_ci      }
1514bf215546Sopenharmony_ci   }
1515bf215546Sopenharmony_ci   /* Return early if possible. Bindless samplers need to be processed
1516bf215546Sopenharmony_ci    * because of the !sampler->bound codepath below.
1517bf215546Sopenharmony_ci    */
1518bf215546Sopenharmony_ci   if (!ctx_flushed && !(uni->type->is_sampler() && uni->is_bindless))
1519bf215546Sopenharmony_ci      return; /* no change in uniform values */
1520bf215546Sopenharmony_ci
1521bf215546Sopenharmony_ci   /* If the uniform is a sampler, do the extra magic necessary to propagate
1522bf215546Sopenharmony_ci    * the changes through.
1523bf215546Sopenharmony_ci    */
1524bf215546Sopenharmony_ci   if (uni->type->is_sampler()) {
1525bf215546Sopenharmony_ci      /* Note that samplers are the only uniforms that don't call
1526bf215546Sopenharmony_ci       * FLUSH_VERTICES above.
1527bf215546Sopenharmony_ci       */
1528bf215546Sopenharmony_ci      bool flushed = false;
1529bf215546Sopenharmony_ci      bool any_changed = false;
1530bf215546Sopenharmony_ci      bool samplers_validated = shProg->SamplersValidated;
1531bf215546Sopenharmony_ci
1532bf215546Sopenharmony_ci      shProg->SamplersValidated = GL_TRUE;
1533bf215546Sopenharmony_ci
1534bf215546Sopenharmony_ci      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
1535bf215546Sopenharmony_ci         struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
1536bf215546Sopenharmony_ci
1537bf215546Sopenharmony_ci         /* If the shader stage doesn't use the sampler uniform, skip this. */
1538bf215546Sopenharmony_ci         if (!uni->opaque[i].active)
1539bf215546Sopenharmony_ci            continue;
1540bf215546Sopenharmony_ci
1541bf215546Sopenharmony_ci         bool changed = false;
1542bf215546Sopenharmony_ci         for (int j = 0; j < count; j++) {
1543bf215546Sopenharmony_ci            unsigned unit = uni->opaque[i].index + offset + j;
1544bf215546Sopenharmony_ci            unsigned value = ((unsigned *)values)[j];
1545bf215546Sopenharmony_ci
1546bf215546Sopenharmony_ci            if (uni->is_bindless) {
1547bf215546Sopenharmony_ci               struct gl_bindless_sampler *sampler =
1548bf215546Sopenharmony_ci                  &sh->Program->sh.BindlessSamplers[unit];
1549bf215546Sopenharmony_ci
1550bf215546Sopenharmony_ci               /* Mark this bindless sampler as bound to a texture unit.
1551bf215546Sopenharmony_ci                */
1552bf215546Sopenharmony_ci               if (sampler->unit != value || !sampler->bound) {
1553bf215546Sopenharmony_ci                  if (!flushed) {
1554bf215546Sopenharmony_ci                     FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0);
1555bf215546Sopenharmony_ci                     flushed = true;
1556bf215546Sopenharmony_ci                  }
1557bf215546Sopenharmony_ci                  sampler->unit = value;
1558bf215546Sopenharmony_ci                  changed = true;
1559bf215546Sopenharmony_ci               }
1560bf215546Sopenharmony_ci               sampler->bound = true;
1561bf215546Sopenharmony_ci               sh->Program->sh.HasBoundBindlessSampler = true;
1562bf215546Sopenharmony_ci            } else {
1563bf215546Sopenharmony_ci               if (sh->Program->SamplerUnits[unit] != value) {
1564bf215546Sopenharmony_ci                  if (!flushed) {
1565bf215546Sopenharmony_ci                     FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0);
1566bf215546Sopenharmony_ci                     flushed = true;
1567bf215546Sopenharmony_ci                  }
1568bf215546Sopenharmony_ci                  sh->Program->SamplerUnits[unit] = value;
1569bf215546Sopenharmony_ci                  changed = true;
1570bf215546Sopenharmony_ci               }
1571bf215546Sopenharmony_ci            }
1572bf215546Sopenharmony_ci         }
1573bf215546Sopenharmony_ci
1574bf215546Sopenharmony_ci         if (changed) {
1575bf215546Sopenharmony_ci            struct gl_program *const prog = sh->Program;
1576bf215546Sopenharmony_ci            _mesa_update_shader_textures_used(shProg, prog);
1577bf215546Sopenharmony_ci            any_changed = true;
1578bf215546Sopenharmony_ci         }
1579bf215546Sopenharmony_ci      }
1580bf215546Sopenharmony_ci
1581bf215546Sopenharmony_ci      if (any_changed)
1582bf215546Sopenharmony_ci         _mesa_update_valid_to_render_state(ctx);
1583bf215546Sopenharmony_ci      else
1584bf215546Sopenharmony_ci         shProg->SamplersValidated = samplers_validated;
1585bf215546Sopenharmony_ci   }
1586bf215546Sopenharmony_ci
1587bf215546Sopenharmony_ci   /* If the uniform is an image, update the mapping from image
1588bf215546Sopenharmony_ci    * uniforms to image units present in the shader data structure.
1589bf215546Sopenharmony_ci    */
1590bf215546Sopenharmony_ci   if (uni->type->is_image()) {
1591bf215546Sopenharmony_ci      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
1592bf215546Sopenharmony_ci         struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
1593bf215546Sopenharmony_ci
1594bf215546Sopenharmony_ci         /* If the shader stage doesn't use the image uniform, skip this. */
1595bf215546Sopenharmony_ci         if (!uni->opaque[i].active)
1596bf215546Sopenharmony_ci            continue;
1597bf215546Sopenharmony_ci
1598bf215546Sopenharmony_ci         for (int j = 0; j < count; j++) {
1599bf215546Sopenharmony_ci            unsigned unit = uni->opaque[i].index + offset + j;
1600bf215546Sopenharmony_ci            unsigned value = ((unsigned *)values)[j];
1601bf215546Sopenharmony_ci
1602bf215546Sopenharmony_ci            if (uni->is_bindless) {
1603bf215546Sopenharmony_ci               struct gl_bindless_image *image =
1604bf215546Sopenharmony_ci                  &sh->Program->sh.BindlessImages[unit];
1605bf215546Sopenharmony_ci
1606bf215546Sopenharmony_ci               /* Mark this bindless image as bound to an image unit.
1607bf215546Sopenharmony_ci                */
1608bf215546Sopenharmony_ci               image->unit = value;
1609bf215546Sopenharmony_ci               image->bound = true;
1610bf215546Sopenharmony_ci               sh->Program->sh.HasBoundBindlessImage = true;
1611bf215546Sopenharmony_ci            } else {
1612bf215546Sopenharmony_ci               sh->Program->sh.ImageUnits[unit] = value;
1613bf215546Sopenharmony_ci            }
1614bf215546Sopenharmony_ci         }
1615bf215546Sopenharmony_ci      }
1616bf215546Sopenharmony_ci
1617bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_IMAGE_UNITS;
1618bf215546Sopenharmony_ci   }
1619bf215546Sopenharmony_ci}
1620bf215546Sopenharmony_ci
1621bf215546Sopenharmony_ci
1622bf215546Sopenharmony_cistatic bool
1623bf215546Sopenharmony_cicopy_uniform_matrix_to_storage(struct gl_context *ctx,
1624bf215546Sopenharmony_ci                               gl_constant_value *storage,
1625bf215546Sopenharmony_ci                               struct gl_uniform_storage *const uni,
1626bf215546Sopenharmony_ci                               unsigned count, const void *values,
1627bf215546Sopenharmony_ci                               const unsigned size_mul, const unsigned offset,
1628bf215546Sopenharmony_ci                               const unsigned components,
1629bf215546Sopenharmony_ci                               const unsigned vectors, bool transpose,
1630bf215546Sopenharmony_ci                               unsigned cols, unsigned rows,
1631bf215546Sopenharmony_ci                               enum glsl_base_type basicType, bool flush)
1632bf215546Sopenharmony_ci{
1633bf215546Sopenharmony_ci   const unsigned elements = components * vectors;
1634bf215546Sopenharmony_ci   const unsigned size = sizeof(storage[0]) * elements * count * size_mul;
1635bf215546Sopenharmony_ci
1636bf215546Sopenharmony_ci   if (uni->type->base_type == GLSL_TYPE_FLOAT16) {
1637bf215546Sopenharmony_ci      assert(ctx->Const.PackedDriverUniformStorage);
1638bf215546Sopenharmony_ci      const unsigned dst_components = align(components, 2);
1639bf215546Sopenharmony_ci      const unsigned dst_elements = dst_components * vectors;
1640bf215546Sopenharmony_ci
1641bf215546Sopenharmony_ci      if (!transpose) {
1642bf215546Sopenharmony_ci         const float *src = (const float *)values;
1643bf215546Sopenharmony_ci         uint16_t *dst = (uint16_t*)storage;
1644bf215546Sopenharmony_ci
1645bf215546Sopenharmony_ci         unsigned i = 0, r = 0, c = 0;
1646bf215546Sopenharmony_ci
1647bf215546Sopenharmony_ci         if (flush) {
1648bf215546Sopenharmony_ci            /* Find the first element that's different. */
1649bf215546Sopenharmony_ci            for (; i < count; i++) {
1650bf215546Sopenharmony_ci               for (; c < cols; c++) {
1651bf215546Sopenharmony_ci                  for (; r < rows; r++) {
1652bf215546Sopenharmony_ci                     if (dst[(c * dst_components) + r] !=
1653bf215546Sopenharmony_ci                         _mesa_float_to_half(src[(c * components) + r])) {
1654bf215546Sopenharmony_ci                        _mesa_flush_vertices_for_uniforms(ctx, uni);
1655bf215546Sopenharmony_ci                        flush = false;
1656bf215546Sopenharmony_ci                        goto break_loops_16bit;
1657bf215546Sopenharmony_ci                     }
1658bf215546Sopenharmony_ci                  }
1659bf215546Sopenharmony_ci                  r = 0;
1660bf215546Sopenharmony_ci               }
1661bf215546Sopenharmony_ci               c = 0;
1662bf215546Sopenharmony_ci               dst += dst_elements;
1663bf215546Sopenharmony_ci               src += elements;
1664bf215546Sopenharmony_ci            }
1665bf215546Sopenharmony_ci
1666bf215546Sopenharmony_ci         break_loops_16bit:
1667bf215546Sopenharmony_ci            if (flush)
1668bf215546Sopenharmony_ci               return false; /* No change. */
1669bf215546Sopenharmony_ci         }
1670bf215546Sopenharmony_ci
1671bf215546Sopenharmony_ci         /* Set the remaining elements. We know that at least 1 element is
1672bf215546Sopenharmony_ci          * different and that we have flushed.
1673bf215546Sopenharmony_ci          */
1674bf215546Sopenharmony_ci         for (; i < count; i++) {
1675bf215546Sopenharmony_ci            for (; c < cols; c++) {
1676bf215546Sopenharmony_ci               for (; r < rows; r++) {
1677bf215546Sopenharmony_ci                  dst[(c * dst_components) + r] =
1678bf215546Sopenharmony_ci                     _mesa_float_to_half(src[(c * components) + r]);
1679bf215546Sopenharmony_ci               }
1680bf215546Sopenharmony_ci               r = 0;
1681bf215546Sopenharmony_ci            }
1682bf215546Sopenharmony_ci            c = 0;
1683bf215546Sopenharmony_ci            dst += dst_elements;
1684bf215546Sopenharmony_ci            src += elements;
1685bf215546Sopenharmony_ci         }
1686bf215546Sopenharmony_ci         return true;
1687bf215546Sopenharmony_ci      } else {
1688bf215546Sopenharmony_ci         /* Transpose the matrix. */
1689bf215546Sopenharmony_ci         const float *src = (const float *)values;
1690bf215546Sopenharmony_ci         uint16_t *dst = (uint16_t*)storage;
1691bf215546Sopenharmony_ci
1692bf215546Sopenharmony_ci         unsigned i = 0, r = 0, c = 0;
1693bf215546Sopenharmony_ci
1694bf215546Sopenharmony_ci         if (flush) {
1695bf215546Sopenharmony_ci            /* Find the first element that's different. */
1696bf215546Sopenharmony_ci            for (; i < count; i++) {
1697bf215546Sopenharmony_ci               for (; r < rows; r++) {
1698bf215546Sopenharmony_ci                  for (; c < cols; c++) {
1699bf215546Sopenharmony_ci                     if (dst[(c * dst_components) + r] !=
1700bf215546Sopenharmony_ci                         _mesa_float_to_half(src[c + (r * vectors)])) {
1701bf215546Sopenharmony_ci                        _mesa_flush_vertices_for_uniforms(ctx, uni);
1702bf215546Sopenharmony_ci                        flush = false;
1703bf215546Sopenharmony_ci                        goto break_loops_16bit_transpose;
1704bf215546Sopenharmony_ci                     }
1705bf215546Sopenharmony_ci                  }
1706bf215546Sopenharmony_ci                  c = 0;
1707bf215546Sopenharmony_ci               }
1708bf215546Sopenharmony_ci               r = 0;
1709bf215546Sopenharmony_ci               dst += elements;
1710bf215546Sopenharmony_ci               src += elements;
1711bf215546Sopenharmony_ci            }
1712bf215546Sopenharmony_ci
1713bf215546Sopenharmony_ci         break_loops_16bit_transpose:
1714bf215546Sopenharmony_ci            if (flush)
1715bf215546Sopenharmony_ci               return false; /* No change. */
1716bf215546Sopenharmony_ci         }
1717bf215546Sopenharmony_ci
1718bf215546Sopenharmony_ci         /* Set the remaining elements. We know that at least 1 element is
1719bf215546Sopenharmony_ci          * different and that we have flushed.
1720bf215546Sopenharmony_ci          */
1721bf215546Sopenharmony_ci         for (; i < count; i++) {
1722bf215546Sopenharmony_ci            for (; r < rows; r++) {
1723bf215546Sopenharmony_ci               for (; c < cols; c++) {
1724bf215546Sopenharmony_ci                  dst[(c * dst_components) + r] =
1725bf215546Sopenharmony_ci                     _mesa_float_to_half(src[c + (r * vectors)]);
1726bf215546Sopenharmony_ci               }
1727bf215546Sopenharmony_ci               c = 0;
1728bf215546Sopenharmony_ci            }
1729bf215546Sopenharmony_ci            r = 0;
1730bf215546Sopenharmony_ci            dst += elements;
1731bf215546Sopenharmony_ci            src += elements;
1732bf215546Sopenharmony_ci         }
1733bf215546Sopenharmony_ci         return true;
1734bf215546Sopenharmony_ci      }
1735bf215546Sopenharmony_ci   } else if (!transpose) {
1736bf215546Sopenharmony_ci      if (!memcmp(storage, values, size))
1737bf215546Sopenharmony_ci         return false;
1738bf215546Sopenharmony_ci
1739bf215546Sopenharmony_ci      if (flush)
1740bf215546Sopenharmony_ci         _mesa_flush_vertices_for_uniforms(ctx, uni);
1741bf215546Sopenharmony_ci
1742bf215546Sopenharmony_ci      memcpy(storage, values, size);
1743bf215546Sopenharmony_ci      return true;
1744bf215546Sopenharmony_ci   } else if (basicType == GLSL_TYPE_FLOAT) {
1745bf215546Sopenharmony_ci      /* Transpose the matrix. */
1746bf215546Sopenharmony_ci      const float *src = (const float *)values;
1747bf215546Sopenharmony_ci      float *dst = (float*)storage;
1748bf215546Sopenharmony_ci
1749bf215546Sopenharmony_ci      unsigned i = 0, r = 0, c = 0;
1750bf215546Sopenharmony_ci
1751bf215546Sopenharmony_ci      if (flush) {
1752bf215546Sopenharmony_ci         /* Find the first element that's different. */
1753bf215546Sopenharmony_ci         for (; i < count; i++) {
1754bf215546Sopenharmony_ci            for (; r < rows; r++) {
1755bf215546Sopenharmony_ci               for (; c < cols; c++) {
1756bf215546Sopenharmony_ci                  if (dst[(c * components) + r] != src[c + (r * vectors)]) {
1757bf215546Sopenharmony_ci                     _mesa_flush_vertices_for_uniforms(ctx, uni);
1758bf215546Sopenharmony_ci                     flush = false;
1759bf215546Sopenharmony_ci                     goto break_loops;
1760bf215546Sopenharmony_ci                  }
1761bf215546Sopenharmony_ci               }
1762bf215546Sopenharmony_ci               c = 0;
1763bf215546Sopenharmony_ci            }
1764bf215546Sopenharmony_ci            r = 0;
1765bf215546Sopenharmony_ci            dst += elements;
1766bf215546Sopenharmony_ci            src += elements;
1767bf215546Sopenharmony_ci         }
1768bf215546Sopenharmony_ci
1769bf215546Sopenharmony_ci      break_loops:
1770bf215546Sopenharmony_ci         if (flush)
1771bf215546Sopenharmony_ci            return false; /* No change. */
1772bf215546Sopenharmony_ci      }
1773bf215546Sopenharmony_ci
1774bf215546Sopenharmony_ci      /* Set the remaining elements. We know that at least 1 element is
1775bf215546Sopenharmony_ci       * different and that we have flushed.
1776bf215546Sopenharmony_ci       */
1777bf215546Sopenharmony_ci      for (; i < count; i++) {
1778bf215546Sopenharmony_ci         for (; r < rows; r++) {
1779bf215546Sopenharmony_ci            for (; c < cols; c++)
1780bf215546Sopenharmony_ci               dst[(c * components) + r] = src[c + (r * vectors)];
1781bf215546Sopenharmony_ci            c = 0;
1782bf215546Sopenharmony_ci         }
1783bf215546Sopenharmony_ci         r = 0;
1784bf215546Sopenharmony_ci         dst += elements;
1785bf215546Sopenharmony_ci         src += elements;
1786bf215546Sopenharmony_ci      }
1787bf215546Sopenharmony_ci      return true;
1788bf215546Sopenharmony_ci   } else {
1789bf215546Sopenharmony_ci      assert(basicType == GLSL_TYPE_DOUBLE);
1790bf215546Sopenharmony_ci      const double *src = (const double *)values;
1791bf215546Sopenharmony_ci      double *dst = (double*)storage;
1792bf215546Sopenharmony_ci
1793bf215546Sopenharmony_ci      unsigned i = 0, r = 0, c = 0;
1794bf215546Sopenharmony_ci
1795bf215546Sopenharmony_ci      if (flush) {
1796bf215546Sopenharmony_ci         /* Find the first element that's different. */
1797bf215546Sopenharmony_ci         for (; i < count; i++) {
1798bf215546Sopenharmony_ci            for (; r < rows; r++) {
1799bf215546Sopenharmony_ci               for (; c < cols; c++) {
1800bf215546Sopenharmony_ci                  if (dst[(c * components) + r] != src[c + (r * vectors)]) {
1801bf215546Sopenharmony_ci                     _mesa_flush_vertices_for_uniforms(ctx, uni);
1802bf215546Sopenharmony_ci                     flush = false;
1803bf215546Sopenharmony_ci                     goto break_loops2;
1804bf215546Sopenharmony_ci                  }
1805bf215546Sopenharmony_ci               }
1806bf215546Sopenharmony_ci               c = 0;
1807bf215546Sopenharmony_ci            }
1808bf215546Sopenharmony_ci            r = 0;
1809bf215546Sopenharmony_ci            dst += elements;
1810bf215546Sopenharmony_ci            src += elements;
1811bf215546Sopenharmony_ci         }
1812bf215546Sopenharmony_ci
1813bf215546Sopenharmony_ci      break_loops2:
1814bf215546Sopenharmony_ci         if (flush)
1815bf215546Sopenharmony_ci            return false; /* No change. */
1816bf215546Sopenharmony_ci      }
1817bf215546Sopenharmony_ci
1818bf215546Sopenharmony_ci      /* Set the remaining elements. We know that at least 1 element is
1819bf215546Sopenharmony_ci       * different and that we have flushed.
1820bf215546Sopenharmony_ci       */
1821bf215546Sopenharmony_ci      for (; i < count; i++) {
1822bf215546Sopenharmony_ci         for (; r < rows; r++) {
1823bf215546Sopenharmony_ci            for (; c < cols; c++)
1824bf215546Sopenharmony_ci               dst[(c * components) + r] = src[c + (r * vectors)];
1825bf215546Sopenharmony_ci            c = 0;
1826bf215546Sopenharmony_ci         }
1827bf215546Sopenharmony_ci         r = 0;
1828bf215546Sopenharmony_ci         dst += elements;
1829bf215546Sopenharmony_ci         src += elements;
1830bf215546Sopenharmony_ci      }
1831bf215546Sopenharmony_ci      return true;
1832bf215546Sopenharmony_ci   }
1833bf215546Sopenharmony_ci}
1834bf215546Sopenharmony_ci
1835bf215546Sopenharmony_ci
1836bf215546Sopenharmony_ci/**
1837bf215546Sopenharmony_ci * Called by glUniformMatrix*() functions.
1838bf215546Sopenharmony_ci * Note: cols=2, rows=4  ==>  array[2] of vec4
1839bf215546Sopenharmony_ci */
1840bf215546Sopenharmony_ciextern "C" void
1841bf215546Sopenharmony_ci_mesa_uniform_matrix(GLint location, GLsizei count,
1842bf215546Sopenharmony_ci                     GLboolean transpose, const void *values,
1843bf215546Sopenharmony_ci                     struct gl_context *ctx, struct gl_shader_program *shProg,
1844bf215546Sopenharmony_ci                     GLuint cols, GLuint rows, enum glsl_base_type basicType)
1845bf215546Sopenharmony_ci{
1846bf215546Sopenharmony_ci   unsigned offset;
1847bf215546Sopenharmony_ci   struct gl_uniform_storage *const uni =
1848bf215546Sopenharmony_ci      validate_uniform_parameters(location, count, &offset,
1849bf215546Sopenharmony_ci                                  ctx, shProg, "glUniformMatrix");
1850bf215546Sopenharmony_ci   if (uni == NULL)
1851bf215546Sopenharmony_ci      return;
1852bf215546Sopenharmony_ci
1853bf215546Sopenharmony_ci   /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE.
1854bf215546Sopenharmony_ci    * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml
1855bf215546Sopenharmony_ci    */
1856bf215546Sopenharmony_ci   if (transpose) {
1857bf215546Sopenharmony_ci      if (ctx->API == API_OPENGLES2 && ctx->Version < 30) {
1858bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
1859bf215546Sopenharmony_ci                     "glUniformMatrix(matrix transpose is not GL_FALSE)");
1860bf215546Sopenharmony_ci         return;
1861bf215546Sopenharmony_ci      }
1862bf215546Sopenharmony_ci   }
1863bf215546Sopenharmony_ci
1864bf215546Sopenharmony_ci   if (!uni->type->is_matrix()) {
1865bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1866bf215546Sopenharmony_ci		  "glUniformMatrix(non-matrix uniform)");
1867bf215546Sopenharmony_ci      return;
1868bf215546Sopenharmony_ci   }
1869bf215546Sopenharmony_ci
1870bf215546Sopenharmony_ci   assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE);
1871bf215546Sopenharmony_ci   const unsigned size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;
1872bf215546Sopenharmony_ci
1873bf215546Sopenharmony_ci   assert(!uni->type->is_sampler());
1874bf215546Sopenharmony_ci   const unsigned vectors = uni->type->matrix_columns;
1875bf215546Sopenharmony_ci   const unsigned components = uni->type->vector_elements;
1876bf215546Sopenharmony_ci
1877bf215546Sopenharmony_ci   /* Verify that the types are compatible.  This is greatly simplified for
1878bf215546Sopenharmony_ci    * matrices because they can only have a float base type.
1879bf215546Sopenharmony_ci    */
1880bf215546Sopenharmony_ci   if (vectors != cols || components != rows) {
1881bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1882bf215546Sopenharmony_ci		  "glUniformMatrix(matrix size mismatch)");
1883bf215546Sopenharmony_ci      return;
1884bf215546Sopenharmony_ci   }
1885bf215546Sopenharmony_ci
1886bf215546Sopenharmony_ci   /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec
1887bf215546Sopenharmony_ci    * says:
1888bf215546Sopenharmony_ci    *
1889bf215546Sopenharmony_ci    *     "If any of the following conditions occur, an INVALID_OPERATION
1890bf215546Sopenharmony_ci    *     error is generated by the Uniform* commands, and no uniform values
1891bf215546Sopenharmony_ci    *     are changed:
1892bf215546Sopenharmony_ci    *
1893bf215546Sopenharmony_ci    *     ...
1894bf215546Sopenharmony_ci    *
1895bf215546Sopenharmony_ci    *     - if the uniform declared in the shader is not of type boolean and
1896bf215546Sopenharmony_ci    *       the type indicated in the name of the Uniform* command used does
1897bf215546Sopenharmony_ci    *       not match the type of the uniform"
1898bf215546Sopenharmony_ci    *
1899bf215546Sopenharmony_ci    * There are no Boolean matrix types, so we do not need to allow
1900bf215546Sopenharmony_ci    * GLSL_TYPE_BOOL here (as _mesa_uniform does).
1901bf215546Sopenharmony_ci    */
1902bf215546Sopenharmony_ci   if (uni->type->base_type != basicType &&
1903bf215546Sopenharmony_ci       !(uni->type->base_type == GLSL_TYPE_FLOAT16 &&
1904bf215546Sopenharmony_ci         basicType == GLSL_TYPE_FLOAT)) {
1905bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1906bf215546Sopenharmony_ci                  "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)",
1907bf215546Sopenharmony_ci                  cols, rows, uni->name.string, location,
1908bf215546Sopenharmony_ci                  glsl_type_name(uni->type->base_type),
1909bf215546Sopenharmony_ci                  glsl_type_name(basicType));
1910bf215546Sopenharmony_ci      return;
1911bf215546Sopenharmony_ci   }
1912bf215546Sopenharmony_ci
1913bf215546Sopenharmony_ci   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
1914bf215546Sopenharmony_ci      log_uniform(values, uni->type->base_type, components, vectors, count,
1915bf215546Sopenharmony_ci		  bool(transpose), shProg, location, uni);
1916bf215546Sopenharmony_ci   }
1917bf215546Sopenharmony_ci
1918bf215546Sopenharmony_ci   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
1919bf215546Sopenharmony_ci    *
1920bf215546Sopenharmony_ci    *     "When loading N elements starting at an arbitrary position k in a
1921bf215546Sopenharmony_ci    *     uniform declared as an array, elements k through k + N - 1 in the
1922bf215546Sopenharmony_ci    *     array will be replaced with the new values. Values for any array
1923bf215546Sopenharmony_ci    *     element that exceeds the highest array element index used, as
1924bf215546Sopenharmony_ci    *     reported by GetActiveUniform, will be ignored by the GL."
1925bf215546Sopenharmony_ci    *
1926bf215546Sopenharmony_ci    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
1927bf215546Sopenharmony_ci    * will have already generated an error.
1928bf215546Sopenharmony_ci    */
1929bf215546Sopenharmony_ci   if (uni->array_elements != 0) {
1930bf215546Sopenharmony_ci      count = MIN2(count, (int) (uni->array_elements - offset));
1931bf215546Sopenharmony_ci   }
1932bf215546Sopenharmony_ci
1933bf215546Sopenharmony_ci   /* Store the data in the "actual type" backing storage for the uniform.
1934bf215546Sopenharmony_ci    */
1935bf215546Sopenharmony_ci   gl_constant_value *storage;
1936bf215546Sopenharmony_ci   const unsigned elements = components * vectors;
1937bf215546Sopenharmony_ci   if (ctx->Const.PackedDriverUniformStorage) {
1938bf215546Sopenharmony_ci      bool flushed = false;
1939bf215546Sopenharmony_ci
1940bf215546Sopenharmony_ci      for (unsigned s = 0; s < uni->num_driver_storage; s++) {
1941bf215546Sopenharmony_ci         unsigned dword_components = components;
1942bf215546Sopenharmony_ci
1943bf215546Sopenharmony_ci         /* 16-bit uniforms are packed. */
1944bf215546Sopenharmony_ci         if (glsl_base_type_is_16bit(uni->type->base_type))
1945bf215546Sopenharmony_ci            dword_components = DIV_ROUND_UP(dword_components, 2);
1946bf215546Sopenharmony_ci
1947bf215546Sopenharmony_ci         storage = (gl_constant_value *)
1948bf215546Sopenharmony_ci            uni->driver_storage[s].data +
1949bf215546Sopenharmony_ci            (size_mul * offset * dword_components * vectors);
1950bf215546Sopenharmony_ci
1951bf215546Sopenharmony_ci         if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values,
1952bf215546Sopenharmony_ci                                            size_mul, offset, components,
1953bf215546Sopenharmony_ci                                            vectors, transpose, cols, rows,
1954bf215546Sopenharmony_ci                                            basicType, !flushed))
1955bf215546Sopenharmony_ci            flushed = true;
1956bf215546Sopenharmony_ci      }
1957bf215546Sopenharmony_ci   } else {
1958bf215546Sopenharmony_ci      storage =  &uni->storage[size_mul * elements * offset];
1959bf215546Sopenharmony_ci      if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values,
1960bf215546Sopenharmony_ci                                         size_mul, offset, components, vectors,
1961bf215546Sopenharmony_ci                                         transpose, cols, rows, basicType,
1962bf215546Sopenharmony_ci                                         true))
1963bf215546Sopenharmony_ci         _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
1964bf215546Sopenharmony_ci   }
1965bf215546Sopenharmony_ci}
1966bf215546Sopenharmony_ci
1967bf215546Sopenharmony_cistatic void
1968bf215546Sopenharmony_ciupdate_bound_bindless_sampler_flag(struct gl_program *prog)
1969bf215546Sopenharmony_ci{
1970bf215546Sopenharmony_ci   unsigned i;
1971bf215546Sopenharmony_ci
1972bf215546Sopenharmony_ci   if (likely(!prog->sh.HasBoundBindlessSampler))
1973bf215546Sopenharmony_ci      return;
1974bf215546Sopenharmony_ci
1975bf215546Sopenharmony_ci   for (i = 0; i < prog->sh.NumBindlessSamplers; i++) {
1976bf215546Sopenharmony_ci      struct gl_bindless_sampler *sampler = &prog->sh.BindlessSamplers[i];
1977bf215546Sopenharmony_ci
1978bf215546Sopenharmony_ci      if (sampler->bound)
1979bf215546Sopenharmony_ci         return;
1980bf215546Sopenharmony_ci   }
1981bf215546Sopenharmony_ci   prog->sh.HasBoundBindlessSampler = false;
1982bf215546Sopenharmony_ci}
1983bf215546Sopenharmony_ci
1984bf215546Sopenharmony_cistatic void
1985bf215546Sopenharmony_ciupdate_bound_bindless_image_flag(struct gl_program *prog)
1986bf215546Sopenharmony_ci{
1987bf215546Sopenharmony_ci   unsigned i;
1988bf215546Sopenharmony_ci
1989bf215546Sopenharmony_ci   if (likely(!prog->sh.HasBoundBindlessImage))
1990bf215546Sopenharmony_ci      return;
1991bf215546Sopenharmony_ci
1992bf215546Sopenharmony_ci   for (i = 0; i < prog->sh.NumBindlessImages; i++) {
1993bf215546Sopenharmony_ci      struct gl_bindless_image *image = &prog->sh.BindlessImages[i];
1994bf215546Sopenharmony_ci
1995bf215546Sopenharmony_ci      if (image->bound)
1996bf215546Sopenharmony_ci         return;
1997bf215546Sopenharmony_ci   }
1998bf215546Sopenharmony_ci   prog->sh.HasBoundBindlessImage = false;
1999bf215546Sopenharmony_ci}
2000bf215546Sopenharmony_ci
2001bf215546Sopenharmony_ci/**
2002bf215546Sopenharmony_ci * Called via glUniformHandleui64*ARB() functions.
2003bf215546Sopenharmony_ci */
2004bf215546Sopenharmony_ciextern "C" void
2005bf215546Sopenharmony_ci_mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values,
2006bf215546Sopenharmony_ci                     struct gl_context *ctx, struct gl_shader_program *shProg)
2007bf215546Sopenharmony_ci{
2008bf215546Sopenharmony_ci   unsigned offset;
2009bf215546Sopenharmony_ci   struct gl_uniform_storage *uni;
2010bf215546Sopenharmony_ci
2011bf215546Sopenharmony_ci   if (_mesa_is_no_error_enabled(ctx)) {
2012bf215546Sopenharmony_ci      /* From Section 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec:
2013bf215546Sopenharmony_ci       *
2014bf215546Sopenharmony_ci       *   "If the value of location is -1, the Uniform* commands will
2015bf215546Sopenharmony_ci       *   silently ignore the data passed in, and the current uniform values
2016bf215546Sopenharmony_ci       *   will not be changed.
2017bf215546Sopenharmony_ci       */
2018bf215546Sopenharmony_ci      if (location == -1)
2019bf215546Sopenharmony_ci         return;
2020bf215546Sopenharmony_ci
2021bf215546Sopenharmony_ci      uni = shProg->UniformRemapTable[location];
2022bf215546Sopenharmony_ci      if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
2023bf215546Sopenharmony_ci         return;
2024bf215546Sopenharmony_ci
2025bf215546Sopenharmony_ci      /* The array index specified by the uniform location is just the
2026bf215546Sopenharmony_ci       * uniform location minus the base location of of the uniform.
2027bf215546Sopenharmony_ci       */
2028bf215546Sopenharmony_ci      assert(uni->array_elements > 0 || location == (int)uni->remap_location);
2029bf215546Sopenharmony_ci      offset = location - uni->remap_location;
2030bf215546Sopenharmony_ci   } else {
2031bf215546Sopenharmony_ci      uni = validate_uniform_parameters(location, count, &offset,
2032bf215546Sopenharmony_ci                                        ctx, shProg, "glUniformHandleui64*ARB");
2033bf215546Sopenharmony_ci      if (!uni)
2034bf215546Sopenharmony_ci         return;
2035bf215546Sopenharmony_ci
2036bf215546Sopenharmony_ci      if (!uni->is_bindless) {
2037bf215546Sopenharmony_ci         /* From section "Errors" of the ARB_bindless_texture spec:
2038bf215546Sopenharmony_ci          *
2039bf215546Sopenharmony_ci          * "The error INVALID_OPERATION is generated by
2040bf215546Sopenharmony_ci          *  UniformHandleui64{v}ARB if the sampler or image uniform being
2041bf215546Sopenharmony_ci          *  updated has the "bound_sampler" or "bound_image" layout qualifier."
2042bf215546Sopenharmony_ci          *
2043bf215546Sopenharmony_ci          * From section 4.4.6 of the ARB_bindless_texture spec:
2044bf215546Sopenharmony_ci          *
2045bf215546Sopenharmony_ci          * "In the absence of these qualifiers, sampler and image uniforms are
2046bf215546Sopenharmony_ci          *  considered "bound". Additionally, if GL_ARB_bindless_texture is
2047bf215546Sopenharmony_ci          *  not enabled, these uniforms are considered "bound"."
2048bf215546Sopenharmony_ci          */
2049bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
2050bf215546Sopenharmony_ci                     "glUniformHandleui64*ARB(non-bindless sampler/image uniform)");
2051bf215546Sopenharmony_ci         return;
2052bf215546Sopenharmony_ci      }
2053bf215546Sopenharmony_ci   }
2054bf215546Sopenharmony_ci
2055bf215546Sopenharmony_ci   const unsigned components = uni->type->vector_elements;
2056bf215546Sopenharmony_ci   const int size_mul = 2;
2057bf215546Sopenharmony_ci
2058bf215546Sopenharmony_ci   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
2059bf215546Sopenharmony_ci      log_uniform(values, GLSL_TYPE_UINT64, components, 1, count,
2060bf215546Sopenharmony_ci                  false, shProg, location, uni);
2061bf215546Sopenharmony_ci   }
2062bf215546Sopenharmony_ci
2063bf215546Sopenharmony_ci   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
2064bf215546Sopenharmony_ci    *
2065bf215546Sopenharmony_ci    *     "When loading N elements starting at an arbitrary position k in a
2066bf215546Sopenharmony_ci    *     uniform declared as an array, elements k through k + N - 1 in the
2067bf215546Sopenharmony_ci    *     array will be replaced with the new values. Values for any array
2068bf215546Sopenharmony_ci    *     element that exceeds the highest array element index used, as
2069bf215546Sopenharmony_ci    *     reported by GetActiveUniform, will be ignored by the GL."
2070bf215546Sopenharmony_ci    *
2071bf215546Sopenharmony_ci    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
2072bf215546Sopenharmony_ci    * will have already generated an error.
2073bf215546Sopenharmony_ci    */
2074bf215546Sopenharmony_ci   if (uni->array_elements != 0) {
2075bf215546Sopenharmony_ci      count = MIN2(count, (int) (uni->array_elements - offset));
2076bf215546Sopenharmony_ci   }
2077bf215546Sopenharmony_ci
2078bf215546Sopenharmony_ci
2079bf215546Sopenharmony_ci   /* Store the data in the "actual type" backing storage for the uniform.
2080bf215546Sopenharmony_ci    */
2081bf215546Sopenharmony_ci   if (ctx->Const.PackedDriverUniformStorage) {
2082bf215546Sopenharmony_ci      bool flushed = false;
2083bf215546Sopenharmony_ci
2084bf215546Sopenharmony_ci      for (unsigned s = 0; s < uni->num_driver_storage; s++) {
2085bf215546Sopenharmony_ci         void *storage = (gl_constant_value *)
2086bf215546Sopenharmony_ci            uni->driver_storage[s].data + (size_mul * offset * components);
2087bf215546Sopenharmony_ci         unsigned size = sizeof(uni->storage[0]) * components * count * size_mul;
2088bf215546Sopenharmony_ci
2089bf215546Sopenharmony_ci         if (!memcmp(storage, values, size))
2090bf215546Sopenharmony_ci            continue;
2091bf215546Sopenharmony_ci
2092bf215546Sopenharmony_ci         if (!flushed) {
2093bf215546Sopenharmony_ci            _mesa_flush_vertices_for_uniforms(ctx, uni);
2094bf215546Sopenharmony_ci            flushed = true;
2095bf215546Sopenharmony_ci         }
2096bf215546Sopenharmony_ci         memcpy(storage, values, size);
2097bf215546Sopenharmony_ci      }
2098bf215546Sopenharmony_ci      if (!flushed)
2099bf215546Sopenharmony_ci         return;
2100bf215546Sopenharmony_ci   } else {
2101bf215546Sopenharmony_ci      void *storage = &uni->storage[size_mul * components * offset];
2102bf215546Sopenharmony_ci      unsigned size = sizeof(uni->storage[0]) * components * count * size_mul;
2103bf215546Sopenharmony_ci
2104bf215546Sopenharmony_ci      if (!memcmp(storage, values, size))
2105bf215546Sopenharmony_ci         return;
2106bf215546Sopenharmony_ci
2107bf215546Sopenharmony_ci      _mesa_flush_vertices_for_uniforms(ctx, uni);
2108bf215546Sopenharmony_ci      memcpy(storage, values, size);
2109bf215546Sopenharmony_ci      _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
2110bf215546Sopenharmony_ci   }
2111bf215546Sopenharmony_ci
2112bf215546Sopenharmony_ci   if (uni->type->is_sampler()) {
2113bf215546Sopenharmony_ci      /* Mark this bindless sampler as not bound to a texture unit because
2114bf215546Sopenharmony_ci       * it refers to a texture handle.
2115bf215546Sopenharmony_ci       */
2116bf215546Sopenharmony_ci      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
2117bf215546Sopenharmony_ci         struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
2118bf215546Sopenharmony_ci
2119bf215546Sopenharmony_ci         /* If the shader stage doesn't use the sampler uniform, skip this. */
2120bf215546Sopenharmony_ci         if (!uni->opaque[i].active)
2121bf215546Sopenharmony_ci            continue;
2122bf215546Sopenharmony_ci
2123bf215546Sopenharmony_ci         for (int j = 0; j < count; j++) {
2124bf215546Sopenharmony_ci            unsigned unit = uni->opaque[i].index + offset + j;
2125bf215546Sopenharmony_ci            struct gl_bindless_sampler *sampler =
2126bf215546Sopenharmony_ci               &sh->Program->sh.BindlessSamplers[unit];
2127bf215546Sopenharmony_ci
2128bf215546Sopenharmony_ci            sampler->bound = false;
2129bf215546Sopenharmony_ci         }
2130bf215546Sopenharmony_ci
2131bf215546Sopenharmony_ci         update_bound_bindless_sampler_flag(sh->Program);
2132bf215546Sopenharmony_ci      }
2133bf215546Sopenharmony_ci   }
2134bf215546Sopenharmony_ci
2135bf215546Sopenharmony_ci   if (uni->type->is_image()) {
2136bf215546Sopenharmony_ci      /* Mark this bindless image as not bound to an image unit because it
2137bf215546Sopenharmony_ci       * refers to a texture handle.
2138bf215546Sopenharmony_ci       */
2139bf215546Sopenharmony_ci      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
2140bf215546Sopenharmony_ci         struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
2141bf215546Sopenharmony_ci
2142bf215546Sopenharmony_ci         /* If the shader stage doesn't use the sampler uniform, skip this. */
2143bf215546Sopenharmony_ci         if (!uni->opaque[i].active)
2144bf215546Sopenharmony_ci            continue;
2145bf215546Sopenharmony_ci
2146bf215546Sopenharmony_ci         for (int j = 0; j < count; j++) {
2147bf215546Sopenharmony_ci            unsigned unit = uni->opaque[i].index + offset + j;
2148bf215546Sopenharmony_ci            struct gl_bindless_image *image =
2149bf215546Sopenharmony_ci               &sh->Program->sh.BindlessImages[unit];
2150bf215546Sopenharmony_ci
2151bf215546Sopenharmony_ci            image->bound = false;
2152bf215546Sopenharmony_ci         }
2153bf215546Sopenharmony_ci
2154bf215546Sopenharmony_ci         update_bound_bindless_image_flag(sh->Program);
2155bf215546Sopenharmony_ci      }
2156bf215546Sopenharmony_ci   }
2157bf215546Sopenharmony_ci}
2158bf215546Sopenharmony_ci
2159bf215546Sopenharmony_ciextern "C" bool
2160bf215546Sopenharmony_ci_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
2161bf215546Sopenharmony_ci				 char *errMsg, size_t errMsgLength)
2162bf215546Sopenharmony_ci{
2163bf215546Sopenharmony_ci   /* Shader does not have samplers. */
2164bf215546Sopenharmony_ci   if (shProg->data->NumUniformStorage == 0)
2165bf215546Sopenharmony_ci      return true;
2166bf215546Sopenharmony_ci
2167bf215546Sopenharmony_ci   if (!shProg->SamplersValidated) {
2168bf215546Sopenharmony_ci      snprintf(errMsg, errMsgLength,
2169bf215546Sopenharmony_ci                     "active samplers with a different type "
2170bf215546Sopenharmony_ci                     "refer to the same texture image unit");
2171bf215546Sopenharmony_ci      return false;
2172bf215546Sopenharmony_ci   }
2173bf215546Sopenharmony_ci   return true;
2174bf215546Sopenharmony_ci}
2175bf215546Sopenharmony_ci
2176bf215546Sopenharmony_ciextern "C" bool
2177bf215546Sopenharmony_ci_mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline)
2178bf215546Sopenharmony_ci{
2179bf215546Sopenharmony_ci   /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
2180bf215546Sopenharmony_ci    * OpenGL 4.1 spec says:
2181bf215546Sopenharmony_ci    *
2182bf215546Sopenharmony_ci    *     "[INVALID_OPERATION] is generated by any command that transfers
2183bf215546Sopenharmony_ci    *     vertices to the GL if:
2184bf215546Sopenharmony_ci    *
2185bf215546Sopenharmony_ci    *         ...
2186bf215546Sopenharmony_ci    *
2187bf215546Sopenharmony_ci    *         - Any two active samplers in the current program object are of
2188bf215546Sopenharmony_ci    *           different types, but refer to the same texture image unit.
2189bf215546Sopenharmony_ci    *
2190bf215546Sopenharmony_ci    *         - The number of active samplers in the program exceeds the
2191bf215546Sopenharmony_ci    *           maximum number of texture image units allowed."
2192bf215546Sopenharmony_ci    */
2193bf215546Sopenharmony_ci
2194bf215546Sopenharmony_ci   GLbitfield mask;
2195bf215546Sopenharmony_ci   GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
2196bf215546Sopenharmony_ci   unsigned active_samplers = 0;
2197bf215546Sopenharmony_ci   const struct gl_program **prog =
2198bf215546Sopenharmony_ci      (const struct gl_program **) pipeline->CurrentProgram;
2199bf215546Sopenharmony_ci
2200bf215546Sopenharmony_ci
2201bf215546Sopenharmony_ci   memset(TexturesUsed, 0, sizeof(TexturesUsed));
2202bf215546Sopenharmony_ci
2203bf215546Sopenharmony_ci   for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) {
2204bf215546Sopenharmony_ci      if (!prog[idx])
2205bf215546Sopenharmony_ci         continue;
2206bf215546Sopenharmony_ci
2207bf215546Sopenharmony_ci      mask = prog[idx]->SamplersUsed;
2208bf215546Sopenharmony_ci      while (mask) {
2209bf215546Sopenharmony_ci         const int s = u_bit_scan(&mask);
2210bf215546Sopenharmony_ci         GLuint unit = prog[idx]->SamplerUnits[s];
2211bf215546Sopenharmony_ci         GLuint tgt = prog[idx]->sh.SamplerTargets[s];
2212bf215546Sopenharmony_ci
2213bf215546Sopenharmony_ci         /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a
2214bf215546Sopenharmony_ci          * great job of eliminating unused uniforms currently so for now
2215bf215546Sopenharmony_ci          * don't throw an error if two sampler types both point to 0.
2216bf215546Sopenharmony_ci          */
2217bf215546Sopenharmony_ci         if (unit == 0)
2218bf215546Sopenharmony_ci            continue;
2219bf215546Sopenharmony_ci
2220bf215546Sopenharmony_ci         if (TexturesUsed[unit] & ~(1 << tgt)) {
2221bf215546Sopenharmony_ci            pipeline->InfoLog =
2222bf215546Sopenharmony_ci               ralloc_asprintf(pipeline,
2223bf215546Sopenharmony_ci                     "Program %d: "
2224bf215546Sopenharmony_ci                     "Texture unit %d is accessed with 2 different types",
2225bf215546Sopenharmony_ci                     prog[idx]->Id, unit);
2226bf215546Sopenharmony_ci            return false;
2227bf215546Sopenharmony_ci         }
2228bf215546Sopenharmony_ci
2229bf215546Sopenharmony_ci         TexturesUsed[unit] |= (1 << tgt);
2230bf215546Sopenharmony_ci      }
2231bf215546Sopenharmony_ci
2232bf215546Sopenharmony_ci      active_samplers += prog[idx]->info.num_textures;
2233bf215546Sopenharmony_ci   }
2234bf215546Sopenharmony_ci
2235bf215546Sopenharmony_ci   if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) {
2236bf215546Sopenharmony_ci      pipeline->InfoLog =
2237bf215546Sopenharmony_ci         ralloc_asprintf(pipeline,
2238bf215546Sopenharmony_ci                         "the number of active samplers %d exceed the "
2239bf215546Sopenharmony_ci                         "maximum %d",
2240bf215546Sopenharmony_ci                         active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
2241bf215546Sopenharmony_ci      return false;
2242bf215546Sopenharmony_ci   }
2243bf215546Sopenharmony_ci
2244bf215546Sopenharmony_ci   return true;
2245bf215546Sopenharmony_ci}
2246