1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2003 VMware, Inc.
4bf215546Sopenharmony_ci * Copyright 2009 VMware, Inc.
5bf215546Sopenharmony_ci * All Rights Reserved.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
9bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
10bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
11bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
12bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
13bf215546Sopenharmony_ci * the following conditions:
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
16bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
17bf215546Sopenharmony_ci * of the Software.
18bf215546Sopenharmony_ci *
19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26bf215546Sopenharmony_ci *
27bf215546Sopenharmony_ci **************************************************************************/
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include <stdio.h>
30bf215546Sopenharmony_ci#include "arrayobj.h"
31bf215546Sopenharmony_ci#include "glheader.h"
32bf215546Sopenharmony_ci#include "c99_alloca.h"
33bf215546Sopenharmony_ci#include "context.h"
34bf215546Sopenharmony_ci#include "state.h"
35bf215546Sopenharmony_ci#include "draw.h"
36bf215546Sopenharmony_ci#include "draw_validate.h"
37bf215546Sopenharmony_ci#include "dispatch.h"
38bf215546Sopenharmony_ci#include "varray.h"
39bf215546Sopenharmony_ci#include "bufferobj.h"
40bf215546Sopenharmony_ci#include "enums.h"
41bf215546Sopenharmony_ci#include "macros.h"
42bf215546Sopenharmony_ci#include "transformfeedback.h"
43bf215546Sopenharmony_ci#include "pipe/p_state.h"
44bf215546Sopenharmony_ci#include "api_exec_decl.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include "state_tracker/st_context.h"
47bf215546Sopenharmony_ci#include "state_tracker/st_draw.h"
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_citypedef struct {
50bf215546Sopenharmony_ci   GLuint count;
51bf215546Sopenharmony_ci   GLuint primCount;
52bf215546Sopenharmony_ci   GLuint first;
53bf215546Sopenharmony_ci   GLuint baseInstance;
54bf215546Sopenharmony_ci} DrawArraysIndirectCommand;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_citypedef struct {
57bf215546Sopenharmony_ci   GLuint count;
58bf215546Sopenharmony_ci   GLuint primCount;
59bf215546Sopenharmony_ci   GLuint firstIndex;
60bf215546Sopenharmony_ci   GLint  baseVertex;
61bf215546Sopenharmony_ci   GLuint baseInstance;
62bf215546Sopenharmony_ci} DrawElementsIndirectCommand;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci/**
66bf215546Sopenharmony_ci * Want to figure out which fragment program inputs are actually
67bf215546Sopenharmony_ci * constant/current values from ctx->Current.  These should be
68bf215546Sopenharmony_ci * referenced as a tracked state variable rather than a fragment
69bf215546Sopenharmony_ci * program input, to save the overhead of putting a constant value in
70bf215546Sopenharmony_ci * every submitted vertex, transferring it to hardware, interpolating
71bf215546Sopenharmony_ci * it across the triangle, etc...
72bf215546Sopenharmony_ci *
73bf215546Sopenharmony_ci * When there is a VP bound, just use vp->outputs.  But when we're
74bf215546Sopenharmony_ci * generating vp from fixed function state, basically want to
75bf215546Sopenharmony_ci * calculate:
76bf215546Sopenharmony_ci *
77bf215546Sopenharmony_ci * vp_out_2_fp_in( vp_in_2_vp_out( varying_inputs ) |
78bf215546Sopenharmony_ci *                 potential_vp_outputs )
79bf215546Sopenharmony_ci *
80bf215546Sopenharmony_ci * Where potential_vp_outputs is calculated by looking at enabled
81bf215546Sopenharmony_ci * texgen, etc.
82bf215546Sopenharmony_ci *
83bf215546Sopenharmony_ci * The generated fragment program should then only declare inputs that
84bf215546Sopenharmony_ci * may vary or otherwise differ from the ctx->Current values.
85bf215546Sopenharmony_ci * Otherwise, the fp should track them as state values instead.
86bf215546Sopenharmony_ci */
87bf215546Sopenharmony_civoid
88bf215546Sopenharmony_ci_mesa_set_varying_vp_inputs(struct gl_context *ctx, GLbitfield varying_inputs)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   if (ctx->VertexProgram._VPModeOptimizesConstantAttribs &&
91bf215546Sopenharmony_ci       ctx->VertexProgram._VaryingInputs != varying_inputs) {
92bf215546Sopenharmony_ci      ctx->VertexProgram._VaryingInputs = varying_inputs;
93bf215546Sopenharmony_ci      ctx->NewState |= _NEW_FF_VERT_PROGRAM | _NEW_FF_FRAG_PROGRAM;
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci}
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci/**
99bf215546Sopenharmony_ci * Set the _DrawVAO and the net enabled arrays.
100bf215546Sopenharmony_ci * The vao->_Enabled bitmask is transformed due to position/generic0
101bf215546Sopenharmony_ci * as stored in vao->_AttributeMapMode. Then the filter bitmask is applied
102bf215546Sopenharmony_ci * to filter out arrays unwanted for the currently executed draw operation.
103bf215546Sopenharmony_ci * For example, the generic attributes are masked out form the _DrawVAO's
104bf215546Sopenharmony_ci * enabled arrays when a fixed function array draw is executed.
105bf215546Sopenharmony_ci */
106bf215546Sopenharmony_civoid
107bf215546Sopenharmony_ci_mesa_set_draw_vao(struct gl_context *ctx, struct gl_vertex_array_object *vao,
108bf215546Sopenharmony_ci                   GLbitfield filter)
109bf215546Sopenharmony_ci{
110bf215546Sopenharmony_ci   struct gl_vertex_array_object **ptr = &ctx->Array._DrawVAO;
111bf215546Sopenharmony_ci   bool new_vertex_buffers = false, new_vertex_elements = false;
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   if (*ptr != vao) {
114bf215546Sopenharmony_ci      _mesa_reference_vao_(ctx, ptr, vao);
115bf215546Sopenharmony_ci      new_vertex_buffers = true;
116bf215546Sopenharmony_ci      new_vertex_elements = true;
117bf215546Sopenharmony_ci   }
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   if (vao->NewVertexBuffers || vao->NewVertexElements) {
120bf215546Sopenharmony_ci      _mesa_update_vao_derived_arrays(ctx, vao);
121bf215546Sopenharmony_ci      new_vertex_buffers |= vao->NewVertexBuffers;
122bf215546Sopenharmony_ci      new_vertex_elements |= vao->NewVertexElements;
123bf215546Sopenharmony_ci      vao->NewVertexBuffers = false;
124bf215546Sopenharmony_ci      vao->NewVertexElements = false;
125bf215546Sopenharmony_ci   }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   assert(vao->_EnabledWithMapMode ==
128bf215546Sopenharmony_ci          _mesa_vao_enable_to_vp_inputs(vao->_AttributeMapMode, vao->Enabled));
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   /* Filter out unwanted arrays. */
131bf215546Sopenharmony_ci   const GLbitfield enabled = filter & vao->_EnabledWithMapMode;
132bf215546Sopenharmony_ci   if (ctx->Array._DrawVAOEnabledAttribs != enabled) {
133bf215546Sopenharmony_ci      ctx->Array._DrawVAOEnabledAttribs = enabled;
134bf215546Sopenharmony_ci      new_vertex_buffers = true;
135bf215546Sopenharmony_ci      new_vertex_elements = true;
136bf215546Sopenharmony_ci   }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   if (new_vertex_buffers || new_vertex_elements) {
139bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS;
140bf215546Sopenharmony_ci      ctx->Array.NewVertexElements |= new_vertex_elements;
141bf215546Sopenharmony_ci   }
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   _mesa_set_varying_vp_inputs(ctx, enabled);
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci/**
148bf215546Sopenharmony_ci * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
149bf215546Sopenharmony_ci * etc?  Also, do additional checking related to transformation feedback.
150bf215546Sopenharmony_ci * Note: this function cannot be called during glNewList(GL_COMPILE) because
151bf215546Sopenharmony_ci * this code depends on current transform feedback state.
152bf215546Sopenharmony_ci * Also, do additional checking related to tessellation shaders.
153bf215546Sopenharmony_ci */
154bf215546Sopenharmony_cistatic GLenum
155bf215546Sopenharmony_civalid_prim_mode_custom(struct gl_context *ctx, GLenum mode,
156bf215546Sopenharmony_ci                       GLbitfield valid_prim_mask)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci#if DEBUG
159bf215546Sopenharmony_ci   unsigned mask = ctx->ValidPrimMask;
160bf215546Sopenharmony_ci   unsigned mask_indexed = ctx->ValidPrimMaskIndexed;
161bf215546Sopenharmony_ci   bool drawpix_valid = ctx->DrawPixValid;
162bf215546Sopenharmony_ci   _mesa_update_valid_to_render_state(ctx);
163bf215546Sopenharmony_ci   assert(mask == ctx->ValidPrimMask &&
164bf215546Sopenharmony_ci          mask_indexed == ctx->ValidPrimMaskIndexed &&
165bf215546Sopenharmony_ci          drawpix_valid == ctx->DrawPixValid);
166bf215546Sopenharmony_ci#endif
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   /* All primitive type enums are less than 32, so we can use the shift. */
169bf215546Sopenharmony_ci   if (mode >= 32 || !((1u << mode) & valid_prim_mask)) {
170bf215546Sopenharmony_ci      /* If the primitive type is not in SupportedPrimMask, set GL_INVALID_ENUM,
171bf215546Sopenharmony_ci       * else set DrawGLError (e.g. GL_INVALID_OPERATION).
172bf215546Sopenharmony_ci       */
173bf215546Sopenharmony_ci      return mode >= 32 || !((1u << mode) & ctx->SupportedPrimMask) ?
174bf215546Sopenharmony_ci               GL_INVALID_ENUM : ctx->DrawGLError;
175bf215546Sopenharmony_ci   }
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   return GL_NO_ERROR;
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ciGLenum
181bf215546Sopenharmony_ci_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode)
182bf215546Sopenharmony_ci{
183bf215546Sopenharmony_ci   return valid_prim_mode_custom(ctx, mode, ctx->ValidPrimMask);
184bf215546Sopenharmony_ci}
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_cistatic GLenum
187bf215546Sopenharmony_civalid_prim_mode_indexed(struct gl_context *ctx, GLenum mode)
188bf215546Sopenharmony_ci{
189bf215546Sopenharmony_ci   return valid_prim_mode_custom(ctx, mode, ctx->ValidPrimMaskIndexed);
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci/**
193bf215546Sopenharmony_ci * Verify that the element type is valid.
194bf215546Sopenharmony_ci *
195bf215546Sopenharmony_ci * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
196bf215546Sopenharmony_ci */
197bf215546Sopenharmony_cistatic GLenum
198bf215546Sopenharmony_civalid_elements_type(struct gl_context *ctx, GLenum type)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   /* GL_UNSIGNED_BYTE  = 0x1401
201bf215546Sopenharmony_ci    * GL_UNSIGNED_SHORT = 0x1403
202bf215546Sopenharmony_ci    * GL_UNSIGNED_INT   = 0x1405
203bf215546Sopenharmony_ci    *
204bf215546Sopenharmony_ci    * The trick is that bit 1 and bit 2 mean USHORT and UINT, respectively.
205bf215546Sopenharmony_ci    * After clearing those two bits (with ~6), we should get UBYTE.
206bf215546Sopenharmony_ci    * Both bits can't be set, because the enum would be greater than UINT.
207bf215546Sopenharmony_ci    */
208bf215546Sopenharmony_ci   if (!(type <= GL_UNSIGNED_INT && (type & ~6) == GL_UNSIGNED_BYTE))
209bf215546Sopenharmony_ci      return GL_INVALID_ENUM;
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   return GL_NO_ERROR;
212bf215546Sopenharmony_ci}
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_cistatic inline bool
215bf215546Sopenharmony_ciindices_aligned(unsigned index_size_shift, const GLvoid *indices)
216bf215546Sopenharmony_ci{
217bf215546Sopenharmony_ci   /* Require that indices are aligned to the element size. GL doesn't specify
218bf215546Sopenharmony_ci    * an error for this, but the ES 3.0 spec says:
219bf215546Sopenharmony_ci    *
220bf215546Sopenharmony_ci    *    "Clients must align data elements consistently with the requirements
221bf215546Sopenharmony_ci    *     of the client platform, with an additional base-level requirement
222bf215546Sopenharmony_ci    *     that an offset within a buffer to a datum comprising N basic machine
223bf215546Sopenharmony_ci    *     units be a multiple of N"
224bf215546Sopenharmony_ci    *
225bf215546Sopenharmony_ci    * This is only required by index buffers, not user indices.
226bf215546Sopenharmony_ci    */
227bf215546Sopenharmony_ci   return ((uintptr_t)indices & ((1 << index_size_shift) - 1)) == 0;
228bf215546Sopenharmony_ci}
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_cistatic GLenum
231bf215546Sopenharmony_civalidate_DrawElements_common(struct gl_context *ctx, GLenum mode,
232bf215546Sopenharmony_ci                             GLsizei count, GLsizei numInstances, GLenum type)
233bf215546Sopenharmony_ci{
234bf215546Sopenharmony_ci   if (count < 0 || numInstances < 0)
235bf215546Sopenharmony_ci      return GL_INVALID_VALUE;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   GLenum error = valid_prim_mode_indexed(ctx, mode);
238bf215546Sopenharmony_ci   if (error)
239bf215546Sopenharmony_ci      return error;
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   return valid_elements_type(ctx, type);
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci/**
245bf215546Sopenharmony_ci * Error checking for glDrawElements().  Includes parameter checking
246bf215546Sopenharmony_ci * and VBO bounds checking.
247bf215546Sopenharmony_ci * \return GL_TRUE if OK to render, GL_FALSE if error found
248bf215546Sopenharmony_ci */
249bf215546Sopenharmony_cistatic GLboolean
250bf215546Sopenharmony_ci_mesa_validate_DrawElements(struct gl_context *ctx,
251bf215546Sopenharmony_ci                            GLenum mode, GLsizei count, GLenum type)
252bf215546Sopenharmony_ci{
253bf215546Sopenharmony_ci   GLenum error = validate_DrawElements_common(ctx, mode, count, 1, type);
254bf215546Sopenharmony_ci   if (error)
255bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawElements");
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   return !error;
258bf215546Sopenharmony_ci}
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci/**
262bf215546Sopenharmony_ci * Error checking for glMultiDrawElements().  Includes parameter checking
263bf215546Sopenharmony_ci * and VBO bounds checking.
264bf215546Sopenharmony_ci * \return GL_TRUE if OK to render, GL_FALSE if error found
265bf215546Sopenharmony_ci */
266bf215546Sopenharmony_cistatic GLboolean
267bf215546Sopenharmony_ci_mesa_validate_MultiDrawElements(struct gl_context *ctx,
268bf215546Sopenharmony_ci                                 GLenum mode, const GLsizei *count,
269bf215546Sopenharmony_ci                                 GLenum type, const GLvoid * const *indices,
270bf215546Sopenharmony_ci                                 GLsizei primcount)
271bf215546Sopenharmony_ci{
272bf215546Sopenharmony_ci   GLenum error;
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   /*
275bf215546Sopenharmony_ci    * Section 2.3.1 (Errors) of the OpenGL 4.5 (Core Profile) spec says:
276bf215546Sopenharmony_ci    *
277bf215546Sopenharmony_ci    *    "If a negative number is provided where an argument of type sizei or
278bf215546Sopenharmony_ci    *     sizeiptr is specified, an INVALID_VALUE error is generated."
279bf215546Sopenharmony_ci    *
280bf215546Sopenharmony_ci    * and in the same section:
281bf215546Sopenharmony_ci    *
282bf215546Sopenharmony_ci    *    "In other cases, there are no side effects unless otherwise noted;
283bf215546Sopenharmony_ci    *     the command which generates the error is ignored so that it has no
284bf215546Sopenharmony_ci    *     effect on GL state or framebuffer contents."
285bf215546Sopenharmony_ci    *
286bf215546Sopenharmony_ci    * Hence, check both primcount and all the count[i].
287bf215546Sopenharmony_ci    */
288bf215546Sopenharmony_ci   if (primcount < 0) {
289bf215546Sopenharmony_ci      error = GL_INVALID_VALUE;
290bf215546Sopenharmony_ci   } else {
291bf215546Sopenharmony_ci      error = valid_prim_mode_indexed(ctx, mode);
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci      if (!error) {
294bf215546Sopenharmony_ci         error = valid_elements_type(ctx, type);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci         if (!error) {
297bf215546Sopenharmony_ci            for (int i = 0; i < primcount; i++) {
298bf215546Sopenharmony_ci               if (count[i] < 0) {
299bf215546Sopenharmony_ci                  error = GL_INVALID_VALUE;
300bf215546Sopenharmony_ci                  break;
301bf215546Sopenharmony_ci               }
302bf215546Sopenharmony_ci            }
303bf215546Sopenharmony_ci         }
304bf215546Sopenharmony_ci      }
305bf215546Sopenharmony_ci   }
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   if (error)
308bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawElements");
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   /* Not using a VBO for indices, so avoid NULL pointer derefs later.
311bf215546Sopenharmony_ci    */
312bf215546Sopenharmony_ci   if (!ctx->Array.VAO->IndexBufferObj) {
313bf215546Sopenharmony_ci      for (int i = 0; i < primcount; i++) {
314bf215546Sopenharmony_ci         if (!indices[i])
315bf215546Sopenharmony_ci            return GL_FALSE;
316bf215546Sopenharmony_ci      }
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   return !error;
320bf215546Sopenharmony_ci}
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci/**
324bf215546Sopenharmony_ci * Error checking for glDrawRangeElements().  Includes parameter checking
325bf215546Sopenharmony_ci * and VBO bounds checking.
326bf215546Sopenharmony_ci * \return GL_TRUE if OK to render, GL_FALSE if error found
327bf215546Sopenharmony_ci */
328bf215546Sopenharmony_cistatic GLboolean
329bf215546Sopenharmony_ci_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
330bf215546Sopenharmony_ci                                 GLuint start, GLuint end,
331bf215546Sopenharmony_ci                                 GLsizei count, GLenum type)
332bf215546Sopenharmony_ci{
333bf215546Sopenharmony_ci   GLenum error;
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   if (end < start) {
336bf215546Sopenharmony_ci      error = GL_INVALID_VALUE;
337bf215546Sopenharmony_ci   } else {
338bf215546Sopenharmony_ci      error = validate_DrawElements_common(ctx, mode, count, 1, type);
339bf215546Sopenharmony_ci   }
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   if (error)
342bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawRangeElements");
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   return !error;
345bf215546Sopenharmony_ci}
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_cistatic bool
349bf215546Sopenharmony_cineed_xfb_remaining_prims_check(const struct gl_context *ctx)
350bf215546Sopenharmony_ci{
351bf215546Sopenharmony_ci   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
352bf215546Sopenharmony_ci    * Primitive Capture):
353bf215546Sopenharmony_ci    *
354bf215546Sopenharmony_ci    *   The error INVALID_OPERATION is generated by DrawArrays and
355bf215546Sopenharmony_ci    *   DrawArraysInstanced if recording the vertices of a primitive to the
356bf215546Sopenharmony_ci    *   buffer objects being used for transform feedback purposes would result
357bf215546Sopenharmony_ci    *   in either exceeding the limits of any buffer object’s size, or in
358bf215546Sopenharmony_ci    *   exceeding the end position offset + size − 1, as set by
359bf215546Sopenharmony_ci    *   BindBufferRange.
360bf215546Sopenharmony_ci    *
361bf215546Sopenharmony_ci    * This is in contrast to the behaviour of desktop GL, where the extra
362bf215546Sopenharmony_ci    * primitives are silently dropped from the transform feedback buffer.
363bf215546Sopenharmony_ci    *
364bf215546Sopenharmony_ci    * This text is removed in ES 3.2, presumably because it's not really
365bf215546Sopenharmony_ci    * implementable with geometry and tessellation shaders.  In fact,
366bf215546Sopenharmony_ci    * the OES_geometry_shader spec says:
367bf215546Sopenharmony_ci    *
368bf215546Sopenharmony_ci    *    "(13) Does this extension change how transform feedback operates
369bf215546Sopenharmony_ci    *     compared to unextended OpenGL ES 3.0 or 3.1?
370bf215546Sopenharmony_ci    *
371bf215546Sopenharmony_ci    *     RESOLVED: Yes. Because dynamic geometry amplification in a geometry
372bf215546Sopenharmony_ci    *     shader can make it difficult if not impossible to predict the amount
373bf215546Sopenharmony_ci    *     of geometry that may be generated in advance of executing the shader,
374bf215546Sopenharmony_ci    *     the draw-time error for transform feedback buffer overflow conditions
375bf215546Sopenharmony_ci    *     is removed and replaced with the GL behavior (primitives are not
376bf215546Sopenharmony_ci    *     written and the corresponding counter is not updated)..."
377bf215546Sopenharmony_ci    */
378bf215546Sopenharmony_ci   return _mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx) &&
379bf215546Sopenharmony_ci          !_mesa_has_OES_geometry_shader(ctx) &&
380bf215546Sopenharmony_ci          !_mesa_has_OES_tessellation_shader(ctx);
381bf215546Sopenharmony_ci}
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci/**
385bf215546Sopenharmony_ci * Figure out the number of transform feedback primitives that will be output
386bf215546Sopenharmony_ci * considering the drawing mode, number of vertices, and instance count,
387bf215546Sopenharmony_ci * assuming that no geometry shading is done and primitive restart is not
388bf215546Sopenharmony_ci * used.
389bf215546Sopenharmony_ci *
390bf215546Sopenharmony_ci * This is used by driver back-ends in implementing the PRIMITIVES_GENERATED
391bf215546Sopenharmony_ci * and TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries.  It is also used to
392bf215546Sopenharmony_ci * pre-validate draw calls in GLES3 (where draw calls only succeed if there is
393bf215546Sopenharmony_ci * enough room in the transform feedback buffer for the result).
394bf215546Sopenharmony_ci */
395bf215546Sopenharmony_cistatic size_t
396bf215546Sopenharmony_cicount_tessellated_primitives(GLenum mode, GLuint count, GLuint num_instances)
397bf215546Sopenharmony_ci{
398bf215546Sopenharmony_ci   size_t num_primitives;
399bf215546Sopenharmony_ci   switch (mode) {
400bf215546Sopenharmony_ci   case GL_POINTS:
401bf215546Sopenharmony_ci      num_primitives = count;
402bf215546Sopenharmony_ci      break;
403bf215546Sopenharmony_ci   case GL_LINE_STRIP:
404bf215546Sopenharmony_ci      num_primitives = count >= 2 ? count - 1 : 0;
405bf215546Sopenharmony_ci      break;
406bf215546Sopenharmony_ci   case GL_LINE_LOOP:
407bf215546Sopenharmony_ci      num_primitives = count >= 2 ? count : 0;
408bf215546Sopenharmony_ci      break;
409bf215546Sopenharmony_ci   case GL_LINES:
410bf215546Sopenharmony_ci      num_primitives = count / 2;
411bf215546Sopenharmony_ci      break;
412bf215546Sopenharmony_ci   case GL_TRIANGLE_STRIP:
413bf215546Sopenharmony_ci   case GL_TRIANGLE_FAN:
414bf215546Sopenharmony_ci   case GL_POLYGON:
415bf215546Sopenharmony_ci      num_primitives = count >= 3 ? count - 2 : 0;
416bf215546Sopenharmony_ci      break;
417bf215546Sopenharmony_ci   case GL_TRIANGLES:
418bf215546Sopenharmony_ci      num_primitives = count / 3;
419bf215546Sopenharmony_ci      break;
420bf215546Sopenharmony_ci   case GL_QUAD_STRIP:
421bf215546Sopenharmony_ci      num_primitives = count >= 4 ? ((count / 2) - 1) * 2 : 0;
422bf215546Sopenharmony_ci      break;
423bf215546Sopenharmony_ci   case GL_QUADS:
424bf215546Sopenharmony_ci      num_primitives = (count / 4) * 2;
425bf215546Sopenharmony_ci      break;
426bf215546Sopenharmony_ci   case GL_LINES_ADJACENCY:
427bf215546Sopenharmony_ci      num_primitives = count / 4;
428bf215546Sopenharmony_ci      break;
429bf215546Sopenharmony_ci   case GL_LINE_STRIP_ADJACENCY:
430bf215546Sopenharmony_ci      num_primitives = count >= 4 ? count - 3 : 0;
431bf215546Sopenharmony_ci      break;
432bf215546Sopenharmony_ci   case GL_TRIANGLES_ADJACENCY:
433bf215546Sopenharmony_ci      num_primitives = count / 6;
434bf215546Sopenharmony_ci      break;
435bf215546Sopenharmony_ci   case GL_TRIANGLE_STRIP_ADJACENCY:
436bf215546Sopenharmony_ci      num_primitives = count >= 6 ? (count - 4) / 2 : 0;
437bf215546Sopenharmony_ci      break;
438bf215546Sopenharmony_ci   default:
439bf215546Sopenharmony_ci      assert(!"Unexpected primitive type in count_tessellated_primitives");
440bf215546Sopenharmony_ci      num_primitives = 0;
441bf215546Sopenharmony_ci      break;
442bf215546Sopenharmony_ci   }
443bf215546Sopenharmony_ci   return num_primitives * num_instances;
444bf215546Sopenharmony_ci}
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_cistatic GLenum
448bf215546Sopenharmony_civalidate_draw_arrays(struct gl_context *ctx,
449bf215546Sopenharmony_ci                     GLenum mode, GLsizei count, GLsizei numInstances)
450bf215546Sopenharmony_ci{
451bf215546Sopenharmony_ci   if (count < 0 || numInstances < 0)
452bf215546Sopenharmony_ci      return GL_INVALID_VALUE;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   GLenum error = _mesa_valid_prim_mode(ctx, mode);
455bf215546Sopenharmony_ci   if (error)
456bf215546Sopenharmony_ci      return error;
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   if (need_xfb_remaining_prims_check(ctx)) {
459bf215546Sopenharmony_ci      struct gl_transform_feedback_object *xfb_obj
460bf215546Sopenharmony_ci         = ctx->TransformFeedback.CurrentObject;
461bf215546Sopenharmony_ci      size_t prim_count = count_tessellated_primitives(mode, count, numInstances);
462bf215546Sopenharmony_ci      if (xfb_obj->GlesRemainingPrims < prim_count)
463bf215546Sopenharmony_ci         return GL_INVALID_OPERATION;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci      xfb_obj->GlesRemainingPrims -= prim_count;
466bf215546Sopenharmony_ci   }
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   return GL_NO_ERROR;
469bf215546Sopenharmony_ci}
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci/**
472bf215546Sopenharmony_ci * Called from the tnl module to error check the function parameters and
473bf215546Sopenharmony_ci * verify that we really can draw something.
474bf215546Sopenharmony_ci * \return GL_TRUE if OK to render, GL_FALSE if error found
475bf215546Sopenharmony_ci */
476bf215546Sopenharmony_cistatic GLboolean
477bf215546Sopenharmony_ci_mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count)
478bf215546Sopenharmony_ci{
479bf215546Sopenharmony_ci   GLenum error = validate_draw_arrays(ctx, mode, count, 1);
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   if (error)
482bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawArrays");
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   return !error;
485bf215546Sopenharmony_ci}
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_cistatic GLboolean
489bf215546Sopenharmony_ci_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
490bf215546Sopenharmony_ci                                   GLsizei count, GLsizei numInstances)
491bf215546Sopenharmony_ci{
492bf215546Sopenharmony_ci   GLenum error;
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   if (first < 0) {
495bf215546Sopenharmony_ci      error = GL_INVALID_VALUE;
496bf215546Sopenharmony_ci   } else {
497bf215546Sopenharmony_ci      error = validate_draw_arrays(ctx, mode, count, numInstances);
498bf215546Sopenharmony_ci   }
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci   if (error)
501bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawArraysInstanced");
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   return !error;
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci/**
508bf215546Sopenharmony_ci * Called to error check the function parameters.
509bf215546Sopenharmony_ci *
510bf215546Sopenharmony_ci * Note that glMultiDrawArrays is not part of GLES, so there's limited scope
511bf215546Sopenharmony_ci * for sharing code with the validation of glDrawArrays.
512bf215546Sopenharmony_ci */
513bf215546Sopenharmony_cistatic bool
514bf215546Sopenharmony_ci_mesa_validate_MultiDrawArrays(struct gl_context *ctx, GLenum mode,
515bf215546Sopenharmony_ci                               const GLsizei *count, GLsizei primcount)
516bf215546Sopenharmony_ci{
517bf215546Sopenharmony_ci   GLenum error;
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   if (primcount < 0) {
520bf215546Sopenharmony_ci      error = GL_INVALID_VALUE;
521bf215546Sopenharmony_ci   } else {
522bf215546Sopenharmony_ci      error = _mesa_valid_prim_mode(ctx, mode);
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci      if (!error) {
525bf215546Sopenharmony_ci         for (int i = 0; i < primcount; ++i) {
526bf215546Sopenharmony_ci            if (count[i] < 0) {
527bf215546Sopenharmony_ci               error = GL_INVALID_VALUE;
528bf215546Sopenharmony_ci               break;
529bf215546Sopenharmony_ci            }
530bf215546Sopenharmony_ci         }
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci         if (!error) {
533bf215546Sopenharmony_ci            if (need_xfb_remaining_prims_check(ctx)) {
534bf215546Sopenharmony_ci               struct gl_transform_feedback_object *xfb_obj
535bf215546Sopenharmony_ci                  = ctx->TransformFeedback.CurrentObject;
536bf215546Sopenharmony_ci               size_t xfb_prim_count = 0;
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci               for (int i = 0; i < primcount; ++i) {
539bf215546Sopenharmony_ci                  xfb_prim_count +=
540bf215546Sopenharmony_ci                     count_tessellated_primitives(mode, count[i], 1);
541bf215546Sopenharmony_ci               }
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci               if (xfb_obj->GlesRemainingPrims < xfb_prim_count) {
544bf215546Sopenharmony_ci                  error = GL_INVALID_OPERATION;
545bf215546Sopenharmony_ci               } else {
546bf215546Sopenharmony_ci                  xfb_obj->GlesRemainingPrims -= xfb_prim_count;
547bf215546Sopenharmony_ci               }
548bf215546Sopenharmony_ci            }
549bf215546Sopenharmony_ci         }
550bf215546Sopenharmony_ci      }
551bf215546Sopenharmony_ci   }
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   if (error)
554bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawArrays");
555bf215546Sopenharmony_ci
556bf215546Sopenharmony_ci   return !error;
557bf215546Sopenharmony_ci}
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_cistatic GLboolean
561bf215546Sopenharmony_ci_mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
562bf215546Sopenharmony_ci                                     GLenum mode, GLsizei count, GLenum type,
563bf215546Sopenharmony_ci                                     GLsizei numInstances)
564bf215546Sopenharmony_ci{
565bf215546Sopenharmony_ci   GLenum error =
566bf215546Sopenharmony_ci      validate_DrawElements_common(ctx, mode, count, numInstances, type);
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   if (error)
569bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawElementsInstanced");
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci   return !error;
572bf215546Sopenharmony_ci}
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_cistatic GLboolean
576bf215546Sopenharmony_ci_mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
577bf215546Sopenharmony_ci                                     GLenum mode,
578bf215546Sopenharmony_ci                                     struct gl_transform_feedback_object *obj,
579bf215546Sopenharmony_ci                                     GLuint stream,
580bf215546Sopenharmony_ci                                     GLsizei numInstances)
581bf215546Sopenharmony_ci{
582bf215546Sopenharmony_ci   GLenum error;
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci   /* From the GL 4.5 specification, page 429:
585bf215546Sopenharmony_ci    * "An INVALID_VALUE error is generated if id is not the name of a
586bf215546Sopenharmony_ci    *  transform feedback object."
587bf215546Sopenharmony_ci    */
588bf215546Sopenharmony_ci   if (!obj || !obj->EverBound || stream >= ctx->Const.MaxVertexStreams ||
589bf215546Sopenharmony_ci       numInstances < 0) {
590bf215546Sopenharmony_ci      error = GL_INVALID_VALUE;
591bf215546Sopenharmony_ci   } else {
592bf215546Sopenharmony_ci      error = _mesa_valid_prim_mode(ctx, mode);
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci      if (!error) {
595bf215546Sopenharmony_ci         if (!obj->EndedAnytime)
596bf215546Sopenharmony_ci            error = GL_INVALID_OPERATION;
597bf215546Sopenharmony_ci      }
598bf215546Sopenharmony_ci   }
599bf215546Sopenharmony_ci
600bf215546Sopenharmony_ci   if (error)
601bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawTransformFeedback*");
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci   return !error;
604bf215546Sopenharmony_ci}
605bf215546Sopenharmony_ci
606bf215546Sopenharmony_cistatic GLenum
607bf215546Sopenharmony_civalid_draw_indirect(struct gl_context *ctx,
608bf215546Sopenharmony_ci                    GLenum mode, const GLvoid *indirect,
609bf215546Sopenharmony_ci                    GLsizei size)
610bf215546Sopenharmony_ci{
611bf215546Sopenharmony_ci   const uint64_t end = (uint64_t) (uintptr_t) indirect + size;
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_ci   /* OpenGL ES 3.1 spec. section 10.5:
614bf215546Sopenharmony_ci    *
615bf215546Sopenharmony_ci    *      "DrawArraysIndirect requires that all data sourced for the
616bf215546Sopenharmony_ci    *      command, including the DrawArraysIndirectCommand
617bf215546Sopenharmony_ci    *      structure,  be in buffer objects,  and may not be called when
618bf215546Sopenharmony_ci    *      the default vertex array object is bound."
619bf215546Sopenharmony_ci    */
620bf215546Sopenharmony_ci   if (ctx->API != API_OPENGL_COMPAT &&
621bf215546Sopenharmony_ci       ctx->Array.VAO == ctx->Array.DefaultVAO)
622bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_ci   /* From OpenGL ES 3.1 spec. section 10.5:
625bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if zero is bound to
626bf215546Sopenharmony_ci    *     VERTEX_ARRAY_BINDING, DRAW_INDIRECT_BUFFER or to any enabled
627bf215546Sopenharmony_ci    *     vertex array."
628bf215546Sopenharmony_ci    *
629bf215546Sopenharmony_ci    * Here we check that for each enabled vertex array we have a vertex
630bf215546Sopenharmony_ci    * buffer bound.
631bf215546Sopenharmony_ci    */
632bf215546Sopenharmony_ci   if (_mesa_is_gles31(ctx) &&
633bf215546Sopenharmony_ci       ctx->Array.VAO->Enabled & ~ctx->Array.VAO->VertexAttribBufferMask)
634bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   GLenum error = _mesa_valid_prim_mode(ctx, mode);
637bf215546Sopenharmony_ci   if (error)
638bf215546Sopenharmony_ci      return error;
639bf215546Sopenharmony_ci
640bf215546Sopenharmony_ci   /* OpenGL ES 3.1 specification, section 10.5:
641bf215546Sopenharmony_ci    *
642bf215546Sopenharmony_ci    *      "An INVALID_OPERATION error is generated if
643bf215546Sopenharmony_ci    *      transform feedback is active and not paused."
644bf215546Sopenharmony_ci    *
645bf215546Sopenharmony_ci    * The OES_geometry_shader spec says:
646bf215546Sopenharmony_ci    *
647bf215546Sopenharmony_ci    *    On p. 250 in the errors section for the DrawArraysIndirect command,
648bf215546Sopenharmony_ci    *    and on p. 254 in the errors section for the DrawElementsIndirect
649bf215546Sopenharmony_ci    *    command, delete the errors which state:
650bf215546Sopenharmony_ci    *
651bf215546Sopenharmony_ci    *    "An INVALID_OPERATION error is generated if transform feedback is
652bf215546Sopenharmony_ci    *    active and not paused."
653bf215546Sopenharmony_ci    *
654bf215546Sopenharmony_ci    *    (thus allowing transform feedback to work with indirect draw commands).
655bf215546Sopenharmony_ci    */
656bf215546Sopenharmony_ci   if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader &&
657bf215546Sopenharmony_ci       _mesa_is_xfb_active_and_unpaused(ctx))
658bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci   /* From OpenGL version 4.4. section 10.5
661bf215546Sopenharmony_ci    * and OpenGL ES 3.1, section 10.6:
662bf215546Sopenharmony_ci    *
663bf215546Sopenharmony_ci    *      "An INVALID_VALUE error is generated if indirect is not a
664bf215546Sopenharmony_ci    *       multiple of the size, in basic machine units, of uint."
665bf215546Sopenharmony_ci    */
666bf215546Sopenharmony_ci   if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1))
667bf215546Sopenharmony_ci      return GL_INVALID_VALUE;
668bf215546Sopenharmony_ci
669bf215546Sopenharmony_ci   if (!ctx->DrawIndirectBuffer)
670bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer))
673bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci   /* From the ARB_draw_indirect specification:
676bf215546Sopenharmony_ci    * "An INVALID_OPERATION error is generated if the commands source data
677bf215546Sopenharmony_ci    *  beyond the end of the buffer object [...]"
678bf215546Sopenharmony_ci    */
679bf215546Sopenharmony_ci   if (ctx->DrawIndirectBuffer->Size < end)
680bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
681bf215546Sopenharmony_ci
682bf215546Sopenharmony_ci   return GL_NO_ERROR;
683bf215546Sopenharmony_ci}
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_cistatic inline GLenum
686bf215546Sopenharmony_civalid_draw_indirect_elements(struct gl_context *ctx,
687bf215546Sopenharmony_ci                             GLenum mode, GLenum type, const GLvoid *indirect,
688bf215546Sopenharmony_ci                             GLsizeiptr size)
689bf215546Sopenharmony_ci{
690bf215546Sopenharmony_ci   GLenum error = valid_elements_type(ctx, type);
691bf215546Sopenharmony_ci   if (error)
692bf215546Sopenharmony_ci      return error;
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci   /*
695bf215546Sopenharmony_ci    * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
696bf215546Sopenharmony_ci    * may not come from a client array and must come from an index buffer.
697bf215546Sopenharmony_ci    * If no element array buffer is bound, an INVALID_OPERATION error is
698bf215546Sopenharmony_ci    * generated.
699bf215546Sopenharmony_ci    */
700bf215546Sopenharmony_ci   if (!ctx->Array.VAO->IndexBufferObj)
701bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci   return valid_draw_indirect(ctx, mode, indirect, size);
704bf215546Sopenharmony_ci}
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_cistatic GLboolean
707bf215546Sopenharmony_ci_mesa_valid_draw_indirect_multi(struct gl_context *ctx,
708bf215546Sopenharmony_ci                                GLsizei primcount, GLsizei stride,
709bf215546Sopenharmony_ci                                const char *name)
710bf215546Sopenharmony_ci{
711bf215546Sopenharmony_ci
712bf215546Sopenharmony_ci   /* From the ARB_multi_draw_indirect specification:
713bf215546Sopenharmony_ci    * "INVALID_VALUE is generated by MultiDrawArraysIndirect or
714bf215546Sopenharmony_ci    *  MultiDrawElementsIndirect if <primcount> is negative."
715bf215546Sopenharmony_ci    *
716bf215546Sopenharmony_ci    * "<primcount> must be positive, otherwise an INVALID_VALUE error will
717bf215546Sopenharmony_ci    *  be generated."
718bf215546Sopenharmony_ci    */
719bf215546Sopenharmony_ci   if (primcount < 0) {
720bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
721bf215546Sopenharmony_ci      return GL_FALSE;
722bf215546Sopenharmony_ci   }
723bf215546Sopenharmony_ci
724bf215546Sopenharmony_ci
725bf215546Sopenharmony_ci   /* From the ARB_multi_draw_indirect specification:
726bf215546Sopenharmony_ci    * "<stride> must be a multiple of four, otherwise an INVALID_VALUE
727bf215546Sopenharmony_ci    *  error is generated."
728bf215546Sopenharmony_ci    */
729bf215546Sopenharmony_ci   if (stride % 4) {
730bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);
731bf215546Sopenharmony_ci      return GL_FALSE;
732bf215546Sopenharmony_ci   }
733bf215546Sopenharmony_ci
734bf215546Sopenharmony_ci   return GL_TRUE;
735bf215546Sopenharmony_ci}
736bf215546Sopenharmony_ci
737bf215546Sopenharmony_cistatic GLboolean
738bf215546Sopenharmony_ci_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
739bf215546Sopenharmony_ci                                  GLenum mode,
740bf215546Sopenharmony_ci                                  const GLvoid *indirect)
741bf215546Sopenharmony_ci{
742bf215546Sopenharmony_ci   const unsigned drawArraysNumParams = 4;
743bf215546Sopenharmony_ci   GLenum error =
744bf215546Sopenharmony_ci      valid_draw_indirect(ctx, mode, indirect,
745bf215546Sopenharmony_ci                          drawArraysNumParams * sizeof(GLuint));
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_ci   if (error)
748bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawArraysIndirect");
749bf215546Sopenharmony_ci
750bf215546Sopenharmony_ci   return !error;
751bf215546Sopenharmony_ci}
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_cistatic GLboolean
754bf215546Sopenharmony_ci_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
755bf215546Sopenharmony_ci                                    GLenum mode, GLenum type,
756bf215546Sopenharmony_ci                                    const GLvoid *indirect)
757bf215546Sopenharmony_ci{
758bf215546Sopenharmony_ci   const unsigned drawElementsNumParams = 5;
759bf215546Sopenharmony_ci   GLenum error = valid_draw_indirect_elements(ctx, mode, type, indirect,
760bf215546Sopenharmony_ci                                               drawElementsNumParams *
761bf215546Sopenharmony_ci                                               sizeof(GLuint));
762bf215546Sopenharmony_ci   if (error)
763bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glDrawElementsIndirect");
764bf215546Sopenharmony_ci
765bf215546Sopenharmony_ci   return !error;
766bf215546Sopenharmony_ci}
767bf215546Sopenharmony_ci
768bf215546Sopenharmony_cistatic GLboolean
769bf215546Sopenharmony_ci_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
770bf215546Sopenharmony_ci                                       GLenum mode,
771bf215546Sopenharmony_ci                                       const GLvoid *indirect,
772bf215546Sopenharmony_ci                                       GLsizei primcount, GLsizei stride)
773bf215546Sopenharmony_ci{
774bf215546Sopenharmony_ci   GLsizeiptr size = 0;
775bf215546Sopenharmony_ci   const unsigned drawArraysNumParams = 4;
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
778bf215546Sopenharmony_ci   assert(stride != 0);
779bf215546Sopenharmony_ci
780bf215546Sopenharmony_ci   if (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
781bf215546Sopenharmony_ci                                        "glMultiDrawArraysIndirect"))
782bf215546Sopenharmony_ci      return GL_FALSE;
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_ci   /* number of bytes of the indirect buffer which will be read */
785bf215546Sopenharmony_ci   size = primcount
786bf215546Sopenharmony_ci      ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
787bf215546Sopenharmony_ci      : 0;
788bf215546Sopenharmony_ci
789bf215546Sopenharmony_ci   GLenum error = valid_draw_indirect(ctx, mode, indirect, size);
790bf215546Sopenharmony_ci   if (error)
791bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawArraysIndirect");
792bf215546Sopenharmony_ci
793bf215546Sopenharmony_ci   return !error;
794bf215546Sopenharmony_ci}
795bf215546Sopenharmony_ci
796bf215546Sopenharmony_cistatic GLboolean
797bf215546Sopenharmony_ci_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
798bf215546Sopenharmony_ci                                         GLenum mode, GLenum type,
799bf215546Sopenharmony_ci                                         const GLvoid *indirect,
800bf215546Sopenharmony_ci                                         GLsizei primcount, GLsizei stride)
801bf215546Sopenharmony_ci{
802bf215546Sopenharmony_ci   GLsizeiptr size = 0;
803bf215546Sopenharmony_ci   const unsigned drawElementsNumParams = 5;
804bf215546Sopenharmony_ci
805bf215546Sopenharmony_ci   /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
806bf215546Sopenharmony_ci   assert(stride != 0);
807bf215546Sopenharmony_ci
808bf215546Sopenharmony_ci   if (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
809bf215546Sopenharmony_ci                                        "glMultiDrawElementsIndirect"))
810bf215546Sopenharmony_ci      return GL_FALSE;
811bf215546Sopenharmony_ci
812bf215546Sopenharmony_ci   /* number of bytes of the indirect buffer which will be read */
813bf215546Sopenharmony_ci   size = primcount
814bf215546Sopenharmony_ci      ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
815bf215546Sopenharmony_ci      : 0;
816bf215546Sopenharmony_ci
817bf215546Sopenharmony_ci   GLenum error = valid_draw_indirect_elements(ctx, mode, type, indirect,
818bf215546Sopenharmony_ci                                               size);
819bf215546Sopenharmony_ci   if (error)
820bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawElementsIndirect");
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci   return !error;
823bf215546Sopenharmony_ci}
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_cistatic GLenum
826bf215546Sopenharmony_civalid_draw_indirect_parameters(struct gl_context *ctx,
827bf215546Sopenharmony_ci                               GLintptr drawcount)
828bf215546Sopenharmony_ci{
829bf215546Sopenharmony_ci   /* From the ARB_indirect_parameters specification:
830bf215546Sopenharmony_ci    * "INVALID_VALUE is generated by MultiDrawArraysIndirectCountARB or
831bf215546Sopenharmony_ci    *  MultiDrawElementsIndirectCountARB if <drawcount> is not a multiple of
832bf215546Sopenharmony_ci    *  four."
833bf215546Sopenharmony_ci    */
834bf215546Sopenharmony_ci   if (drawcount & 3)
835bf215546Sopenharmony_ci      return GL_INVALID_VALUE;
836bf215546Sopenharmony_ci
837bf215546Sopenharmony_ci   /* From the ARB_indirect_parameters specification:
838bf215546Sopenharmony_ci    * "INVALID_OPERATION is generated by MultiDrawArraysIndirectCountARB or
839bf215546Sopenharmony_ci    *  MultiDrawElementsIndirectCountARB if no buffer is bound to the
840bf215546Sopenharmony_ci    *  PARAMETER_BUFFER_ARB binding point."
841bf215546Sopenharmony_ci    */
842bf215546Sopenharmony_ci   if (!ctx->ParameterBuffer)
843bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
844bf215546Sopenharmony_ci
845bf215546Sopenharmony_ci   if (_mesa_check_disallowed_mapping(ctx->ParameterBuffer))
846bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
847bf215546Sopenharmony_ci
848bf215546Sopenharmony_ci   /* From the ARB_indirect_parameters specification:
849bf215546Sopenharmony_ci    * "INVALID_OPERATION is generated by MultiDrawArraysIndirectCountARB or
850bf215546Sopenharmony_ci    *  MultiDrawElementsIndirectCountARB if reading a <sizei> typed value
851bf215546Sopenharmony_ci    *  from the buffer bound to the PARAMETER_BUFFER_ARB target at the offset
852bf215546Sopenharmony_ci    *  specified by <drawcount> would result in an out-of-bounds access."
853bf215546Sopenharmony_ci    */
854bf215546Sopenharmony_ci   if (ctx->ParameterBuffer->Size < drawcount + sizeof(GLsizei))
855bf215546Sopenharmony_ci      return GL_INVALID_OPERATION;
856bf215546Sopenharmony_ci
857bf215546Sopenharmony_ci   return GL_NO_ERROR;
858bf215546Sopenharmony_ci}
859bf215546Sopenharmony_ci
860bf215546Sopenharmony_cistatic GLboolean
861bf215546Sopenharmony_ci_mesa_validate_MultiDrawArraysIndirectCount(struct gl_context *ctx,
862bf215546Sopenharmony_ci                                            GLenum mode,
863bf215546Sopenharmony_ci                                            GLintptr indirect,
864bf215546Sopenharmony_ci                                            GLintptr drawcount,
865bf215546Sopenharmony_ci                                            GLsizei maxdrawcount,
866bf215546Sopenharmony_ci                                            GLsizei stride)
867bf215546Sopenharmony_ci{
868bf215546Sopenharmony_ci   GLsizeiptr size = 0;
869bf215546Sopenharmony_ci   const unsigned drawArraysNumParams = 4;
870bf215546Sopenharmony_ci
871bf215546Sopenharmony_ci   /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
872bf215546Sopenharmony_ci   assert(stride != 0);
873bf215546Sopenharmony_ci
874bf215546Sopenharmony_ci   if (!_mesa_valid_draw_indirect_multi(ctx, maxdrawcount, stride,
875bf215546Sopenharmony_ci                                        "glMultiDrawArraysIndirectCountARB"))
876bf215546Sopenharmony_ci      return GL_FALSE;
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci   /* number of bytes of the indirect buffer which will be read */
879bf215546Sopenharmony_ci   size = maxdrawcount
880bf215546Sopenharmony_ci      ? (maxdrawcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
881bf215546Sopenharmony_ci      : 0;
882bf215546Sopenharmony_ci
883bf215546Sopenharmony_ci   GLenum error = valid_draw_indirect(ctx, mode, (void *)indirect, size);
884bf215546Sopenharmony_ci   if (!error)
885bf215546Sopenharmony_ci      error = valid_draw_indirect_parameters(ctx, drawcount);
886bf215546Sopenharmony_ci
887bf215546Sopenharmony_ci   if (error)
888bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawArraysIndirectCountARB");
889bf215546Sopenharmony_ci
890bf215546Sopenharmony_ci   return !error;
891bf215546Sopenharmony_ci}
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_cistatic GLboolean
894bf215546Sopenharmony_ci_mesa_validate_MultiDrawElementsIndirectCount(struct gl_context *ctx,
895bf215546Sopenharmony_ci                                              GLenum mode, GLenum type,
896bf215546Sopenharmony_ci                                              GLintptr indirect,
897bf215546Sopenharmony_ci                                              GLintptr drawcount,
898bf215546Sopenharmony_ci                                              GLsizei maxdrawcount,
899bf215546Sopenharmony_ci                                              GLsizei stride)
900bf215546Sopenharmony_ci{
901bf215546Sopenharmony_ci   GLsizeiptr size = 0;
902bf215546Sopenharmony_ci   const unsigned drawElementsNumParams = 5;
903bf215546Sopenharmony_ci
904bf215546Sopenharmony_ci   /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
905bf215546Sopenharmony_ci   assert(stride != 0);
906bf215546Sopenharmony_ci
907bf215546Sopenharmony_ci   if (!_mesa_valid_draw_indirect_multi(ctx, maxdrawcount, stride,
908bf215546Sopenharmony_ci                                        "glMultiDrawElementsIndirectCountARB"))
909bf215546Sopenharmony_ci      return GL_FALSE;
910bf215546Sopenharmony_ci
911bf215546Sopenharmony_ci   /* number of bytes of the indirect buffer which will be read */
912bf215546Sopenharmony_ci   size = maxdrawcount
913bf215546Sopenharmony_ci      ? (maxdrawcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
914bf215546Sopenharmony_ci      : 0;
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   GLenum error = valid_draw_indirect_elements(ctx, mode, type,
917bf215546Sopenharmony_ci                                               (void *)indirect, size);
918bf215546Sopenharmony_ci   if (!error)
919bf215546Sopenharmony_ci      error = valid_draw_indirect_parameters(ctx, drawcount);
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci   if (error)
922bf215546Sopenharmony_ci      _mesa_error(ctx, error, "glMultiDrawElementsIndirectCountARB");
923bf215546Sopenharmony_ci
924bf215546Sopenharmony_ci   return !error;
925bf215546Sopenharmony_ci}
926bf215546Sopenharmony_ci
927bf215546Sopenharmony_ci
928bf215546Sopenharmony_ci#define MAX_ALLOCA_PRIMS(prim) (50000 / sizeof(*prim))
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci/* Use calloc for large allocations and alloca for small allocations. */
931bf215546Sopenharmony_ci/* We have to use a macro because alloca is local within the function. */
932bf215546Sopenharmony_ci#define ALLOC_PRIMS(prim, primcount, func) do { \
933bf215546Sopenharmony_ci   if (unlikely(primcount > MAX_ALLOCA_PRIMS(prim))) { \
934bf215546Sopenharmony_ci      prim = calloc(primcount, sizeof(*prim)); \
935bf215546Sopenharmony_ci      if (!prim) { \
936bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, func); \
937bf215546Sopenharmony_ci         return; \
938bf215546Sopenharmony_ci      } \
939bf215546Sopenharmony_ci   } else { \
940bf215546Sopenharmony_ci      prim = alloca(primcount * sizeof(*prim)); \
941bf215546Sopenharmony_ci   } \
942bf215546Sopenharmony_ci} while (0)
943bf215546Sopenharmony_ci
944bf215546Sopenharmony_ci#define FREE_PRIMS(prim, primcount) do { \
945bf215546Sopenharmony_ci   if (primcount > MAX_ALLOCA_PRIMS(prim)) \
946bf215546Sopenharmony_ci      free(prim); \
947bf215546Sopenharmony_ci} while (0)
948bf215546Sopenharmony_ci
949bf215546Sopenharmony_ci
950bf215546Sopenharmony_ci/**
951bf215546Sopenharmony_ci * Called via Driver.DrawGallium. This is a fallback invoking Driver.Draw.
952bf215546Sopenharmony_ci */
953bf215546Sopenharmony_civoid
954bf215546Sopenharmony_ci_mesa_draw_gallium_fallback(struct gl_context *ctx,
955bf215546Sopenharmony_ci                            struct pipe_draw_info *info,
956bf215546Sopenharmony_ci                            unsigned drawid_offset,
957bf215546Sopenharmony_ci                            const struct pipe_draw_start_count_bias *draws,
958bf215546Sopenharmony_ci                            unsigned num_draws)
959bf215546Sopenharmony_ci{
960bf215546Sopenharmony_ci   struct _mesa_index_buffer ib;
961bf215546Sopenharmony_ci   unsigned index_size = info->index_size;
962bf215546Sopenharmony_ci   unsigned min_index = 0, max_index = ~0u;
963bf215546Sopenharmony_ci   bool index_bounds_valid = false;
964bf215546Sopenharmony_ci
965bf215546Sopenharmony_ci   if (!info->instance_count)
966bf215546Sopenharmony_ci      return;
967bf215546Sopenharmony_ci
968bf215546Sopenharmony_ci   if (index_size) {
969bf215546Sopenharmony_ci      if (info->index_bounds_valid) {
970bf215546Sopenharmony_ci         min_index = info->min_index;
971bf215546Sopenharmony_ci         max_index = info->max_index;
972bf215546Sopenharmony_ci         index_bounds_valid = true;
973bf215546Sopenharmony_ci      }
974bf215546Sopenharmony_ci   } else {
975bf215546Sopenharmony_ci      /* The index_bounds_valid field and min/max_index are not used for
976bf215546Sopenharmony_ci       * non-indexed draw calls (they are undefined), but classic drivers
977bf215546Sopenharmony_ci       * need the index bounds. They will be computed manually.
978bf215546Sopenharmony_ci       */
979bf215546Sopenharmony_ci      index_bounds_valid = true;
980bf215546Sopenharmony_ci   }
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_ci   ib.index_size_shift = util_logbase2(index_size);
983bf215546Sopenharmony_ci
984bf215546Sopenharmony_ci   /* Single draw or a fallback for user indices. */
985bf215546Sopenharmony_ci   if (num_draws == 1) {
986bf215546Sopenharmony_ci      if (!draws[0].count)
987bf215546Sopenharmony_ci         return;
988bf215546Sopenharmony_ci
989bf215546Sopenharmony_ci      if (index_size) {
990bf215546Sopenharmony_ci         ib.count = draws[0].count;
991bf215546Sopenharmony_ci
992bf215546Sopenharmony_ci         if (info->has_user_indices) {
993bf215546Sopenharmony_ci            ib.obj = NULL;
994bf215546Sopenharmony_ci            ib.ptr = (const char*)info->index.user;
995bf215546Sopenharmony_ci         } else {
996bf215546Sopenharmony_ci            ib.obj = info->index.gl_bo;
997bf215546Sopenharmony_ci            ib.ptr = NULL;
998bf215546Sopenharmony_ci         }
999bf215546Sopenharmony_ci      }
1000bf215546Sopenharmony_ci
1001bf215546Sopenharmony_ci      struct _mesa_prim prim;
1002bf215546Sopenharmony_ci      prim.mode = info->mode;
1003bf215546Sopenharmony_ci      prim.begin = 1;
1004bf215546Sopenharmony_ci      prim.end = 1;
1005bf215546Sopenharmony_ci      prim.start = draws[0].start;
1006bf215546Sopenharmony_ci      prim.count = draws[0].count;
1007bf215546Sopenharmony_ci      prim.basevertex = index_size ? draws[0].index_bias : 0;
1008bf215546Sopenharmony_ci      prim.draw_id = drawid_offset;
1009bf215546Sopenharmony_ci
1010bf215546Sopenharmony_ci      if (!index_size) {
1011bf215546Sopenharmony_ci         min_index = draws[0].start;
1012bf215546Sopenharmony_ci         max_index = draws[0].start + draws[0].count - 1;
1013bf215546Sopenharmony_ci      }
1014bf215546Sopenharmony_ci
1015bf215546Sopenharmony_ci      st_feedback_draw_vbo(ctx, &prim, 1, index_size ? &ib : NULL,
1016bf215546Sopenharmony_ci                           index_bounds_valid, info->primitive_restart,
1017bf215546Sopenharmony_ci                           info->restart_index, min_index, max_index,
1018bf215546Sopenharmony_ci                           info->instance_count, info->start_instance);
1019bf215546Sopenharmony_ci      return;
1020bf215546Sopenharmony_ci   }
1021bf215546Sopenharmony_ci
1022bf215546Sopenharmony_ci   struct _mesa_prim *prim;
1023bf215546Sopenharmony_ci   unsigned max_count = 0;
1024bf215546Sopenharmony_ci   unsigned num_prims = 0;
1025bf215546Sopenharmony_ci
1026bf215546Sopenharmony_ci   ALLOC_PRIMS(prim, num_draws, "DrawGallium");
1027bf215546Sopenharmony_ci
1028bf215546Sopenharmony_ci   min_index = ~0u;
1029bf215546Sopenharmony_ci   max_index = 0;
1030bf215546Sopenharmony_ci
1031bf215546Sopenharmony_ci   for (unsigned i = 0; i < num_draws; i++) {
1032bf215546Sopenharmony_ci      if (!draws[i].count)
1033bf215546Sopenharmony_ci         continue;
1034bf215546Sopenharmony_ci
1035bf215546Sopenharmony_ci      prim[num_prims].mode = info->mode;
1036bf215546Sopenharmony_ci      prim[num_prims].begin = 1;
1037bf215546Sopenharmony_ci      prim[num_prims].end = 1;
1038bf215546Sopenharmony_ci      prim[num_prims].start = draws[i].start;
1039bf215546Sopenharmony_ci      prim[num_prims].count = draws[i].count;
1040bf215546Sopenharmony_ci      prim[num_prims].basevertex = info->index_size ? draws[i].index_bias : 0;
1041bf215546Sopenharmony_ci      prim[num_prims].draw_id = drawid_offset + (info->increment_draw_id ? i : 0);
1042bf215546Sopenharmony_ci
1043bf215546Sopenharmony_ci      if (!index_size) {
1044bf215546Sopenharmony_ci         min_index = MIN2(min_index, draws[i].start);
1045bf215546Sopenharmony_ci         max_index = MAX2(max_index, draws[i].start + draws[i].count - 1);
1046bf215546Sopenharmony_ci      }
1047bf215546Sopenharmony_ci
1048bf215546Sopenharmony_ci      max_count = MAX2(max_count, prim[num_prims].count);
1049bf215546Sopenharmony_ci      num_prims++;
1050bf215546Sopenharmony_ci   }
1051bf215546Sopenharmony_ci
1052bf215546Sopenharmony_ci   if (info->index_size) {
1053bf215546Sopenharmony_ci      ib.count = max_count;
1054bf215546Sopenharmony_ci      ib.index_size_shift = util_logbase2(index_size);
1055bf215546Sopenharmony_ci
1056bf215546Sopenharmony_ci      if (info->has_user_indices) {
1057bf215546Sopenharmony_ci         ib.obj = NULL;
1058bf215546Sopenharmony_ci         ib.ptr = (const char*)info->index.user;
1059bf215546Sopenharmony_ci      } else {
1060bf215546Sopenharmony_ci         ib.obj = info->index.gl_bo;
1061bf215546Sopenharmony_ci         ib.ptr = NULL;
1062bf215546Sopenharmony_ci      }
1063bf215546Sopenharmony_ci   }
1064bf215546Sopenharmony_ci
1065bf215546Sopenharmony_ci   if (num_prims)
1066bf215546Sopenharmony_ci      st_feedback_draw_vbo(ctx, prim, num_prims, index_size ? &ib : NULL,
1067bf215546Sopenharmony_ci                           index_bounds_valid, info->primitive_restart,
1068bf215546Sopenharmony_ci                           info->restart_index, min_index, max_index,
1069bf215546Sopenharmony_ci                           info->instance_count, info->start_instance);
1070bf215546Sopenharmony_ci   FREE_PRIMS(prim, num_draws);
1071bf215546Sopenharmony_ci}
1072bf215546Sopenharmony_ci
1073bf215546Sopenharmony_ci
1074bf215546Sopenharmony_ci/**
1075bf215546Sopenharmony_ci * Called via Driver.DrawGallium. This is a fallback invoking Driver.Draw.
1076bf215546Sopenharmony_ci */
1077bf215546Sopenharmony_civoid
1078bf215546Sopenharmony_ci_mesa_draw_gallium_multimode_fallback(struct gl_context *ctx,
1079bf215546Sopenharmony_ci                                      struct pipe_draw_info *info,
1080bf215546Sopenharmony_ci                                      const struct pipe_draw_start_count_bias *draws,
1081bf215546Sopenharmony_ci                                      const unsigned char *mode,
1082bf215546Sopenharmony_ci                                      unsigned num_draws)
1083bf215546Sopenharmony_ci{
1084bf215546Sopenharmony_ci   unsigned i, first;
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci   /* Find consecutive draws where mode doesn't vary. */
1087bf215546Sopenharmony_ci   for (i = 0, first = 0; i <= num_draws; i++) {
1088bf215546Sopenharmony_ci      if (i == num_draws || mode[i] != mode[first]) {
1089bf215546Sopenharmony_ci         info->mode = mode[first];
1090bf215546Sopenharmony_ci         ctx->Driver.DrawGallium(ctx, info, 0, &draws[first], i - first);
1091bf215546Sopenharmony_ci         first = i;
1092bf215546Sopenharmony_ci      }
1093bf215546Sopenharmony_ci   }
1094bf215546Sopenharmony_ci}
1095bf215546Sopenharmony_ci
1096bf215546Sopenharmony_ci/**
1097bf215546Sopenharmony_ci * Check that element 'j' of the array has reasonable data.
1098bf215546Sopenharmony_ci * Map VBO if needed.
1099bf215546Sopenharmony_ci * For debugging purposes; not normally used.
1100bf215546Sopenharmony_ci */
1101bf215546Sopenharmony_cistatic void
1102bf215546Sopenharmony_cicheck_array_data(struct gl_context *ctx, struct gl_vertex_array_object *vao,
1103bf215546Sopenharmony_ci                 GLuint attrib, GLuint j)
1104bf215546Sopenharmony_ci{
1105bf215546Sopenharmony_ci   const struct gl_array_attributes *array = &vao->VertexAttrib[attrib];
1106bf215546Sopenharmony_ci   if (vao->Enabled & VERT_BIT(attrib)) {
1107bf215546Sopenharmony_ci      const struct gl_vertex_buffer_binding *binding =
1108bf215546Sopenharmony_ci         &vao->BufferBinding[array->BufferBindingIndex];
1109bf215546Sopenharmony_ci      struct gl_buffer_object *bo = binding->BufferObj;
1110bf215546Sopenharmony_ci      const void *data = array->Ptr;
1111bf215546Sopenharmony_ci      if (bo) {
1112bf215546Sopenharmony_ci         data = ADD_POINTERS(_mesa_vertex_attrib_address(array, binding),
1113bf215546Sopenharmony_ci                             bo->Mappings[MAP_INTERNAL].Pointer);
1114bf215546Sopenharmony_ci      }
1115bf215546Sopenharmony_ci      switch (array->Format.Type) {
1116bf215546Sopenharmony_ci      case GL_FLOAT:
1117bf215546Sopenharmony_ci         {
1118bf215546Sopenharmony_ci            GLfloat *f = (GLfloat *) ((GLubyte *) data + binding->Stride * j);
1119bf215546Sopenharmony_ci            GLint k;
1120bf215546Sopenharmony_ci            for (k = 0; k < array->Format.Size; k++) {
1121bf215546Sopenharmony_ci               if (util_is_inf_or_nan(f[k]) || f[k] >= 1.0e20F || f[k] <= -1.0e10F) {
1122bf215546Sopenharmony_ci                  printf("Bad array data:\n");
1123bf215546Sopenharmony_ci                  printf("  Element[%u].%u = %f\n", j, k, f[k]);
1124bf215546Sopenharmony_ci                  printf("  Array %u at %p\n", attrib, (void *) array);
1125bf215546Sopenharmony_ci                  printf("  Type 0x%x, Size %d, Stride %d\n",
1126bf215546Sopenharmony_ci                         array->Format.Type, array->Format.Size,
1127bf215546Sopenharmony_ci                         binding->Stride);
1128bf215546Sopenharmony_ci                  printf("  Address/offset %p in Buffer Object %u\n",
1129bf215546Sopenharmony_ci                         array->Ptr, bo ? bo->Name : 0);
1130bf215546Sopenharmony_ci                  f[k] = 1.0F;  /* XXX replace the bad value! */
1131bf215546Sopenharmony_ci               }
1132bf215546Sopenharmony_ci               /*assert(!util_is_inf_or_nan(f[k])); */
1133bf215546Sopenharmony_ci            }
1134bf215546Sopenharmony_ci         }
1135bf215546Sopenharmony_ci         break;
1136bf215546Sopenharmony_ci      default:
1137bf215546Sopenharmony_ci         ;
1138bf215546Sopenharmony_ci      }
1139bf215546Sopenharmony_ci   }
1140bf215546Sopenharmony_ci}
1141bf215546Sopenharmony_ci
1142bf215546Sopenharmony_ci
1143bf215546Sopenharmony_cistatic inline unsigned
1144bf215546Sopenharmony_ciget_index_size_shift(GLenum type)
1145bf215546Sopenharmony_ci{
1146bf215546Sopenharmony_ci   /* The type is already validated, so use a fast conversion.
1147bf215546Sopenharmony_ci    *
1148bf215546Sopenharmony_ci    * GL_UNSIGNED_BYTE  - GL_UNSIGNED_BYTE = 0
1149bf215546Sopenharmony_ci    * GL_UNSIGNED_SHORT - GL_UNSIGNED_BYTE = 2
1150bf215546Sopenharmony_ci    * GL_UNSIGNED_INT   - GL_UNSIGNED_BYTE = 4
1151bf215546Sopenharmony_ci    *
1152bf215546Sopenharmony_ci    * Divide by 2 to get 0,1,2.
1153bf215546Sopenharmony_ci    */
1154bf215546Sopenharmony_ci   return (type - GL_UNSIGNED_BYTE) >> 1;
1155bf215546Sopenharmony_ci}
1156bf215546Sopenharmony_ci
1157bf215546Sopenharmony_ci/**
1158bf215546Sopenharmony_ci * Examine the array's data for NaNs, etc.
1159bf215546Sopenharmony_ci * For debug purposes; not normally used.
1160bf215546Sopenharmony_ci */
1161bf215546Sopenharmony_cistatic void
1162bf215546Sopenharmony_cicheck_draw_elements_data(struct gl_context *ctx, GLsizei count,
1163bf215546Sopenharmony_ci                         GLenum elemType, const void *elements,
1164bf215546Sopenharmony_ci                         GLint basevertex)
1165bf215546Sopenharmony_ci{
1166bf215546Sopenharmony_ci   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1167bf215546Sopenharmony_ci   GLint i;
1168bf215546Sopenharmony_ci   GLuint k;
1169bf215546Sopenharmony_ci
1170bf215546Sopenharmony_ci   _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_ci   if (vao->IndexBufferObj)
1173bf215546Sopenharmony_ci       elements =
1174bf215546Sopenharmony_ci          ADD_POINTERS(vao->IndexBufferObj->Mappings[MAP_INTERNAL].Pointer, elements);
1175bf215546Sopenharmony_ci
1176bf215546Sopenharmony_ci   for (i = 0; i < count; i++) {
1177bf215546Sopenharmony_ci      GLuint j;
1178bf215546Sopenharmony_ci
1179bf215546Sopenharmony_ci      /* j = element[i] */
1180bf215546Sopenharmony_ci      switch (elemType) {
1181bf215546Sopenharmony_ci      case GL_UNSIGNED_BYTE:
1182bf215546Sopenharmony_ci         j = ((const GLubyte *) elements)[i];
1183bf215546Sopenharmony_ci         break;
1184bf215546Sopenharmony_ci      case GL_UNSIGNED_SHORT:
1185bf215546Sopenharmony_ci         j = ((const GLushort *) elements)[i];
1186bf215546Sopenharmony_ci         break;
1187bf215546Sopenharmony_ci      case GL_UNSIGNED_INT:
1188bf215546Sopenharmony_ci         j = ((const GLuint *) elements)[i];
1189bf215546Sopenharmony_ci         break;
1190bf215546Sopenharmony_ci      default:
1191bf215546Sopenharmony_ci         unreachable("Unexpected index buffer type");
1192bf215546Sopenharmony_ci      }
1193bf215546Sopenharmony_ci
1194bf215546Sopenharmony_ci      /* check element j of each enabled array */
1195bf215546Sopenharmony_ci      for (k = 0; k < VERT_ATTRIB_MAX; k++) {
1196bf215546Sopenharmony_ci         check_array_data(ctx, vao, k, j);
1197bf215546Sopenharmony_ci      }
1198bf215546Sopenharmony_ci   }
1199bf215546Sopenharmony_ci
1200bf215546Sopenharmony_ci   _mesa_vao_unmap(ctx, vao);
1201bf215546Sopenharmony_ci}
1202bf215546Sopenharmony_ci
1203bf215546Sopenharmony_ci
1204bf215546Sopenharmony_ci/**
1205bf215546Sopenharmony_ci * Check array data, looking for NaNs, etc.
1206bf215546Sopenharmony_ci */
1207bf215546Sopenharmony_cistatic void
1208bf215546Sopenharmony_cicheck_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count)
1209bf215546Sopenharmony_ci{
1210bf215546Sopenharmony_ci   /* TO DO */
1211bf215546Sopenharmony_ci}
1212bf215546Sopenharmony_ci
1213bf215546Sopenharmony_ci
1214bf215546Sopenharmony_ci/**
1215bf215546Sopenharmony_ci * Print info/data for glDrawArrays(), for debugging.
1216bf215546Sopenharmony_ci */
1217bf215546Sopenharmony_cistatic void
1218bf215546Sopenharmony_ciprint_draw_arrays(struct gl_context *ctx,
1219bf215546Sopenharmony_ci                  GLenum mode, GLint start, GLsizei count)
1220bf215546Sopenharmony_ci{
1221bf215546Sopenharmony_ci   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1222bf215546Sopenharmony_ci
1223bf215546Sopenharmony_ci   printf("_mesa_DrawArrays(mode 0x%x, start %d, count %d):\n",
1224bf215546Sopenharmony_ci          mode, start, count);
1225bf215546Sopenharmony_ci
1226bf215546Sopenharmony_ci   _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1227bf215546Sopenharmony_ci
1228bf215546Sopenharmony_ci   GLbitfield mask = vao->Enabled;
1229bf215546Sopenharmony_ci   while (mask) {
1230bf215546Sopenharmony_ci      const gl_vert_attrib i = u_bit_scan(&mask);
1231bf215546Sopenharmony_ci      const struct gl_array_attributes *array = &vao->VertexAttrib[i];
1232bf215546Sopenharmony_ci
1233bf215546Sopenharmony_ci      const struct gl_vertex_buffer_binding *binding =
1234bf215546Sopenharmony_ci         &vao->BufferBinding[array->BufferBindingIndex];
1235bf215546Sopenharmony_ci      struct gl_buffer_object *bufObj = binding->BufferObj;
1236bf215546Sopenharmony_ci
1237bf215546Sopenharmony_ci      printf("attr %s: size %d stride %d  "
1238bf215546Sopenharmony_ci             "ptr %p  Bufobj %u\n",
1239bf215546Sopenharmony_ci             gl_vert_attrib_name((gl_vert_attrib) i),
1240bf215546Sopenharmony_ci             array->Format.Size, binding->Stride,
1241bf215546Sopenharmony_ci             array->Ptr, bufObj ? bufObj->Name : 0);
1242bf215546Sopenharmony_ci
1243bf215546Sopenharmony_ci      if (bufObj) {
1244bf215546Sopenharmony_ci         GLubyte *p = bufObj->Mappings[MAP_INTERNAL].Pointer;
1245bf215546Sopenharmony_ci         int offset = (int) (GLintptr)
1246bf215546Sopenharmony_ci            _mesa_vertex_attrib_address(array, binding);
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_ci         unsigned multiplier;
1249bf215546Sopenharmony_ci         switch (array->Format.Type) {
1250bf215546Sopenharmony_ci         case GL_DOUBLE:
1251bf215546Sopenharmony_ci         case GL_INT64_ARB:
1252bf215546Sopenharmony_ci         case GL_UNSIGNED_INT64_ARB:
1253bf215546Sopenharmony_ci            multiplier = 2;
1254bf215546Sopenharmony_ci            break;
1255bf215546Sopenharmony_ci         default:
1256bf215546Sopenharmony_ci            multiplier = 1;
1257bf215546Sopenharmony_ci         }
1258bf215546Sopenharmony_ci
1259bf215546Sopenharmony_ci         float *f = (float *) (p + offset);
1260bf215546Sopenharmony_ci         int *k = (int *) f;
1261bf215546Sopenharmony_ci         int i = 0;
1262bf215546Sopenharmony_ci         int n = (count - 1) * (binding->Stride / (4 * multiplier))
1263bf215546Sopenharmony_ci            + array->Format.Size;
1264bf215546Sopenharmony_ci         if (n > 32)
1265bf215546Sopenharmony_ci            n = 32;
1266bf215546Sopenharmony_ci         printf("  Data at offset %d:\n", offset);
1267bf215546Sopenharmony_ci         do {
1268bf215546Sopenharmony_ci            if (multiplier == 2)
1269bf215546Sopenharmony_ci               printf("    double[%d] = 0x%016llx %lf\n", i,
1270bf215546Sopenharmony_ci                      ((unsigned long long *) k)[i], ((double *) f)[i]);
1271bf215546Sopenharmony_ci            else
1272bf215546Sopenharmony_ci               printf("    float[%d] = 0x%08x %f\n", i, k[i], f[i]);
1273bf215546Sopenharmony_ci            i++;
1274bf215546Sopenharmony_ci         } while (i < n);
1275bf215546Sopenharmony_ci      }
1276bf215546Sopenharmony_ci   }
1277bf215546Sopenharmony_ci
1278bf215546Sopenharmony_ci   _mesa_vao_unmap_arrays(ctx, vao);
1279bf215546Sopenharmony_ci}
1280bf215546Sopenharmony_ci
1281bf215546Sopenharmony_ci
1282bf215546Sopenharmony_ci/**
1283bf215546Sopenharmony_ci * Helper function called by the other DrawArrays() functions below.
1284bf215546Sopenharmony_ci * This is where we handle primitive restart for drawing non-indexed
1285bf215546Sopenharmony_ci * arrays.  If primitive restart is enabled, it typically means
1286bf215546Sopenharmony_ci * splitting one DrawArrays() into two.
1287bf215546Sopenharmony_ci */
1288bf215546Sopenharmony_cistatic void
1289bf215546Sopenharmony_ci_mesa_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
1290bf215546Sopenharmony_ci                  GLsizei count, GLuint numInstances, GLuint baseInstance)
1291bf215546Sopenharmony_ci{
1292bf215546Sopenharmony_ci   /* Viewperf has many draws with count=0. Discarding them is faster than
1293bf215546Sopenharmony_ci    * processing them.
1294bf215546Sopenharmony_ci    */
1295bf215546Sopenharmony_ci   if (!count || !numInstances)
1296bf215546Sopenharmony_ci      return;
1297bf215546Sopenharmony_ci
1298bf215546Sopenharmony_ci   /* OpenGL 4.5 says that primitive restart is ignored with non-indexed
1299bf215546Sopenharmony_ci    * draws.
1300bf215546Sopenharmony_ci    */
1301bf215546Sopenharmony_ci   struct pipe_draw_info info;
1302bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
1303bf215546Sopenharmony_ci
1304bf215546Sopenharmony_ci   info.mode = mode;
1305bf215546Sopenharmony_ci   info.index_size = 0;
1306bf215546Sopenharmony_ci   /* Packed section begin. */
1307bf215546Sopenharmony_ci   info.primitive_restart = false;
1308bf215546Sopenharmony_ci   info.has_user_indices = false;
1309bf215546Sopenharmony_ci   info.index_bounds_valid = true;
1310bf215546Sopenharmony_ci   info.increment_draw_id = false;
1311bf215546Sopenharmony_ci   info.was_line_loop = false;
1312bf215546Sopenharmony_ci   info.take_index_buffer_ownership = false;
1313bf215546Sopenharmony_ci   info.index_bias_varies = false;
1314bf215546Sopenharmony_ci   /* Packed section end. */
1315bf215546Sopenharmony_ci   info.start_instance = baseInstance;
1316bf215546Sopenharmony_ci   info.instance_count = numInstances;
1317bf215546Sopenharmony_ci   info.view_mask = 0;
1318bf215546Sopenharmony_ci   info.min_index = start;
1319bf215546Sopenharmony_ci   info.max_index = start + count - 1;
1320bf215546Sopenharmony_ci
1321bf215546Sopenharmony_ci   draw.start = start;
1322bf215546Sopenharmony_ci   draw.count = count;
1323bf215546Sopenharmony_ci
1324bf215546Sopenharmony_ci   ctx->Driver.DrawGallium(ctx, &info, 0, &draw, 1);
1325bf215546Sopenharmony_ci
1326bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
1327bf215546Sopenharmony_ci      _mesa_flush(ctx);
1328bf215546Sopenharmony_ci   }
1329bf215546Sopenharmony_ci}
1330bf215546Sopenharmony_ci
1331bf215546Sopenharmony_ci
1332bf215546Sopenharmony_ci/**
1333bf215546Sopenharmony_ci * Execute a glRectf() function.
1334bf215546Sopenharmony_ci */
1335bf215546Sopenharmony_civoid GLAPIENTRY
1336bf215546Sopenharmony_ci_mesa_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1337bf215546Sopenharmony_ci{
1338bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1339bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END(ctx);
1340bf215546Sopenharmony_ci
1341bf215546Sopenharmony_ci   CALL_Begin(ctx->CurrentServerDispatch, (GL_QUADS));
1342bf215546Sopenharmony_ci   /* Begin can change CurrentServerDispatch. */
1343bf215546Sopenharmony_ci   struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1344bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x1, y1));
1345bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x2, y1));
1346bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x2, y2));
1347bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x1, y2));
1348bf215546Sopenharmony_ci   CALL_End(dispatch, ());
1349bf215546Sopenharmony_ci}
1350bf215546Sopenharmony_ci
1351bf215546Sopenharmony_ci
1352bf215546Sopenharmony_civoid GLAPIENTRY
1353bf215546Sopenharmony_ci_mesa_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1354bf215546Sopenharmony_ci{
1355bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1356bf215546Sopenharmony_ci}
1357bf215546Sopenharmony_ci
1358bf215546Sopenharmony_civoid GLAPIENTRY
1359bf215546Sopenharmony_ci_mesa_Rectdv(const GLdouble *v1, const GLdouble *v2)
1360bf215546Sopenharmony_ci{
1361bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1362bf215546Sopenharmony_ci}
1363bf215546Sopenharmony_ci
1364bf215546Sopenharmony_civoid GLAPIENTRY
1365bf215546Sopenharmony_ci_mesa_Rectfv(const GLfloat *v1, const GLfloat *v2)
1366bf215546Sopenharmony_ci{
1367bf215546Sopenharmony_ci   _mesa_Rectf(v1[0], v1[1], v2[0], v2[1]);
1368bf215546Sopenharmony_ci}
1369bf215546Sopenharmony_ci
1370bf215546Sopenharmony_civoid GLAPIENTRY
1371bf215546Sopenharmony_ci_mesa_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1372bf215546Sopenharmony_ci{
1373bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1374bf215546Sopenharmony_ci}
1375bf215546Sopenharmony_ci
1376bf215546Sopenharmony_civoid GLAPIENTRY
1377bf215546Sopenharmony_ci_mesa_Rectiv(const GLint *v1, const GLint *v2)
1378bf215546Sopenharmony_ci{
1379bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1380bf215546Sopenharmony_ci}
1381bf215546Sopenharmony_ci
1382bf215546Sopenharmony_civoid GLAPIENTRY
1383bf215546Sopenharmony_ci_mesa_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1384bf215546Sopenharmony_ci{
1385bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1386bf215546Sopenharmony_ci}
1387bf215546Sopenharmony_ci
1388bf215546Sopenharmony_civoid GLAPIENTRY
1389bf215546Sopenharmony_ci_mesa_Rectsv(const GLshort *v1, const GLshort *v2)
1390bf215546Sopenharmony_ci{
1391bf215546Sopenharmony_ci   _mesa_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1392bf215546Sopenharmony_ci}
1393bf215546Sopenharmony_ci
1394bf215546Sopenharmony_ci
1395bf215546Sopenharmony_civoid GLAPIENTRY
1396bf215546Sopenharmony_ci_mesa_EvalMesh1(GLenum mode, GLint i1, GLint i2)
1397bf215546Sopenharmony_ci{
1398bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1399bf215546Sopenharmony_ci   GLint i;
1400bf215546Sopenharmony_ci   GLfloat u, du;
1401bf215546Sopenharmony_ci   GLenum prim;
1402bf215546Sopenharmony_ci
1403bf215546Sopenharmony_ci   switch (mode) {
1404bf215546Sopenharmony_ci   case GL_POINT:
1405bf215546Sopenharmony_ci      prim = GL_POINTS;
1406bf215546Sopenharmony_ci      break;
1407bf215546Sopenharmony_ci   case GL_LINE:
1408bf215546Sopenharmony_ci      prim = GL_LINE_STRIP;
1409bf215546Sopenharmony_ci      break;
1410bf215546Sopenharmony_ci   default:
1411bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)");
1412bf215546Sopenharmony_ci      return;
1413bf215546Sopenharmony_ci   }
1414bf215546Sopenharmony_ci
1415bf215546Sopenharmony_ci   /* No effect if vertex maps disabled.
1416bf215546Sopenharmony_ci    */
1417bf215546Sopenharmony_ci   if (!ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
1418bf215546Sopenharmony_ci      return;
1419bf215546Sopenharmony_ci
1420bf215546Sopenharmony_ci   du = ctx->Eval.MapGrid1du;
1421bf215546Sopenharmony_ci   u = ctx->Eval.MapGrid1u1 + i1 * du;
1422bf215546Sopenharmony_ci
1423bf215546Sopenharmony_ci
1424bf215546Sopenharmony_ci   CALL_Begin(ctx->CurrentServerDispatch, (prim));
1425bf215546Sopenharmony_ci   /* Begin can change CurrentServerDispatch. */
1426bf215546Sopenharmony_ci   struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1427bf215546Sopenharmony_ci   for (i = i1; i <= i2; i++, u += du) {
1428bf215546Sopenharmony_ci      CALL_EvalCoord1f(dispatch, (u));
1429bf215546Sopenharmony_ci   }
1430bf215546Sopenharmony_ci   CALL_End(dispatch, ());
1431bf215546Sopenharmony_ci}
1432bf215546Sopenharmony_ci
1433bf215546Sopenharmony_ci
1434bf215546Sopenharmony_civoid GLAPIENTRY
1435bf215546Sopenharmony_ci_mesa_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
1436bf215546Sopenharmony_ci{
1437bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1438bf215546Sopenharmony_ci   GLfloat u, du, v, dv, v1, u1;
1439bf215546Sopenharmony_ci   GLint i, j;
1440bf215546Sopenharmony_ci
1441bf215546Sopenharmony_ci   switch (mode) {
1442bf215546Sopenharmony_ci   case GL_POINT:
1443bf215546Sopenharmony_ci   case GL_LINE:
1444bf215546Sopenharmony_ci   case GL_FILL:
1445bf215546Sopenharmony_ci      break;
1446bf215546Sopenharmony_ci   default:
1447bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)");
1448bf215546Sopenharmony_ci      return;
1449bf215546Sopenharmony_ci   }
1450bf215546Sopenharmony_ci
1451bf215546Sopenharmony_ci   /* No effect if vertex maps disabled.
1452bf215546Sopenharmony_ci    */
1453bf215546Sopenharmony_ci   if (!ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
1454bf215546Sopenharmony_ci      return;
1455bf215546Sopenharmony_ci
1456bf215546Sopenharmony_ci   du = ctx->Eval.MapGrid2du;
1457bf215546Sopenharmony_ci   dv = ctx->Eval.MapGrid2dv;
1458bf215546Sopenharmony_ci   v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
1459bf215546Sopenharmony_ci   u1 = ctx->Eval.MapGrid2u1 + i1 * du;
1460bf215546Sopenharmony_ci
1461bf215546Sopenharmony_ci   struct _glapi_table *dispatch;
1462bf215546Sopenharmony_ci
1463bf215546Sopenharmony_ci   switch (mode) {
1464bf215546Sopenharmony_ci   case GL_POINT:
1465bf215546Sopenharmony_ci      CALL_Begin(ctx->CurrentServerDispatch, (GL_POINTS));
1466bf215546Sopenharmony_ci      /* Begin can change CurrentServerDispatch. */
1467bf215546Sopenharmony_ci      dispatch = ctx->CurrentServerDispatch;
1468bf215546Sopenharmony_ci      for (v = v1, j = j1; j <= j2; j++, v += dv) {
1469bf215546Sopenharmony_ci         for (u = u1, i = i1; i <= i2; i++, u += du) {
1470bf215546Sopenharmony_ci            CALL_EvalCoord2f(dispatch, (u, v));
1471bf215546Sopenharmony_ci         }
1472bf215546Sopenharmony_ci      }
1473bf215546Sopenharmony_ci      CALL_End(dispatch, ());
1474bf215546Sopenharmony_ci      break;
1475bf215546Sopenharmony_ci   case GL_LINE:
1476bf215546Sopenharmony_ci      for (v = v1, j = j1; j <= j2; j++, v += dv) {
1477bf215546Sopenharmony_ci         CALL_Begin(ctx->CurrentServerDispatch, (GL_LINE_STRIP));
1478bf215546Sopenharmony_ci         /* Begin can change CurrentServerDispatch. */
1479bf215546Sopenharmony_ci         dispatch = ctx->CurrentServerDispatch;
1480bf215546Sopenharmony_ci         for (u = u1, i = i1; i <= i2; i++, u += du) {
1481bf215546Sopenharmony_ci            CALL_EvalCoord2f(dispatch, (u, v));
1482bf215546Sopenharmony_ci         }
1483bf215546Sopenharmony_ci         CALL_End(dispatch, ());
1484bf215546Sopenharmony_ci      }
1485bf215546Sopenharmony_ci      for (u = u1, i = i1; i <= i2; i++, u += du) {
1486bf215546Sopenharmony_ci         CALL_Begin(ctx->CurrentServerDispatch, (GL_LINE_STRIP));
1487bf215546Sopenharmony_ci         /* Begin can change CurrentServerDispatch. */
1488bf215546Sopenharmony_ci         dispatch = ctx->CurrentServerDispatch;
1489bf215546Sopenharmony_ci         for (v = v1, j = j1; j <= j2; j++, v += dv) {
1490bf215546Sopenharmony_ci            CALL_EvalCoord2f(dispatch, (u, v));
1491bf215546Sopenharmony_ci         }
1492bf215546Sopenharmony_ci         CALL_End(dispatch, ());
1493bf215546Sopenharmony_ci      }
1494bf215546Sopenharmony_ci      break;
1495bf215546Sopenharmony_ci   case GL_FILL:
1496bf215546Sopenharmony_ci      for (v = v1, j = j1; j < j2; j++, v += dv) {
1497bf215546Sopenharmony_ci         CALL_Begin(ctx->CurrentServerDispatch, (GL_TRIANGLE_STRIP));
1498bf215546Sopenharmony_ci         /* Begin can change CurrentServerDispatch. */
1499bf215546Sopenharmony_ci         dispatch = ctx->CurrentServerDispatch;
1500bf215546Sopenharmony_ci         for (u = u1, i = i1; i <= i2; i++, u += du) {
1501bf215546Sopenharmony_ci            CALL_EvalCoord2f(dispatch, (u, v));
1502bf215546Sopenharmony_ci            CALL_EvalCoord2f(dispatch, (u, v + dv));
1503bf215546Sopenharmony_ci         }
1504bf215546Sopenharmony_ci         CALL_End(dispatch, ());
1505bf215546Sopenharmony_ci      }
1506bf215546Sopenharmony_ci      break;
1507bf215546Sopenharmony_ci   }
1508bf215546Sopenharmony_ci}
1509bf215546Sopenharmony_ci
1510bf215546Sopenharmony_ci
1511bf215546Sopenharmony_ci/**
1512bf215546Sopenharmony_ci * Called from glDrawArrays when in immediate mode (not display list mode).
1513bf215546Sopenharmony_ci */
1514bf215546Sopenharmony_civoid GLAPIENTRY
1515bf215546Sopenharmony_ci_mesa_DrawArrays(GLenum mode, GLint start, GLsizei count)
1516bf215546Sopenharmony_ci{
1517bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1518bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1519bf215546Sopenharmony_ci
1520bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1521bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1522bf215546Sopenharmony_ci
1523bf215546Sopenharmony_ci   if (ctx->NewState)
1524bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1525bf215546Sopenharmony_ci
1526bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1527bf215546Sopenharmony_ci       !_mesa_validate_DrawArrays(ctx, mode, count))
1528bf215546Sopenharmony_ci      return;
1529bf215546Sopenharmony_ci
1530bf215546Sopenharmony_ci   if (0)
1531bf215546Sopenharmony_ci      check_draw_arrays_data(ctx, start, count);
1532bf215546Sopenharmony_ci
1533bf215546Sopenharmony_ci   _mesa_draw_arrays(ctx, mode, start, count, 1, 0);
1534bf215546Sopenharmony_ci
1535bf215546Sopenharmony_ci   if (0)
1536bf215546Sopenharmony_ci      print_draw_arrays(ctx, mode, start, count);
1537bf215546Sopenharmony_ci}
1538bf215546Sopenharmony_ci
1539bf215546Sopenharmony_ci
1540bf215546Sopenharmony_ci/**
1541bf215546Sopenharmony_ci * Called from glDrawArraysInstanced when in immediate mode (not
1542bf215546Sopenharmony_ci * display list mode).
1543bf215546Sopenharmony_ci */
1544bf215546Sopenharmony_civoid GLAPIENTRY
1545bf215546Sopenharmony_ci_mesa_DrawArraysInstancedARB(GLenum mode, GLint start, GLsizei count,
1546bf215546Sopenharmony_ci                             GLsizei numInstances)
1547bf215546Sopenharmony_ci{
1548bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1549bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1550bf215546Sopenharmony_ci
1551bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1552bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1553bf215546Sopenharmony_ci
1554bf215546Sopenharmony_ci   if (ctx->NewState)
1555bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1556bf215546Sopenharmony_ci
1557bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1558bf215546Sopenharmony_ci       !_mesa_validate_DrawArraysInstanced(ctx, mode, start, count,
1559bf215546Sopenharmony_ci                                           numInstances))
1560bf215546Sopenharmony_ci      return;
1561bf215546Sopenharmony_ci
1562bf215546Sopenharmony_ci   if (0)
1563bf215546Sopenharmony_ci      check_draw_arrays_data(ctx, start, count);
1564bf215546Sopenharmony_ci
1565bf215546Sopenharmony_ci   _mesa_draw_arrays(ctx, mode, start, count, numInstances, 0);
1566bf215546Sopenharmony_ci
1567bf215546Sopenharmony_ci   if (0)
1568bf215546Sopenharmony_ci      print_draw_arrays(ctx, mode, start, count);
1569bf215546Sopenharmony_ci}
1570bf215546Sopenharmony_ci
1571bf215546Sopenharmony_ci
1572bf215546Sopenharmony_ci/**
1573bf215546Sopenharmony_ci * Called from glDrawArraysInstancedBaseInstance when in immediate mode.
1574bf215546Sopenharmony_ci */
1575bf215546Sopenharmony_civoid GLAPIENTRY
1576bf215546Sopenharmony_ci_mesa_DrawArraysInstancedBaseInstance(GLenum mode, GLint first,
1577bf215546Sopenharmony_ci                                      GLsizei count, GLsizei numInstances,
1578bf215546Sopenharmony_ci                                      GLuint baseInstance)
1579bf215546Sopenharmony_ci{
1580bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1581bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1582bf215546Sopenharmony_ci
1583bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1584bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1585bf215546Sopenharmony_ci
1586bf215546Sopenharmony_ci   if (ctx->NewState)
1587bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1588bf215546Sopenharmony_ci
1589bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1590bf215546Sopenharmony_ci       !_mesa_validate_DrawArraysInstanced(ctx, mode, first, count,
1591bf215546Sopenharmony_ci                                           numInstances))
1592bf215546Sopenharmony_ci      return;
1593bf215546Sopenharmony_ci
1594bf215546Sopenharmony_ci   if (0)
1595bf215546Sopenharmony_ci      check_draw_arrays_data(ctx, first, count);
1596bf215546Sopenharmony_ci
1597bf215546Sopenharmony_ci   _mesa_draw_arrays(ctx, mode, first, count, numInstances, baseInstance);
1598bf215546Sopenharmony_ci
1599bf215546Sopenharmony_ci   if (0)
1600bf215546Sopenharmony_ci      print_draw_arrays(ctx, mode, first, count);
1601bf215546Sopenharmony_ci}
1602bf215546Sopenharmony_ci
1603bf215546Sopenharmony_ci
1604bf215546Sopenharmony_ci/**
1605bf215546Sopenharmony_ci * Called from glMultiDrawArrays when in immediate mode.
1606bf215546Sopenharmony_ci */
1607bf215546Sopenharmony_civoid GLAPIENTRY
1608bf215546Sopenharmony_ci_mesa_MultiDrawArrays(GLenum mode, const GLint *first,
1609bf215546Sopenharmony_ci                      const GLsizei *count, GLsizei primcount)
1610bf215546Sopenharmony_ci{
1611bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1612bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1613bf215546Sopenharmony_ci
1614bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1615bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1616bf215546Sopenharmony_ci
1617bf215546Sopenharmony_ci   if (ctx->NewState)
1618bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1619bf215546Sopenharmony_ci
1620bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1621bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawArrays(ctx, mode, count, primcount))
1622bf215546Sopenharmony_ci      return;
1623bf215546Sopenharmony_ci
1624bf215546Sopenharmony_ci   if (primcount == 0)
1625bf215546Sopenharmony_ci      return;
1626bf215546Sopenharmony_ci
1627bf215546Sopenharmony_ci   struct pipe_draw_info info;
1628bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias *draw;
1629bf215546Sopenharmony_ci
1630bf215546Sopenharmony_ci   ALLOC_PRIMS(draw, primcount, "glMultiDrawElements");
1631bf215546Sopenharmony_ci
1632bf215546Sopenharmony_ci   info.mode = mode;
1633bf215546Sopenharmony_ci   info.index_size = 0;
1634bf215546Sopenharmony_ci   /* Packed section begin. */
1635bf215546Sopenharmony_ci   info.primitive_restart = false;
1636bf215546Sopenharmony_ci   info.has_user_indices = false;
1637bf215546Sopenharmony_ci   info.index_bounds_valid = false;
1638bf215546Sopenharmony_ci   info.increment_draw_id = primcount > 1;
1639bf215546Sopenharmony_ci   info.was_line_loop = false;
1640bf215546Sopenharmony_ci   info.take_index_buffer_ownership = false;
1641bf215546Sopenharmony_ci   info.index_bias_varies = false;
1642bf215546Sopenharmony_ci   /* Packed section end. */
1643bf215546Sopenharmony_ci   info.start_instance = 0;
1644bf215546Sopenharmony_ci   info.instance_count = 1;
1645bf215546Sopenharmony_ci   info.view_mask = 0;
1646bf215546Sopenharmony_ci
1647bf215546Sopenharmony_ci   for (int i = 0; i < primcount; i++) {
1648bf215546Sopenharmony_ci      draw[i].start = first[i];
1649bf215546Sopenharmony_ci      draw[i].count = count[i];
1650bf215546Sopenharmony_ci   }
1651bf215546Sopenharmony_ci
1652bf215546Sopenharmony_ci   ctx->Driver.DrawGallium(ctx, &info, 0, draw, primcount);
1653bf215546Sopenharmony_ci
1654bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
1655bf215546Sopenharmony_ci      _mesa_flush(ctx);
1656bf215546Sopenharmony_ci
1657bf215546Sopenharmony_ci   FREE_PRIMS(draw, primcount);
1658bf215546Sopenharmony_ci}
1659bf215546Sopenharmony_ci
1660bf215546Sopenharmony_ci
1661bf215546Sopenharmony_ci
1662bf215546Sopenharmony_ci/**
1663bf215546Sopenharmony_ci * Map GL_ELEMENT_ARRAY_BUFFER and print contents.
1664bf215546Sopenharmony_ci * For debugging.
1665bf215546Sopenharmony_ci */
1666bf215546Sopenharmony_ci#if 0
1667bf215546Sopenharmony_cistatic void
1668bf215546Sopenharmony_cidump_element_buffer(struct gl_context *ctx, GLenum type)
1669bf215546Sopenharmony_ci{
1670bf215546Sopenharmony_ci   const GLvoid *map =
1671bf215546Sopenharmony_ci      ctx->Driver.MapBufferRange(ctx, 0,
1672bf215546Sopenharmony_ci                                 ctx->Array.VAO->IndexBufferObj->Size,
1673bf215546Sopenharmony_ci                                 GL_MAP_READ_BIT,
1674bf215546Sopenharmony_ci                                 ctx->Array.VAO->IndexBufferObj,
1675bf215546Sopenharmony_ci                                 MAP_INTERNAL);
1676bf215546Sopenharmony_ci   switch (type) {
1677bf215546Sopenharmony_ci   case GL_UNSIGNED_BYTE:
1678bf215546Sopenharmony_ci      {
1679bf215546Sopenharmony_ci         const GLubyte *us = (const GLubyte *) map;
1680bf215546Sopenharmony_ci         GLint i;
1681bf215546Sopenharmony_ci         for (i = 0; i < ctx->Array.VAO->IndexBufferObj->Size; i++) {
1682bf215546Sopenharmony_ci            printf("%02x ", us[i]);
1683bf215546Sopenharmony_ci            if (i % 32 == 31)
1684bf215546Sopenharmony_ci               printf("\n");
1685bf215546Sopenharmony_ci         }
1686bf215546Sopenharmony_ci         printf("\n");
1687bf215546Sopenharmony_ci      }
1688bf215546Sopenharmony_ci      break;
1689bf215546Sopenharmony_ci   case GL_UNSIGNED_SHORT:
1690bf215546Sopenharmony_ci      {
1691bf215546Sopenharmony_ci         const GLushort *us = (const GLushort *) map;
1692bf215546Sopenharmony_ci         GLint i;
1693bf215546Sopenharmony_ci         for (i = 0; i < ctx->Array.VAO->IndexBufferObj->Size / 2; i++) {
1694bf215546Sopenharmony_ci            printf("%04x ", us[i]);
1695bf215546Sopenharmony_ci            if (i % 16 == 15)
1696bf215546Sopenharmony_ci               printf("\n");
1697bf215546Sopenharmony_ci         }
1698bf215546Sopenharmony_ci         printf("\n");
1699bf215546Sopenharmony_ci      }
1700bf215546Sopenharmony_ci      break;
1701bf215546Sopenharmony_ci   case GL_UNSIGNED_INT:
1702bf215546Sopenharmony_ci      {
1703bf215546Sopenharmony_ci         const GLuint *us = (const GLuint *) map;
1704bf215546Sopenharmony_ci         GLint i;
1705bf215546Sopenharmony_ci         for (i = 0; i < ctx->Array.VAO->IndexBufferObj->Size / 4; i++) {
1706bf215546Sopenharmony_ci            printf("%08x ", us[i]);
1707bf215546Sopenharmony_ci            if (i % 8 == 7)
1708bf215546Sopenharmony_ci               printf("\n");
1709bf215546Sopenharmony_ci         }
1710bf215546Sopenharmony_ci         printf("\n");
1711bf215546Sopenharmony_ci      }
1712bf215546Sopenharmony_ci      break;
1713bf215546Sopenharmony_ci   default:
1714bf215546Sopenharmony_ci      ;
1715bf215546Sopenharmony_ci   }
1716bf215546Sopenharmony_ci
1717bf215546Sopenharmony_ci   ctx->Driver.UnmapBuffer(ctx, ctx->Array.VAO->IndexBufferObj, MAP_INTERNAL);
1718bf215546Sopenharmony_ci}
1719bf215546Sopenharmony_ci#endif
1720bf215546Sopenharmony_ci
1721bf215546Sopenharmony_ci
1722bf215546Sopenharmony_ci/**
1723bf215546Sopenharmony_ci * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements.
1724bf215546Sopenharmony_ci * Do the rendering for a glDrawElements or glDrawRangeElements call after
1725bf215546Sopenharmony_ci * we've validated buffer bounds, etc.
1726bf215546Sopenharmony_ci */
1727bf215546Sopenharmony_cistatic void
1728bf215546Sopenharmony_ci_mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
1729bf215546Sopenharmony_ci                                  bool index_bounds_valid,
1730bf215546Sopenharmony_ci                                  GLuint start, GLuint end,
1731bf215546Sopenharmony_ci                                  GLsizei count, GLenum type,
1732bf215546Sopenharmony_ci                                  const GLvoid * indices,
1733bf215546Sopenharmony_ci                                  GLint basevertex, GLuint numInstances,
1734bf215546Sopenharmony_ci                                  GLuint baseInstance)
1735bf215546Sopenharmony_ci{
1736bf215546Sopenharmony_ci   /* Viewperf has many draws with count=0. Discarding them is faster than
1737bf215546Sopenharmony_ci    * processing them.
1738bf215546Sopenharmony_ci    */
1739bf215546Sopenharmony_ci   if (!count || !numInstances)
1740bf215546Sopenharmony_ci      return;
1741bf215546Sopenharmony_ci
1742bf215546Sopenharmony_ci   if (!index_bounds_valid) {
1743bf215546Sopenharmony_ci      assert(start == 0u);
1744bf215546Sopenharmony_ci      assert(end == ~0u);
1745bf215546Sopenharmony_ci   }
1746bf215546Sopenharmony_ci
1747bf215546Sopenharmony_ci   struct pipe_draw_info info;
1748bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
1749bf215546Sopenharmony_ci   unsigned index_size_shift = get_index_size_shift(type);
1750bf215546Sopenharmony_ci   struct gl_buffer_object *index_bo = ctx->Array.VAO->IndexBufferObj;
1751bf215546Sopenharmony_ci
1752bf215546Sopenharmony_ci   if (index_bo && !indices_aligned(index_size_shift, indices))
1753bf215546Sopenharmony_ci      return;
1754bf215546Sopenharmony_ci
1755bf215546Sopenharmony_ci   info.mode = mode;
1756bf215546Sopenharmony_ci   info.index_size = 1 << index_size_shift;
1757bf215546Sopenharmony_ci   /* Packed section begin. */
1758bf215546Sopenharmony_ci   info.primitive_restart = ctx->Array._PrimitiveRestart[index_size_shift];
1759bf215546Sopenharmony_ci   info.has_user_indices = index_bo == NULL;
1760bf215546Sopenharmony_ci   info.index_bounds_valid = index_bounds_valid;
1761bf215546Sopenharmony_ci   info.increment_draw_id = false;
1762bf215546Sopenharmony_ci   info.was_line_loop = false;
1763bf215546Sopenharmony_ci   info.take_index_buffer_ownership = false;
1764bf215546Sopenharmony_ci   info.index_bias_varies = false;
1765bf215546Sopenharmony_ci   /* Packed section end. */
1766bf215546Sopenharmony_ci   info.start_instance = baseInstance;
1767bf215546Sopenharmony_ci   info.instance_count = numInstances;
1768bf215546Sopenharmony_ci   info.view_mask = 0;
1769bf215546Sopenharmony_ci   info.restart_index = ctx->Array._RestartIndex[index_size_shift];
1770bf215546Sopenharmony_ci
1771bf215546Sopenharmony_ci   if (info.has_user_indices) {
1772bf215546Sopenharmony_ci      info.index.user = indices;
1773bf215546Sopenharmony_ci      draw.start = 0;
1774bf215546Sopenharmony_ci   } else {
1775bf215546Sopenharmony_ci      uintptr_t start = (uintptr_t) indices;
1776bf215546Sopenharmony_ci      if (unlikely(index_bo->Size < start)) {
1777bf215546Sopenharmony_ci         _mesa_warning(ctx, "Invalid indices offset 0x%" PRIxPTR
1778bf215546Sopenharmony_ci                            " (indices buffer size is %ld bytes)."
1779bf215546Sopenharmony_ci                            " Draw skipped.", start, index_bo->Size);
1780bf215546Sopenharmony_ci         return;
1781bf215546Sopenharmony_ci      }
1782bf215546Sopenharmony_ci      info.index.gl_bo = index_bo;
1783bf215546Sopenharmony_ci      draw.start = start >> index_size_shift;
1784bf215546Sopenharmony_ci   }
1785bf215546Sopenharmony_ci   draw.index_bias = basevertex;
1786bf215546Sopenharmony_ci
1787bf215546Sopenharmony_ci   info.min_index = start;
1788bf215546Sopenharmony_ci   info.max_index = end;
1789bf215546Sopenharmony_ci   draw.count = count;
1790bf215546Sopenharmony_ci
1791bf215546Sopenharmony_ci   /* Need to give special consideration to rendering a range of
1792bf215546Sopenharmony_ci    * indices starting somewhere above zero.  Typically the
1793bf215546Sopenharmony_ci    * application is issuing multiple DrawRangeElements() to draw
1794bf215546Sopenharmony_ci    * successive primitives layed out linearly in the vertex arrays.
1795bf215546Sopenharmony_ci    * Unless the vertex arrays are all in a VBO (or locked as with
1796bf215546Sopenharmony_ci    * CVA), the OpenGL semantics imply that we need to re-read or
1797bf215546Sopenharmony_ci    * re-upload the vertex data on each draw call.
1798bf215546Sopenharmony_ci    *
1799bf215546Sopenharmony_ci    * In the case of hardware tnl, we want to avoid starting the
1800bf215546Sopenharmony_ci    * upload at zero, as it will mean every draw call uploads an
1801bf215546Sopenharmony_ci    * increasing amount of not-used vertex data.  Worse - in the
1802bf215546Sopenharmony_ci    * software tnl module, all those vertices might be transformed and
1803bf215546Sopenharmony_ci    * lit but never rendered.
1804bf215546Sopenharmony_ci    *
1805bf215546Sopenharmony_ci    * If we just upload or transform the vertices in start..end,
1806bf215546Sopenharmony_ci    * however, the indices will be incorrect.
1807bf215546Sopenharmony_ci    *
1808bf215546Sopenharmony_ci    * At this level, we don't know exactly what the requirements of
1809bf215546Sopenharmony_ci    * the backend are going to be, though it will likely boil down to
1810bf215546Sopenharmony_ci    * either:
1811bf215546Sopenharmony_ci    *
1812bf215546Sopenharmony_ci    * 1) Do nothing, everything is in a VBO and is processed once
1813bf215546Sopenharmony_ci    *       only.
1814bf215546Sopenharmony_ci    *
1815bf215546Sopenharmony_ci    * 2) Adjust the indices and vertex arrays so that start becomes
1816bf215546Sopenharmony_ci    *    zero.
1817bf215546Sopenharmony_ci    *
1818bf215546Sopenharmony_ci    * Rather than doing anything here, I'll provide a helper function
1819bf215546Sopenharmony_ci    * for the latter case elsewhere.
1820bf215546Sopenharmony_ci    */
1821bf215546Sopenharmony_ci
1822bf215546Sopenharmony_ci   ctx->Driver.DrawGallium(ctx, &info, 0, &draw, 1);
1823bf215546Sopenharmony_ci
1824bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
1825bf215546Sopenharmony_ci      _mesa_flush(ctx);
1826bf215546Sopenharmony_ci   }
1827bf215546Sopenharmony_ci}
1828bf215546Sopenharmony_ci
1829bf215546Sopenharmony_ci
1830bf215546Sopenharmony_ci/**
1831bf215546Sopenharmony_ci * Called by glDrawRangeElementsBaseVertex() in immediate mode.
1832bf215546Sopenharmony_ci */
1833bf215546Sopenharmony_civoid GLAPIENTRY
1834bf215546Sopenharmony_ci_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
1835bf215546Sopenharmony_ci                                  GLsizei count, GLenum type,
1836bf215546Sopenharmony_ci                                  const GLvoid * indices, GLint basevertex)
1837bf215546Sopenharmony_ci{
1838bf215546Sopenharmony_ci   static GLuint warnCount = 0;
1839bf215546Sopenharmony_ci   bool index_bounds_valid = true;
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_ci   /* This is only useful to catch invalid values in the "end" parameter
1842bf215546Sopenharmony_ci    * like ~0.
1843bf215546Sopenharmony_ci    */
1844bf215546Sopenharmony_ci   GLuint max_element = 2 * 1000 * 1000 * 1000; /* just a big number */
1845bf215546Sopenharmony_ci
1846bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1847bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1848bf215546Sopenharmony_ci
1849bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1850bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1851bf215546Sopenharmony_ci
1852bf215546Sopenharmony_ci   if (ctx->NewState)
1853bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1854bf215546Sopenharmony_ci
1855bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1856bf215546Sopenharmony_ci       !_mesa_validate_DrawRangeElements(ctx, mode, start, end, count,
1857bf215546Sopenharmony_ci                                         type))
1858bf215546Sopenharmony_ci      return;
1859bf215546Sopenharmony_ci
1860bf215546Sopenharmony_ci   if ((int) end + basevertex < 0 || start + basevertex >= max_element) {
1861bf215546Sopenharmony_ci      /* The application requested we draw using a range of indices that's
1862bf215546Sopenharmony_ci       * outside the bounds of the current VBO.  This is invalid and appears
1863bf215546Sopenharmony_ci       * to give undefined results.  The safest thing to do is to simply
1864bf215546Sopenharmony_ci       * ignore the range, in case the application botched their range tracking
1865bf215546Sopenharmony_ci       * but did provide valid indices.  Also issue a warning indicating that
1866bf215546Sopenharmony_ci       * the application is broken.
1867bf215546Sopenharmony_ci       */
1868bf215546Sopenharmony_ci      if (warnCount++ < 10) {
1869bf215546Sopenharmony_ci         _mesa_warning(ctx, "glDrawRangeElements(start %u, end %u, "
1870bf215546Sopenharmony_ci                       "basevertex %d, count %d, type 0x%x, indices=%p):\n"
1871bf215546Sopenharmony_ci                       "\trange is outside VBO bounds (max=%u); ignoring.\n"
1872bf215546Sopenharmony_ci                       "\tThis should be fixed in the application.",
1873bf215546Sopenharmony_ci                       start, end, basevertex, count, type, indices,
1874bf215546Sopenharmony_ci                       max_element - 1);
1875bf215546Sopenharmony_ci      }
1876bf215546Sopenharmony_ci      index_bounds_valid = false;
1877bf215546Sopenharmony_ci   }
1878bf215546Sopenharmony_ci
1879bf215546Sopenharmony_ci   /* NOTE: It's important that 'end' is a reasonable value.
1880bf215546Sopenharmony_ci    * in _tnl_draw_prims(), we use end to determine how many vertices
1881bf215546Sopenharmony_ci    * to transform.  If it's too large, we can unnecessarily split prims
1882bf215546Sopenharmony_ci    * or we can read/write out of memory in several different places!
1883bf215546Sopenharmony_ci    */
1884bf215546Sopenharmony_ci
1885bf215546Sopenharmony_ci   /* Catch/fix some potential user errors */
1886bf215546Sopenharmony_ci   if (type == GL_UNSIGNED_BYTE) {
1887bf215546Sopenharmony_ci      start = MIN2(start, 0xff);
1888bf215546Sopenharmony_ci      end = MIN2(end, 0xff);
1889bf215546Sopenharmony_ci   }
1890bf215546Sopenharmony_ci   else if (type == GL_UNSIGNED_SHORT) {
1891bf215546Sopenharmony_ci      start = MIN2(start, 0xffff);
1892bf215546Sopenharmony_ci      end = MIN2(end, 0xffff);
1893bf215546Sopenharmony_ci   }
1894bf215546Sopenharmony_ci
1895bf215546Sopenharmony_ci   if (0) {
1896bf215546Sopenharmony_ci      printf("glDraw[Range]Elements{,BaseVertex}"
1897bf215546Sopenharmony_ci             "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, "
1898bf215546Sopenharmony_ci             "base %d\n",
1899bf215546Sopenharmony_ci             start, end, type, count,
1900bf215546Sopenharmony_ci             ctx->Array.VAO->IndexBufferObj ?
1901bf215546Sopenharmony_ci                ctx->Array.VAO->IndexBufferObj->Name : 0, basevertex);
1902bf215546Sopenharmony_ci   }
1903bf215546Sopenharmony_ci
1904bf215546Sopenharmony_ci   if ((int) start + basevertex < 0 || end + basevertex >= max_element)
1905bf215546Sopenharmony_ci      index_bounds_valid = false;
1906bf215546Sopenharmony_ci
1907bf215546Sopenharmony_ci#if 0
1908bf215546Sopenharmony_ci   check_draw_elements_data(ctx, count, type, indices, basevertex);
1909bf215546Sopenharmony_ci#else
1910bf215546Sopenharmony_ci   (void) check_draw_elements_data;
1911bf215546Sopenharmony_ci#endif
1912bf215546Sopenharmony_ci
1913bf215546Sopenharmony_ci   if (!index_bounds_valid) {
1914bf215546Sopenharmony_ci      start = 0;
1915bf215546Sopenharmony_ci      end = ~0;
1916bf215546Sopenharmony_ci   }
1917bf215546Sopenharmony_ci
1918bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, index_bounds_valid, start, end,
1919bf215546Sopenharmony_ci                                     count, type, indices, basevertex, 1, 0);
1920bf215546Sopenharmony_ci}
1921bf215546Sopenharmony_ci
1922bf215546Sopenharmony_ci
1923bf215546Sopenharmony_ci/**
1924bf215546Sopenharmony_ci * Called by glDrawRangeElements() in immediate mode.
1925bf215546Sopenharmony_ci */
1926bf215546Sopenharmony_civoid GLAPIENTRY
1927bf215546Sopenharmony_ci_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1928bf215546Sopenharmony_ci                        GLsizei count, GLenum type, const GLvoid * indices)
1929bf215546Sopenharmony_ci{
1930bf215546Sopenharmony_ci   _mesa_DrawRangeElementsBaseVertex(mode, start, end, count, type,
1931bf215546Sopenharmony_ci                                     indices, 0);
1932bf215546Sopenharmony_ci}
1933bf215546Sopenharmony_ci
1934bf215546Sopenharmony_ci
1935bf215546Sopenharmony_ci/**
1936bf215546Sopenharmony_ci * Called by glDrawElements() in immediate mode.
1937bf215546Sopenharmony_ci */
1938bf215546Sopenharmony_civoid GLAPIENTRY
1939bf215546Sopenharmony_ci_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
1940bf215546Sopenharmony_ci                   const GLvoid * indices)
1941bf215546Sopenharmony_ci{
1942bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1943bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1944bf215546Sopenharmony_ci
1945bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1946bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1947bf215546Sopenharmony_ci
1948bf215546Sopenharmony_ci   if (ctx->NewState)
1949bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1950bf215546Sopenharmony_ci
1951bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1952bf215546Sopenharmony_ci       !_mesa_validate_DrawElements(ctx, mode, count, type))
1953bf215546Sopenharmony_ci      return;
1954bf215546Sopenharmony_ci
1955bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
1956bf215546Sopenharmony_ci                                     count, type, indices, 0, 1, 0);
1957bf215546Sopenharmony_ci}
1958bf215546Sopenharmony_ci
1959bf215546Sopenharmony_ci
1960bf215546Sopenharmony_ci/**
1961bf215546Sopenharmony_ci * Called by glDrawElementsBaseVertex() in immediate mode.
1962bf215546Sopenharmony_ci */
1963bf215546Sopenharmony_civoid GLAPIENTRY
1964bf215546Sopenharmony_ci_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1965bf215546Sopenharmony_ci                             const GLvoid * indices, GLint basevertex)
1966bf215546Sopenharmony_ci{
1967bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1968bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1969bf215546Sopenharmony_ci
1970bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1971bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1972bf215546Sopenharmony_ci
1973bf215546Sopenharmony_ci   if (ctx->NewState)
1974bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1975bf215546Sopenharmony_ci
1976bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
1977bf215546Sopenharmony_ci       !_mesa_validate_DrawElements(ctx, mode, count, type))
1978bf215546Sopenharmony_ci      return;
1979bf215546Sopenharmony_ci
1980bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
1981bf215546Sopenharmony_ci                                     count, type, indices, basevertex, 1, 0);
1982bf215546Sopenharmony_ci}
1983bf215546Sopenharmony_ci
1984bf215546Sopenharmony_ci
1985bf215546Sopenharmony_ci/**
1986bf215546Sopenharmony_ci * Called by glDrawElementsInstanced() in immediate mode.
1987bf215546Sopenharmony_ci */
1988bf215546Sopenharmony_civoid GLAPIENTRY
1989bf215546Sopenharmony_ci_mesa_DrawElementsInstancedARB(GLenum mode, GLsizei count, GLenum type,
1990bf215546Sopenharmony_ci                               const GLvoid * indices, GLsizei numInstances)
1991bf215546Sopenharmony_ci{
1992bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1993bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
1994bf215546Sopenharmony_ci
1995bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
1996bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
1997bf215546Sopenharmony_ci
1998bf215546Sopenharmony_ci   if (ctx->NewState)
1999bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2000bf215546Sopenharmony_ci
2001bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2002bf215546Sopenharmony_ci       !_mesa_validate_DrawElementsInstanced(ctx, mode, count, type,
2003bf215546Sopenharmony_ci                                             numInstances))
2004bf215546Sopenharmony_ci      return;
2005bf215546Sopenharmony_ci
2006bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
2007bf215546Sopenharmony_ci                                     count, type, indices, 0, numInstances, 0);
2008bf215546Sopenharmony_ci}
2009bf215546Sopenharmony_ci
2010bf215546Sopenharmony_ci
2011bf215546Sopenharmony_ci/**
2012bf215546Sopenharmony_ci * Called by glDrawElementsInstancedBaseVertex() in immediate mode.
2013bf215546Sopenharmony_ci */
2014bf215546Sopenharmony_civoid GLAPIENTRY
2015bf215546Sopenharmony_ci_mesa_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count,
2016bf215546Sopenharmony_ci                                      GLenum type, const GLvoid * indices,
2017bf215546Sopenharmony_ci                                      GLsizei numInstances,
2018bf215546Sopenharmony_ci                                      GLint basevertex)
2019bf215546Sopenharmony_ci{
2020bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2021bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2022bf215546Sopenharmony_ci
2023bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2024bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2025bf215546Sopenharmony_ci
2026bf215546Sopenharmony_ci   if (ctx->NewState)
2027bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2028bf215546Sopenharmony_ci
2029bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2030bf215546Sopenharmony_ci       !_mesa_validate_DrawElementsInstanced(ctx, mode, count, type,
2031bf215546Sopenharmony_ci                                             numInstances))
2032bf215546Sopenharmony_ci      return;
2033bf215546Sopenharmony_ci
2034bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
2035bf215546Sopenharmony_ci                                     count, type, indices,
2036bf215546Sopenharmony_ci                                     basevertex, numInstances, 0);
2037bf215546Sopenharmony_ci}
2038bf215546Sopenharmony_ci
2039bf215546Sopenharmony_ci
2040bf215546Sopenharmony_ci/**
2041bf215546Sopenharmony_ci * Called by glDrawElementsInstancedBaseInstance() in immediate mode.
2042bf215546Sopenharmony_ci */
2043bf215546Sopenharmony_civoid GLAPIENTRY
2044bf215546Sopenharmony_ci_mesa_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count,
2045bf215546Sopenharmony_ci                                        GLenum type,
2046bf215546Sopenharmony_ci                                        const GLvoid *indices,
2047bf215546Sopenharmony_ci                                        GLsizei numInstances,
2048bf215546Sopenharmony_ci                                        GLuint baseInstance)
2049bf215546Sopenharmony_ci{
2050bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2051bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2052bf215546Sopenharmony_ci
2053bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2054bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2055bf215546Sopenharmony_ci
2056bf215546Sopenharmony_ci   if (ctx->NewState)
2057bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2058bf215546Sopenharmony_ci
2059bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2060bf215546Sopenharmony_ci       !_mesa_validate_DrawElementsInstanced(ctx, mode, count, type,
2061bf215546Sopenharmony_ci                                             numInstances))
2062bf215546Sopenharmony_ci      return;
2063bf215546Sopenharmony_ci
2064bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
2065bf215546Sopenharmony_ci                                     count, type, indices, 0, numInstances,
2066bf215546Sopenharmony_ci                                     baseInstance);
2067bf215546Sopenharmony_ci}
2068bf215546Sopenharmony_ci
2069bf215546Sopenharmony_ci
2070bf215546Sopenharmony_ci/**
2071bf215546Sopenharmony_ci * Called by glDrawElementsInstancedBaseVertexBaseInstance() in immediate mode.
2072bf215546Sopenharmony_ci */
2073bf215546Sopenharmony_civoid GLAPIENTRY
2074bf215546Sopenharmony_ci_mesa_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode,
2075bf215546Sopenharmony_ci                                                  GLsizei count,
2076bf215546Sopenharmony_ci                                                  GLenum type,
2077bf215546Sopenharmony_ci                                                  const GLvoid *indices,
2078bf215546Sopenharmony_ci                                                  GLsizei numInstances,
2079bf215546Sopenharmony_ci                                                  GLint basevertex,
2080bf215546Sopenharmony_ci                                                  GLuint baseInstance)
2081bf215546Sopenharmony_ci{
2082bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2083bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2084bf215546Sopenharmony_ci
2085bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2086bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2087bf215546Sopenharmony_ci
2088bf215546Sopenharmony_ci   if (ctx->NewState)
2089bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2090bf215546Sopenharmony_ci
2091bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2092bf215546Sopenharmony_ci       !_mesa_validate_DrawElementsInstanced(ctx, mode, count, type,
2093bf215546Sopenharmony_ci                                             numInstances))
2094bf215546Sopenharmony_ci      return;
2095bf215546Sopenharmony_ci
2096bf215546Sopenharmony_ci   _mesa_validated_drawrangeelements(ctx, mode, false, 0, ~0,
2097bf215546Sopenharmony_ci                                     count, type, indices, basevertex,
2098bf215546Sopenharmony_ci                                     numInstances, baseInstance);
2099bf215546Sopenharmony_ci}
2100bf215546Sopenharmony_ci
2101bf215546Sopenharmony_ci
2102bf215546Sopenharmony_ci/**
2103bf215546Sopenharmony_ci * Inner support for both _mesa_MultiDrawElements() and
2104bf215546Sopenharmony_ci * _mesa_MultiDrawRangeElements().
2105bf215546Sopenharmony_ci * This does the actual rendering after we've checked array indexes, etc.
2106bf215546Sopenharmony_ci */
2107bf215546Sopenharmony_cistatic void
2108bf215546Sopenharmony_ci_mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
2109bf215546Sopenharmony_ci                                  const GLsizei *count, GLenum type,
2110bf215546Sopenharmony_ci                                  const GLvoid * const *indices,
2111bf215546Sopenharmony_ci                                  GLsizei primcount, const GLint *basevertex)
2112bf215546Sopenharmony_ci{
2113bf215546Sopenharmony_ci   uintptr_t min_index_ptr, max_index_ptr;
2114bf215546Sopenharmony_ci   bool fallback = false;
2115bf215546Sopenharmony_ci   int i;
2116bf215546Sopenharmony_ci
2117bf215546Sopenharmony_ci   if (primcount == 0)
2118bf215546Sopenharmony_ci      return;
2119bf215546Sopenharmony_ci
2120bf215546Sopenharmony_ci   unsigned index_size_shift = get_index_size_shift(type);
2121bf215546Sopenharmony_ci
2122bf215546Sopenharmony_ci   min_index_ptr = (uintptr_t) indices[0];
2123bf215546Sopenharmony_ci   max_index_ptr = 0;
2124bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
2125bf215546Sopenharmony_ci      min_index_ptr = MIN2(min_index_ptr, (uintptr_t) indices[i]);
2126bf215546Sopenharmony_ci      max_index_ptr = MAX2(max_index_ptr, (uintptr_t) indices[i] +
2127bf215546Sopenharmony_ci                           (count[i] << index_size_shift));
2128bf215546Sopenharmony_ci   }
2129bf215546Sopenharmony_ci
2130bf215546Sopenharmony_ci   /* Check if we can handle this thing as a bunch of index offsets from the
2131bf215546Sopenharmony_ci    * same index pointer.  If we can't, then we have to fall back to doing
2132bf215546Sopenharmony_ci    * a draw_prims per primitive.
2133bf215546Sopenharmony_ci    * Check that the difference between each prim's indexes is a multiple of
2134bf215546Sopenharmony_ci    * the index/element size.
2135bf215546Sopenharmony_ci    */
2136bf215546Sopenharmony_ci   if (index_size_shift) {
2137bf215546Sopenharmony_ci      for (i = 0; i < primcount; i++) {
2138bf215546Sopenharmony_ci         if ((((uintptr_t) indices[i] - min_index_ptr) &
2139bf215546Sopenharmony_ci              ((1 << index_size_shift) - 1)) != 0) {
2140bf215546Sopenharmony_ci            fallback = true;
2141bf215546Sopenharmony_ci            break;
2142bf215546Sopenharmony_ci         }
2143bf215546Sopenharmony_ci      }
2144bf215546Sopenharmony_ci   }
2145bf215546Sopenharmony_ci
2146bf215546Sopenharmony_ci   struct gl_buffer_object *index_bo = ctx->Array.VAO->IndexBufferObj;
2147bf215546Sopenharmony_ci   struct pipe_draw_info info;
2148bf215546Sopenharmony_ci
2149bf215546Sopenharmony_ci   info.mode = mode;
2150bf215546Sopenharmony_ci   info.index_size = 1 << index_size_shift;
2151bf215546Sopenharmony_ci   /* Packed section begin. */
2152bf215546Sopenharmony_ci   info.primitive_restart = ctx->Array._PrimitiveRestart[index_size_shift];
2153bf215546Sopenharmony_ci   info.has_user_indices = index_bo == NULL;
2154bf215546Sopenharmony_ci   info.index_bounds_valid = false;
2155bf215546Sopenharmony_ci   info.increment_draw_id = primcount > 1;
2156bf215546Sopenharmony_ci   info.was_line_loop = false;
2157bf215546Sopenharmony_ci   info.take_index_buffer_ownership = false;
2158bf215546Sopenharmony_ci   info.index_bias_varies = !!basevertex;
2159bf215546Sopenharmony_ci   /* Packed section end. */
2160bf215546Sopenharmony_ci   info.start_instance = 0;
2161bf215546Sopenharmony_ci   info.instance_count = 1;
2162bf215546Sopenharmony_ci   info.view_mask = 0;
2163bf215546Sopenharmony_ci   info.restart_index = ctx->Array._RestartIndex[index_size_shift];
2164bf215546Sopenharmony_ci
2165bf215546Sopenharmony_ci   if (info.has_user_indices)
2166bf215546Sopenharmony_ci      info.index.user = (void*)min_index_ptr;
2167bf215546Sopenharmony_ci   else
2168bf215546Sopenharmony_ci      info.index.gl_bo = index_bo;
2169bf215546Sopenharmony_ci
2170bf215546Sopenharmony_ci   if (!fallback &&
2171bf215546Sopenharmony_ci       (!info.has_user_indices ||
2172bf215546Sopenharmony_ci        /* "max_index_ptr - min_index_ptr >> index_size_shift" is stored
2173bf215546Sopenharmony_ci         * in draw[i].start. The driver will multiply it later by index_size
2174bf215546Sopenharmony_ci         * so make sure the final value won't overflow.
2175bf215546Sopenharmony_ci         *
2176bf215546Sopenharmony_ci         * For real index buffers, gallium doesn't support index buffer offsets
2177bf215546Sopenharmony_ci         * greater than UINT32_MAX bytes.
2178bf215546Sopenharmony_ci         */
2179bf215546Sopenharmony_ci        max_index_ptr - min_index_ptr <= UINT32_MAX)) {
2180bf215546Sopenharmony_ci      struct pipe_draw_start_count_bias *draw;
2181bf215546Sopenharmony_ci
2182bf215546Sopenharmony_ci      ALLOC_PRIMS(draw, primcount, "glMultiDrawElements");
2183bf215546Sopenharmony_ci
2184bf215546Sopenharmony_ci      if (info.has_user_indices) {
2185bf215546Sopenharmony_ci         for (int i = 0; i < primcount; i++) {
2186bf215546Sopenharmony_ci            draw[i].start =
2187bf215546Sopenharmony_ci               ((uintptr_t)indices[i] - min_index_ptr) >> index_size_shift;
2188bf215546Sopenharmony_ci            draw[i].count = count[i];
2189bf215546Sopenharmony_ci            draw[i].index_bias = basevertex ? basevertex[i] : 0;
2190bf215546Sopenharmony_ci         }
2191bf215546Sopenharmony_ci      } else {
2192bf215546Sopenharmony_ci         for (int i = 0; i < primcount; i++) {
2193bf215546Sopenharmony_ci            draw[i].start = (uintptr_t)indices[i] >> index_size_shift;
2194bf215546Sopenharmony_ci            draw[i].count =
2195bf215546Sopenharmony_ci               indices_aligned(index_size_shift, indices[i]) ? count[i] : 0;
2196bf215546Sopenharmony_ci            draw[i].index_bias = basevertex ? basevertex[i] : 0;
2197bf215546Sopenharmony_ci         }
2198bf215546Sopenharmony_ci      }
2199bf215546Sopenharmony_ci
2200bf215546Sopenharmony_ci      ctx->Driver.DrawGallium(ctx, &info, 0, draw, primcount);
2201bf215546Sopenharmony_ci      FREE_PRIMS(draw, primcount);
2202bf215546Sopenharmony_ci   } else {
2203bf215546Sopenharmony_ci      /* draw[i].start would overflow. Draw one at a time. */
2204bf215546Sopenharmony_ci      assert(info.has_user_indices);
2205bf215546Sopenharmony_ci      info.increment_draw_id = false;
2206bf215546Sopenharmony_ci
2207bf215546Sopenharmony_ci      for (int i = 0; i < primcount; i++) {
2208bf215546Sopenharmony_ci         struct pipe_draw_start_count_bias draw;
2209bf215546Sopenharmony_ci
2210bf215546Sopenharmony_ci         if (!count[i])
2211bf215546Sopenharmony_ci            continue;
2212bf215546Sopenharmony_ci
2213bf215546Sopenharmony_ci         /* Reset these, because the callee can change them. */
2214bf215546Sopenharmony_ci         info.index_bounds_valid = false;
2215bf215546Sopenharmony_ci         info.index.user = indices[i];
2216bf215546Sopenharmony_ci         draw.start = 0;
2217bf215546Sopenharmony_ci         draw.index_bias = basevertex ? basevertex[i] : 0;
2218bf215546Sopenharmony_ci         draw.count = count[i];
2219bf215546Sopenharmony_ci
2220bf215546Sopenharmony_ci         ctx->Driver.DrawGallium(ctx, &info, i, &draw, 1);
2221bf215546Sopenharmony_ci      }
2222bf215546Sopenharmony_ci   }
2223bf215546Sopenharmony_ci
2224bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
2225bf215546Sopenharmony_ci      _mesa_flush(ctx);
2226bf215546Sopenharmony_ci   }
2227bf215546Sopenharmony_ci}
2228bf215546Sopenharmony_ci
2229bf215546Sopenharmony_ci
2230bf215546Sopenharmony_civoid GLAPIENTRY
2231bf215546Sopenharmony_ci_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
2232bf215546Sopenharmony_ci                           const GLvoid * const *indices, GLsizei primcount)
2233bf215546Sopenharmony_ci{
2234bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2235bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2236bf215546Sopenharmony_ci
2237bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2238bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2239bf215546Sopenharmony_ci
2240bf215546Sopenharmony_ci   if (ctx->NewState)
2241bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2242bf215546Sopenharmony_ci
2243bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2244bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
2245bf215546Sopenharmony_ci                                         primcount))
2246bf215546Sopenharmony_ci      return;
2247bf215546Sopenharmony_ci
2248bf215546Sopenharmony_ci   _mesa_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
2249bf215546Sopenharmony_ci                                     NULL);
2250bf215546Sopenharmony_ci}
2251bf215546Sopenharmony_ci
2252bf215546Sopenharmony_ci
2253bf215546Sopenharmony_civoid GLAPIENTRY
2254bf215546Sopenharmony_ci_mesa_MultiDrawElementsBaseVertex(GLenum mode,
2255bf215546Sopenharmony_ci                                  const GLsizei *count, GLenum type,
2256bf215546Sopenharmony_ci                                  const GLvoid * const *indices,
2257bf215546Sopenharmony_ci                                  GLsizei primcount,
2258bf215546Sopenharmony_ci                                  const GLsizei *basevertex)
2259bf215546Sopenharmony_ci{
2260bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2261bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2262bf215546Sopenharmony_ci
2263bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2264bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2265bf215546Sopenharmony_ci
2266bf215546Sopenharmony_ci   if (ctx->NewState)
2267bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2268bf215546Sopenharmony_ci
2269bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2270bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
2271bf215546Sopenharmony_ci                                         primcount))
2272bf215546Sopenharmony_ci      return;
2273bf215546Sopenharmony_ci
2274bf215546Sopenharmony_ci   _mesa_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
2275bf215546Sopenharmony_ci                                     basevertex);
2276bf215546Sopenharmony_ci}
2277bf215546Sopenharmony_ci
2278bf215546Sopenharmony_ci
2279bf215546Sopenharmony_ci/**
2280bf215546Sopenharmony_ci * Draw a GL primitive using a vertex count obtained from transform feedback.
2281bf215546Sopenharmony_ci * \param mode  the type of GL primitive to draw
2282bf215546Sopenharmony_ci * \param obj  the transform feedback object to use
2283bf215546Sopenharmony_ci * \param stream  index of the transform feedback stream from which to
2284bf215546Sopenharmony_ci *                get the primitive count.
2285bf215546Sopenharmony_ci * \param numInstances  number of instances to draw
2286bf215546Sopenharmony_ci */
2287bf215546Sopenharmony_cistatic void
2288bf215546Sopenharmony_ci_mesa_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
2289bf215546Sopenharmony_ci                              struct gl_transform_feedback_object *obj,
2290bf215546Sopenharmony_ci                              GLuint stream, GLuint numInstances)
2291bf215546Sopenharmony_ci{
2292bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2293bf215546Sopenharmony_ci
2294bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2295bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2296bf215546Sopenharmony_ci
2297bf215546Sopenharmony_ci   if (ctx->NewState)
2298bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2299bf215546Sopenharmony_ci
2300bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2301bf215546Sopenharmony_ci       !_mesa_validate_DrawTransformFeedback(ctx, mode, obj, stream,
2302bf215546Sopenharmony_ci                                             numInstances))
2303bf215546Sopenharmony_ci      return;
2304bf215546Sopenharmony_ci
2305bf215546Sopenharmony_ci   /* Maybe we should do some primitive splitting for primitive restart
2306bf215546Sopenharmony_ci    * (like in DrawArrays), but we have no way to know how many vertices
2307bf215546Sopenharmony_ci    * will be rendered. */
2308bf215546Sopenharmony_ci
2309bf215546Sopenharmony_ci   st_draw_transform_feedback(ctx, mode, numInstances, stream, obj);
2310bf215546Sopenharmony_ci
2311bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
2312bf215546Sopenharmony_ci      _mesa_flush(ctx);
2313bf215546Sopenharmony_ci   }
2314bf215546Sopenharmony_ci}
2315bf215546Sopenharmony_ci
2316bf215546Sopenharmony_ci
2317bf215546Sopenharmony_ci/**
2318bf215546Sopenharmony_ci * Like DrawArrays, but take the count from a transform feedback object.
2319bf215546Sopenharmony_ci * \param mode  GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
2320bf215546Sopenharmony_ci * \param name  the transform feedback object
2321bf215546Sopenharmony_ci * User still has to setup of the vertex attribute info with
2322bf215546Sopenharmony_ci * glVertexPointer, glColorPointer, etc.
2323bf215546Sopenharmony_ci * Part of GL_ARB_transform_feedback2.
2324bf215546Sopenharmony_ci */
2325bf215546Sopenharmony_civoid GLAPIENTRY
2326bf215546Sopenharmony_ci_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
2327bf215546Sopenharmony_ci{
2328bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2329bf215546Sopenharmony_ci   struct gl_transform_feedback_object *obj =
2330bf215546Sopenharmony_ci      _mesa_lookup_transform_feedback_object(ctx, name);
2331bf215546Sopenharmony_ci
2332bf215546Sopenharmony_ci   _mesa_draw_transform_feedback(ctx, mode, obj, 0, 1);
2333bf215546Sopenharmony_ci}
2334bf215546Sopenharmony_ci
2335bf215546Sopenharmony_ci
2336bf215546Sopenharmony_civoid GLAPIENTRY
2337bf215546Sopenharmony_ci_mesa_DrawTransformFeedbackStream(GLenum mode, GLuint name, GLuint stream)
2338bf215546Sopenharmony_ci{
2339bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2340bf215546Sopenharmony_ci   struct gl_transform_feedback_object *obj =
2341bf215546Sopenharmony_ci      _mesa_lookup_transform_feedback_object(ctx, name);
2342bf215546Sopenharmony_ci
2343bf215546Sopenharmony_ci   _mesa_draw_transform_feedback(ctx, mode, obj, stream, 1);
2344bf215546Sopenharmony_ci}
2345bf215546Sopenharmony_ci
2346bf215546Sopenharmony_ci
2347bf215546Sopenharmony_civoid GLAPIENTRY
2348bf215546Sopenharmony_ci_mesa_DrawTransformFeedbackInstanced(GLenum mode, GLuint name,
2349bf215546Sopenharmony_ci                                     GLsizei primcount)
2350bf215546Sopenharmony_ci{
2351bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2352bf215546Sopenharmony_ci   struct gl_transform_feedback_object *obj =
2353bf215546Sopenharmony_ci      _mesa_lookup_transform_feedback_object(ctx, name);
2354bf215546Sopenharmony_ci
2355bf215546Sopenharmony_ci   _mesa_draw_transform_feedback(ctx, mode, obj, 0, primcount);
2356bf215546Sopenharmony_ci}
2357bf215546Sopenharmony_ci
2358bf215546Sopenharmony_ci
2359bf215546Sopenharmony_civoid GLAPIENTRY
2360bf215546Sopenharmony_ci_mesa_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name,
2361bf215546Sopenharmony_ci                                           GLuint stream,
2362bf215546Sopenharmony_ci                                           GLsizei primcount)
2363bf215546Sopenharmony_ci{
2364bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2365bf215546Sopenharmony_ci   struct gl_transform_feedback_object *obj =
2366bf215546Sopenharmony_ci      _mesa_lookup_transform_feedback_object(ctx, name);
2367bf215546Sopenharmony_ci
2368bf215546Sopenharmony_ci   _mesa_draw_transform_feedback(ctx, mode, obj, stream, primcount);
2369bf215546Sopenharmony_ci}
2370bf215546Sopenharmony_ci
2371bf215546Sopenharmony_ci
2372bf215546Sopenharmony_cistatic void
2373bf215546Sopenharmony_ci_mesa_validated_multidrawarraysindirect(struct gl_context *ctx, GLenum mode,
2374bf215546Sopenharmony_ci                                        GLintptr indirect,
2375bf215546Sopenharmony_ci                                        GLintptr drawcount_offset,
2376bf215546Sopenharmony_ci                                        GLsizei drawcount, GLsizei stride,
2377bf215546Sopenharmony_ci                                        struct gl_buffer_object *drawcount_buffer)
2378bf215546Sopenharmony_ci{
2379bf215546Sopenharmony_ci   /* If drawcount_buffer is set, drawcount is the maximum draw count.*/
2380bf215546Sopenharmony_ci   if (drawcount == 0)
2381bf215546Sopenharmony_ci      return;
2382bf215546Sopenharmony_ci
2383bf215546Sopenharmony_ci   st_indirect_draw_vbo(ctx, mode, ctx->DrawIndirectBuffer, indirect,
2384bf215546Sopenharmony_ci                        drawcount, stride, drawcount_buffer,
2385bf215546Sopenharmony_ci                        drawcount_offset, NULL, false, 0);
2386bf215546Sopenharmony_ci
2387bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
2388bf215546Sopenharmony_ci      _mesa_flush(ctx);
2389bf215546Sopenharmony_ci}
2390bf215546Sopenharmony_ci
2391bf215546Sopenharmony_ci
2392bf215546Sopenharmony_cistatic void
2393bf215546Sopenharmony_ci_mesa_validated_multidrawelementsindirect(struct gl_context *ctx,
2394bf215546Sopenharmony_ci                                          GLenum mode, GLenum type,
2395bf215546Sopenharmony_ci                                          GLintptr indirect,
2396bf215546Sopenharmony_ci                                          GLintptr drawcount_offset,
2397bf215546Sopenharmony_ci                                          GLsizei drawcount, GLsizei stride,
2398bf215546Sopenharmony_ci                                          struct gl_buffer_object *drawcount_buffer)
2399bf215546Sopenharmony_ci{
2400bf215546Sopenharmony_ci   /* If drawcount_buffer is set, drawcount is the maximum draw count.*/
2401bf215546Sopenharmony_ci   if (drawcount == 0)
2402bf215546Sopenharmony_ci      return;
2403bf215546Sopenharmony_ci
2404bf215546Sopenharmony_ci   /* NOTE: IndexBufferObj is guaranteed to be a VBO. */
2405bf215546Sopenharmony_ci   struct _mesa_index_buffer ib;
2406bf215546Sopenharmony_ci   ib.count = 0;                /* unknown */
2407bf215546Sopenharmony_ci   ib.obj = ctx->Array.VAO->IndexBufferObj;
2408bf215546Sopenharmony_ci   ib.ptr = NULL;
2409bf215546Sopenharmony_ci   ib.index_size_shift = get_index_size_shift(type);
2410bf215546Sopenharmony_ci
2411bf215546Sopenharmony_ci   st_indirect_draw_vbo(ctx, mode, ctx->DrawIndirectBuffer, indirect,
2412bf215546Sopenharmony_ci                        drawcount, stride, drawcount_buffer,
2413bf215546Sopenharmony_ci                        drawcount_offset, &ib,
2414bf215546Sopenharmony_ci                        ctx->Array._PrimitiveRestart[ib.index_size_shift],
2415bf215546Sopenharmony_ci                        ctx->Array._RestartIndex[ib.index_size_shift]);
2416bf215546Sopenharmony_ci
2417bf215546Sopenharmony_ci   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
2418bf215546Sopenharmony_ci      _mesa_flush(ctx);
2419bf215546Sopenharmony_ci}
2420bf215546Sopenharmony_ci
2421bf215546Sopenharmony_ci
2422bf215546Sopenharmony_ci/**
2423bf215546Sopenharmony_ci * Like [Multi]DrawArrays/Elements, but they take most arguments from
2424bf215546Sopenharmony_ci * a buffer object.
2425bf215546Sopenharmony_ci */
2426bf215546Sopenharmony_civoid GLAPIENTRY
2427bf215546Sopenharmony_ci_mesa_DrawArraysIndirect(GLenum mode, const GLvoid *indirect)
2428bf215546Sopenharmony_ci{
2429bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2430bf215546Sopenharmony_ci
2431bf215546Sopenharmony_ci   /* From the ARB_draw_indirect spec:
2432bf215546Sopenharmony_ci    *
2433bf215546Sopenharmony_ci    *    "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
2434bf215546Sopenharmony_ci    *    compatibility profile, this indicates that DrawArraysIndirect and
2435bf215546Sopenharmony_ci    *    DrawElementsIndirect are to source their arguments directly from the
2436bf215546Sopenharmony_ci    *    pointer passed as their <indirect> parameters."
2437bf215546Sopenharmony_ci    */
2438bf215546Sopenharmony_ci   if (ctx->API == API_OPENGL_COMPAT &&
2439bf215546Sopenharmony_ci       !ctx->DrawIndirectBuffer) {
2440bf215546Sopenharmony_ci      DrawArraysIndirectCommand *cmd = (DrawArraysIndirectCommand *) indirect;
2441bf215546Sopenharmony_ci
2442bf215546Sopenharmony_ci      _mesa_DrawArraysInstancedBaseInstance(mode, cmd->first, cmd->count,
2443bf215546Sopenharmony_ci                                            cmd->primCount,
2444bf215546Sopenharmony_ci                                            cmd->baseInstance);
2445bf215546Sopenharmony_ci      return;
2446bf215546Sopenharmony_ci   }
2447bf215546Sopenharmony_ci
2448bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2449bf215546Sopenharmony_ci
2450bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2451bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2452bf215546Sopenharmony_ci
2453bf215546Sopenharmony_ci   if (ctx->NewState)
2454bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2455bf215546Sopenharmony_ci
2456bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2457bf215546Sopenharmony_ci       !_mesa_validate_DrawArraysIndirect(ctx, mode, indirect))
2458bf215546Sopenharmony_ci      return;
2459bf215546Sopenharmony_ci
2460bf215546Sopenharmony_ci   _mesa_validated_multidrawarraysindirect(ctx, mode, (GLintptr)indirect,
2461bf215546Sopenharmony_ci                                           0, 1, 16, NULL);
2462bf215546Sopenharmony_ci}
2463bf215546Sopenharmony_ci
2464bf215546Sopenharmony_ci
2465bf215546Sopenharmony_civoid GLAPIENTRY
2466bf215546Sopenharmony_ci_mesa_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect)
2467bf215546Sopenharmony_ci{
2468bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2469bf215546Sopenharmony_ci
2470bf215546Sopenharmony_ci   /* From the ARB_draw_indirect spec:
2471bf215546Sopenharmony_ci    *
2472bf215546Sopenharmony_ci    *    "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
2473bf215546Sopenharmony_ci    *    compatibility profile, this indicates that DrawArraysIndirect and
2474bf215546Sopenharmony_ci    *    DrawElementsIndirect are to source their arguments directly from the
2475bf215546Sopenharmony_ci    *    pointer passed as their <indirect> parameters."
2476bf215546Sopenharmony_ci    */
2477bf215546Sopenharmony_ci   if (ctx->API == API_OPENGL_COMPAT &&
2478bf215546Sopenharmony_ci       !ctx->DrawIndirectBuffer) {
2479bf215546Sopenharmony_ci      /*
2480bf215546Sopenharmony_ci       * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
2481bf215546Sopenharmony_ci       * may not come from a client array and must come from an index buffer.
2482bf215546Sopenharmony_ci       * If no element array buffer is bound, an INVALID_OPERATION error is
2483bf215546Sopenharmony_ci       * generated.
2484bf215546Sopenharmony_ci       */
2485bf215546Sopenharmony_ci      if (!ctx->Array.VAO->IndexBufferObj) {
2486bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
2487bf215546Sopenharmony_ci                     "glDrawElementsIndirect(no buffer bound "
2488bf215546Sopenharmony_ci                     "to GL_ELEMENT_ARRAY_BUFFER)");
2489bf215546Sopenharmony_ci      } else {
2490bf215546Sopenharmony_ci         DrawElementsIndirectCommand *cmd =
2491bf215546Sopenharmony_ci            (DrawElementsIndirectCommand *) indirect;
2492bf215546Sopenharmony_ci
2493bf215546Sopenharmony_ci         /* Convert offset to pointer */
2494bf215546Sopenharmony_ci         void *offset = (void *)
2495bf215546Sopenharmony_ci            (uintptr_t)((cmd->firstIndex * _mesa_sizeof_type(type)) & 0xffffffffUL);
2496bf215546Sopenharmony_ci
2497bf215546Sopenharmony_ci         _mesa_DrawElementsInstancedBaseVertexBaseInstance(mode, cmd->count,
2498bf215546Sopenharmony_ci                                                           type, offset,
2499bf215546Sopenharmony_ci                                                           cmd->primCount,
2500bf215546Sopenharmony_ci                                                           cmd->baseVertex,
2501bf215546Sopenharmony_ci                                                           cmd->baseInstance);
2502bf215546Sopenharmony_ci      }
2503bf215546Sopenharmony_ci
2504bf215546Sopenharmony_ci      return;
2505bf215546Sopenharmony_ci   }
2506bf215546Sopenharmony_ci
2507bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2508bf215546Sopenharmony_ci
2509bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2510bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2511bf215546Sopenharmony_ci
2512bf215546Sopenharmony_ci   if (ctx->NewState)
2513bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2514bf215546Sopenharmony_ci
2515bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2516bf215546Sopenharmony_ci       !_mesa_validate_DrawElementsIndirect(ctx, mode, type, indirect))
2517bf215546Sopenharmony_ci      return;
2518bf215546Sopenharmony_ci
2519bf215546Sopenharmony_ci   _mesa_validated_multidrawelementsindirect(ctx, mode, type,
2520bf215546Sopenharmony_ci                                             (GLintptr)indirect, 0,
2521bf215546Sopenharmony_ci                                             1, 20, NULL);
2522bf215546Sopenharmony_ci}
2523bf215546Sopenharmony_ci
2524bf215546Sopenharmony_ci
2525bf215546Sopenharmony_civoid GLAPIENTRY
2526bf215546Sopenharmony_ci_mesa_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect,
2527bf215546Sopenharmony_ci                              GLsizei primcount, GLsizei stride)
2528bf215546Sopenharmony_ci{
2529bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2530bf215546Sopenharmony_ci
2531bf215546Sopenharmony_ci   /* If <stride> is zero, the array elements are treated as tightly packed. */
2532bf215546Sopenharmony_ci   if (stride == 0)
2533bf215546Sopenharmony_ci      stride = sizeof(DrawArraysIndirectCommand);
2534bf215546Sopenharmony_ci
2535bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2536bf215546Sopenharmony_ci
2537bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2538bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2539bf215546Sopenharmony_ci
2540bf215546Sopenharmony_ci   if (ctx->NewState)
2541bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2542bf215546Sopenharmony_ci
2543bf215546Sopenharmony_ci   /* From the ARB_draw_indirect spec:
2544bf215546Sopenharmony_ci    *
2545bf215546Sopenharmony_ci    *    "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
2546bf215546Sopenharmony_ci    *    compatibility profile, this indicates that DrawArraysIndirect and
2547bf215546Sopenharmony_ci    *    DrawElementsIndirect are to source their arguments directly from the
2548bf215546Sopenharmony_ci    *    pointer passed as their <indirect> parameters."
2549bf215546Sopenharmony_ci    */
2550bf215546Sopenharmony_ci   if (ctx->API == API_OPENGL_COMPAT &&
2551bf215546Sopenharmony_ci       !ctx->DrawIndirectBuffer) {
2552bf215546Sopenharmony_ci
2553bf215546Sopenharmony_ci      if (!_mesa_is_no_error_enabled(ctx) &&
2554bf215546Sopenharmony_ci          (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
2555bf215546Sopenharmony_ci                                           "glMultiDrawArraysIndirect") ||
2556bf215546Sopenharmony_ci           !_mesa_validate_DrawArrays(ctx, mode, 1)))
2557bf215546Sopenharmony_ci         return;
2558bf215546Sopenharmony_ci
2559bf215546Sopenharmony_ci      struct pipe_draw_info info;
2560bf215546Sopenharmony_ci      info.mode = mode;
2561bf215546Sopenharmony_ci      info.index_size = 0;
2562bf215546Sopenharmony_ci      info.view_mask = 0;
2563bf215546Sopenharmony_ci      /* Packed section begin. */
2564bf215546Sopenharmony_ci      info.primitive_restart = false;
2565bf215546Sopenharmony_ci      info.has_user_indices = false;
2566bf215546Sopenharmony_ci      info.index_bounds_valid = false;
2567bf215546Sopenharmony_ci      info.increment_draw_id = primcount > 1;
2568bf215546Sopenharmony_ci      info.was_line_loop = false;
2569bf215546Sopenharmony_ci      info.take_index_buffer_ownership = false;
2570bf215546Sopenharmony_ci      info.index_bias_varies = false;
2571bf215546Sopenharmony_ci      /* Packed section end. */
2572bf215546Sopenharmony_ci
2573bf215546Sopenharmony_ci      const uint8_t *ptr = (const uint8_t *) indirect;
2574bf215546Sopenharmony_ci      for (unsigned i = 0; i < primcount; i++) {
2575bf215546Sopenharmony_ci         DrawArraysIndirectCommand *cmd = (DrawArraysIndirectCommand *) ptr;
2576bf215546Sopenharmony_ci
2577bf215546Sopenharmony_ci         info.start_instance = cmd->baseInstance;
2578bf215546Sopenharmony_ci         info.instance_count = cmd->primCount;
2579bf215546Sopenharmony_ci
2580bf215546Sopenharmony_ci         struct pipe_draw_start_count_bias draw;
2581bf215546Sopenharmony_ci         draw.start = cmd->first;
2582bf215546Sopenharmony_ci         draw.count = cmd->count;
2583bf215546Sopenharmony_ci
2584bf215546Sopenharmony_ci         ctx->Driver.DrawGallium(ctx, &info, i, &draw, 1);
2585bf215546Sopenharmony_ci         ptr += stride;
2586bf215546Sopenharmony_ci      }
2587bf215546Sopenharmony_ci
2588bf215546Sopenharmony_ci      return;
2589bf215546Sopenharmony_ci   }
2590bf215546Sopenharmony_ci
2591bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2592bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawArraysIndirect(ctx, mode, indirect,
2593bf215546Sopenharmony_ci                                               primcount, stride))
2594bf215546Sopenharmony_ci      return;
2595bf215546Sopenharmony_ci
2596bf215546Sopenharmony_ci   _mesa_validated_multidrawarraysindirect(ctx, mode, (GLintptr)indirect, 0,
2597bf215546Sopenharmony_ci                                           primcount, stride, NULL);
2598bf215546Sopenharmony_ci}
2599bf215546Sopenharmony_ci
2600bf215546Sopenharmony_ci
2601bf215546Sopenharmony_civoid GLAPIENTRY
2602bf215546Sopenharmony_ci_mesa_MultiDrawElementsIndirect(GLenum mode, GLenum type,
2603bf215546Sopenharmony_ci                                const GLvoid *indirect,
2604bf215546Sopenharmony_ci                                GLsizei primcount, GLsizei stride)
2605bf215546Sopenharmony_ci{
2606bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2607bf215546Sopenharmony_ci
2608bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2609bf215546Sopenharmony_ci
2610bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2611bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2612bf215546Sopenharmony_ci
2613bf215546Sopenharmony_ci   if (ctx->NewState)
2614bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2615bf215546Sopenharmony_ci
2616bf215546Sopenharmony_ci   /* If <stride> is zero, the array elements are treated as tightly packed. */
2617bf215546Sopenharmony_ci   if (stride == 0)
2618bf215546Sopenharmony_ci      stride = sizeof(DrawElementsIndirectCommand);
2619bf215546Sopenharmony_ci
2620bf215546Sopenharmony_ci   /* From the ARB_draw_indirect spec:
2621bf215546Sopenharmony_ci    *
2622bf215546Sopenharmony_ci    *    "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
2623bf215546Sopenharmony_ci    *    compatibility profile, this indicates that DrawArraysIndirect and
2624bf215546Sopenharmony_ci    *    DrawElementsIndirect are to source their arguments directly from the
2625bf215546Sopenharmony_ci    *    pointer passed as their <indirect> parameters."
2626bf215546Sopenharmony_ci    */
2627bf215546Sopenharmony_ci   if (ctx->API == API_OPENGL_COMPAT &&
2628bf215546Sopenharmony_ci       !ctx->DrawIndirectBuffer) {
2629bf215546Sopenharmony_ci      /*
2630bf215546Sopenharmony_ci       * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
2631bf215546Sopenharmony_ci       * may not come from a client array and must come from an index buffer.
2632bf215546Sopenharmony_ci       * If no element array buffer is bound, an INVALID_OPERATION error is
2633bf215546Sopenharmony_ci       * generated.
2634bf215546Sopenharmony_ci       */
2635bf215546Sopenharmony_ci      if (!ctx->Array.VAO->IndexBufferObj) {
2636bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
2637bf215546Sopenharmony_ci                     "glMultiDrawElementsIndirect(no buffer bound "
2638bf215546Sopenharmony_ci                     "to GL_ELEMENT_ARRAY_BUFFER)");
2639bf215546Sopenharmony_ci
2640bf215546Sopenharmony_ci         return;
2641bf215546Sopenharmony_ci      }
2642bf215546Sopenharmony_ci
2643bf215546Sopenharmony_ci      if (!_mesa_is_no_error_enabled(ctx) &&
2644bf215546Sopenharmony_ci          (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
2645bf215546Sopenharmony_ci                                           "glMultiDrawArraysIndirect") ||
2646bf215546Sopenharmony_ci           !_mesa_validate_DrawElements(ctx, mode, 1, type)))
2647bf215546Sopenharmony_ci         return;
2648bf215546Sopenharmony_ci
2649bf215546Sopenharmony_ci      unsigned index_size_shift = get_index_size_shift(type);
2650bf215546Sopenharmony_ci
2651bf215546Sopenharmony_ci      struct pipe_draw_info info;
2652bf215546Sopenharmony_ci      info.mode = mode;
2653bf215546Sopenharmony_ci      info.index_size = 1 << index_size_shift;
2654bf215546Sopenharmony_ci      info.view_mask = 0;
2655bf215546Sopenharmony_ci      /* Packed section begin. */
2656bf215546Sopenharmony_ci      info.primitive_restart = ctx->Array._PrimitiveRestart[index_size_shift];
2657bf215546Sopenharmony_ci      info.has_user_indices = false;
2658bf215546Sopenharmony_ci      info.index_bounds_valid = false;
2659bf215546Sopenharmony_ci      info.increment_draw_id = primcount > 1;
2660bf215546Sopenharmony_ci      info.was_line_loop = false;
2661bf215546Sopenharmony_ci      info.take_index_buffer_ownership = false;
2662bf215546Sopenharmony_ci      info.index_bias_varies = false;
2663bf215546Sopenharmony_ci      /* Packed section end. */
2664bf215546Sopenharmony_ci      info.restart_index = ctx->Array._RestartIndex[index_size_shift];
2665bf215546Sopenharmony_ci
2666bf215546Sopenharmony_ci      const uint8_t *ptr = (const uint8_t *) indirect;
2667bf215546Sopenharmony_ci      for (unsigned i = 0; i < primcount; i++) {
2668bf215546Sopenharmony_ci         DrawElementsIndirectCommand *cmd = (DrawElementsIndirectCommand*)ptr;
2669bf215546Sopenharmony_ci
2670bf215546Sopenharmony_ci         info.index.gl_bo = ctx->Array.VAO->IndexBufferObj;
2671bf215546Sopenharmony_ci         info.start_instance = cmd->baseInstance;
2672bf215546Sopenharmony_ci         info.instance_count = cmd->primCount;
2673bf215546Sopenharmony_ci
2674bf215546Sopenharmony_ci         struct pipe_draw_start_count_bias draw;
2675bf215546Sopenharmony_ci         draw.start = cmd->firstIndex;
2676bf215546Sopenharmony_ci         draw.count = cmd->count;
2677bf215546Sopenharmony_ci         draw.index_bias = cmd->baseVertex;
2678bf215546Sopenharmony_ci
2679bf215546Sopenharmony_ci         ctx->Driver.DrawGallium(ctx, &info, i, &draw, 1);
2680bf215546Sopenharmony_ci         ptr += stride;
2681bf215546Sopenharmony_ci      }
2682bf215546Sopenharmony_ci
2683bf215546Sopenharmony_ci      return;
2684bf215546Sopenharmony_ci   }
2685bf215546Sopenharmony_ci
2686bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2687bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawElementsIndirect(ctx, mode, type, indirect,
2688bf215546Sopenharmony_ci                                                 primcount, stride))
2689bf215546Sopenharmony_ci      return;
2690bf215546Sopenharmony_ci
2691bf215546Sopenharmony_ci   _mesa_validated_multidrawelementsindirect(ctx, mode, type,
2692bf215546Sopenharmony_ci                                             (GLintptr)indirect, 0, primcount,
2693bf215546Sopenharmony_ci                                             stride, NULL);
2694bf215546Sopenharmony_ci}
2695bf215546Sopenharmony_ci
2696bf215546Sopenharmony_ci
2697bf215546Sopenharmony_civoid GLAPIENTRY
2698bf215546Sopenharmony_ci_mesa_MultiDrawArraysIndirectCountARB(GLenum mode, GLintptr indirect,
2699bf215546Sopenharmony_ci                                      GLintptr drawcount_offset,
2700bf215546Sopenharmony_ci                                      GLsizei maxdrawcount, GLsizei stride)
2701bf215546Sopenharmony_ci{
2702bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2703bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2704bf215546Sopenharmony_ci
2705bf215546Sopenharmony_ci   /* If <stride> is zero, the array elements are treated as tightly packed. */
2706bf215546Sopenharmony_ci   if (stride == 0)
2707bf215546Sopenharmony_ci      stride = 4 * sizeof(GLuint);      /* sizeof(DrawArraysIndirectCommand) */
2708bf215546Sopenharmony_ci
2709bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2710bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2711bf215546Sopenharmony_ci
2712bf215546Sopenharmony_ci   if (ctx->NewState)
2713bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2714bf215546Sopenharmony_ci
2715bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2716bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawArraysIndirectCount(ctx, mode, indirect,
2717bf215546Sopenharmony_ci                                                    drawcount_offset,
2718bf215546Sopenharmony_ci                                                    maxdrawcount, stride))
2719bf215546Sopenharmony_ci      return;
2720bf215546Sopenharmony_ci
2721bf215546Sopenharmony_ci   _mesa_validated_multidrawarraysindirect(ctx, mode, indirect,
2722bf215546Sopenharmony_ci                                           drawcount_offset, maxdrawcount,
2723bf215546Sopenharmony_ci                                           stride, ctx->ParameterBuffer);
2724bf215546Sopenharmony_ci}
2725bf215546Sopenharmony_ci
2726bf215546Sopenharmony_ci
2727bf215546Sopenharmony_civoid GLAPIENTRY
2728bf215546Sopenharmony_ci_mesa_MultiDrawElementsIndirectCountARB(GLenum mode, GLenum type,
2729bf215546Sopenharmony_ci                                        GLintptr indirect,
2730bf215546Sopenharmony_ci                                        GLintptr drawcount_offset,
2731bf215546Sopenharmony_ci                                        GLsizei maxdrawcount, GLsizei stride)
2732bf215546Sopenharmony_ci{
2733bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2734bf215546Sopenharmony_ci   FLUSH_FOR_DRAW(ctx);
2735bf215546Sopenharmony_ci
2736bf215546Sopenharmony_ci   /* If <stride> is zero, the array elements are treated as tightly packed. */
2737bf215546Sopenharmony_ci   if (stride == 0)
2738bf215546Sopenharmony_ci      stride = 5 * sizeof(GLuint);      /* sizeof(DrawElementsIndirectCommand) */
2739bf215546Sopenharmony_ci
2740bf215546Sopenharmony_ci   _mesa_set_draw_vao(ctx, ctx->Array.VAO,
2741bf215546Sopenharmony_ci                      ctx->VertexProgram._VPModeInputFilter);
2742bf215546Sopenharmony_ci
2743bf215546Sopenharmony_ci   if (ctx->NewState)
2744bf215546Sopenharmony_ci      _mesa_update_state(ctx);
2745bf215546Sopenharmony_ci
2746bf215546Sopenharmony_ci   if (!_mesa_is_no_error_enabled(ctx) &&
2747bf215546Sopenharmony_ci       !_mesa_validate_MultiDrawElementsIndirectCount(ctx, mode, type,
2748bf215546Sopenharmony_ci                                                      indirect,
2749bf215546Sopenharmony_ci                                                      drawcount_offset,
2750bf215546Sopenharmony_ci                                                      maxdrawcount, stride))
2751bf215546Sopenharmony_ci      return;
2752bf215546Sopenharmony_ci
2753bf215546Sopenharmony_ci   _mesa_validated_multidrawelementsindirect(ctx, mode, type, indirect,
2754bf215546Sopenharmony_ci                                             drawcount_offset, maxdrawcount,
2755bf215546Sopenharmony_ci                                             stride, ctx->ParameterBuffer);
2756bf215546Sopenharmony_ci}
2757bf215546Sopenharmony_ci
2758bf215546Sopenharmony_ci
2759bf215546Sopenharmony_ci/* GL_IBM_multimode_draw_arrays */
2760bf215546Sopenharmony_civoid GLAPIENTRY
2761bf215546Sopenharmony_ci_mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
2762bf215546Sopenharmony_ci                              const GLsizei * count,
2763bf215546Sopenharmony_ci                              GLsizei primcount, GLint modestride )
2764bf215546Sopenharmony_ci{
2765bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2766bf215546Sopenharmony_ci   GLint i;
2767bf215546Sopenharmony_ci
2768bf215546Sopenharmony_ci   for ( i = 0 ; i < primcount ; i++ ) {
2769bf215546Sopenharmony_ci      if ( count[i] > 0 ) {
2770bf215546Sopenharmony_ci         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
2771bf215546Sopenharmony_ci         CALL_DrawArrays(ctx->CurrentServerDispatch, ( m, first[i], count[i] ));
2772bf215546Sopenharmony_ci      }
2773bf215546Sopenharmony_ci   }
2774bf215546Sopenharmony_ci}
2775bf215546Sopenharmony_ci
2776bf215546Sopenharmony_ci
2777bf215546Sopenharmony_ci/* GL_IBM_multimode_draw_arrays */
2778bf215546Sopenharmony_civoid GLAPIENTRY
2779bf215546Sopenharmony_ci_mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
2780bf215546Sopenharmony_ci                                GLenum type, const GLvoid * const * indices,
2781bf215546Sopenharmony_ci                                GLsizei primcount, GLint modestride )
2782bf215546Sopenharmony_ci{
2783bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2784bf215546Sopenharmony_ci   GLint i;
2785bf215546Sopenharmony_ci
2786bf215546Sopenharmony_ci   for ( i = 0 ; i < primcount ; i++ ) {
2787bf215546Sopenharmony_ci      if ( count[i] > 0 ) {
2788bf215546Sopenharmony_ci         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
2789bf215546Sopenharmony_ci         CALL_DrawElements(ctx->CurrentServerDispatch, ( m, count[i], type,
2790bf215546Sopenharmony_ci                                                         indices[i] ));
2791bf215546Sopenharmony_ci      }
2792bf215546Sopenharmony_ci   }
2793bf215546Sopenharmony_ci}
2794