1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright 2003 VMware, Inc.
5bf215546Sopenharmony_ci * Copyright 2009 VMware, Inc.
6bf215546Sopenharmony_ci * All Rights Reserved.
7bf215546Sopenharmony_ci * Copyright (C) 2016 Advanced Micro Devices, Inc.
8bf215546Sopenharmony_ci *
9bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
10bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
11bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
12bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
14bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
17bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
18bf215546Sopenharmony_ci * Software.
19bf215546Sopenharmony_ci *
20bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
23bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
24bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
27bf215546Sopenharmony_ci */
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "main/glheader.h"
30bf215546Sopenharmony_ci#include "main/context.h"
31bf215546Sopenharmony_ci#include "main/varray.h"
32bf215546Sopenharmony_ci#include "main/macros.h"
33bf215546Sopenharmony_ci#include "main/sse_minmax.h"
34bf215546Sopenharmony_ci#include "x86/common_x86_asm.h"
35bf215546Sopenharmony_ci#include "util/hash_table.h"
36bf215546Sopenharmony_ci#include "util/u_memory.h"
37bf215546Sopenharmony_ci#include "pipe/p_state.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_cistruct minmax_cache_key {
40bf215546Sopenharmony_ci   GLintptr offset;
41bf215546Sopenharmony_ci   GLuint count;
42bf215546Sopenharmony_ci   unsigned index_size;
43bf215546Sopenharmony_ci};
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_cistruct minmax_cache_entry {
47bf215546Sopenharmony_ci   struct minmax_cache_key key;
48bf215546Sopenharmony_ci   GLuint min;
49bf215546Sopenharmony_ci   GLuint max;
50bf215546Sopenharmony_ci};
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_cistatic uint32_t
54bf215546Sopenharmony_civbo_minmax_cache_hash(const struct minmax_cache_key *key)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(*key));
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic bool
61bf215546Sopenharmony_civbo_minmax_cache_key_equal(const struct minmax_cache_key *a,
62bf215546Sopenharmony_ci                           const struct minmax_cache_key *b)
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci   return (a->offset == b->offset) && (a->count == b->count) &&
65bf215546Sopenharmony_ci          (a->index_size == b->index_size);
66bf215546Sopenharmony_ci}
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cistatic void
70bf215546Sopenharmony_civbo_minmax_cache_delete_entry(struct hash_entry *entry)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   free(entry->data);
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic GLboolean
77bf215546Sopenharmony_civbo_use_minmax_cache(struct gl_buffer_object *bufferObj)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   if (bufferObj->UsageHistory & (USAGE_TEXTURE_BUFFER |
80bf215546Sopenharmony_ci                                  USAGE_ATOMIC_COUNTER_BUFFER |
81bf215546Sopenharmony_ci                                  USAGE_SHADER_STORAGE_BUFFER |
82bf215546Sopenharmony_ci                                  USAGE_TRANSFORM_FEEDBACK_BUFFER |
83bf215546Sopenharmony_ci                                  USAGE_PIXEL_PACK_BUFFER |
84bf215546Sopenharmony_ci                                  USAGE_DISABLE_MINMAX_CACHE))
85bf215546Sopenharmony_ci      return GL_FALSE;
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   if ((bufferObj->Mappings[MAP_USER].AccessFlags &
88bf215546Sopenharmony_ci        (GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT)) ==
89bf215546Sopenharmony_ci       (GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT))
90bf215546Sopenharmony_ci      return GL_FALSE;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   return GL_TRUE;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_civoid
97bf215546Sopenharmony_civbo_delete_minmax_cache(struct gl_buffer_object *bufferObj)
98bf215546Sopenharmony_ci{
99bf215546Sopenharmony_ci   _mesa_hash_table_destroy(bufferObj->MinMaxCache, vbo_minmax_cache_delete_entry);
100bf215546Sopenharmony_ci   bufferObj->MinMaxCache = NULL;
101bf215546Sopenharmony_ci}
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic GLboolean
105bf215546Sopenharmony_civbo_get_minmax_cached(struct gl_buffer_object *bufferObj,
106bf215546Sopenharmony_ci                      unsigned index_size, GLintptr offset, GLuint count,
107bf215546Sopenharmony_ci                      GLuint *min_index, GLuint *max_index)
108bf215546Sopenharmony_ci{
109bf215546Sopenharmony_ci   GLboolean found = GL_FALSE;
110bf215546Sopenharmony_ci   struct minmax_cache_key key;
111bf215546Sopenharmony_ci   uint32_t hash;
112bf215546Sopenharmony_ci   struct hash_entry *result;
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   if (!bufferObj->MinMaxCache)
115bf215546Sopenharmony_ci      return GL_FALSE;
116bf215546Sopenharmony_ci   if (!vbo_use_minmax_cache(bufferObj))
117bf215546Sopenharmony_ci      return GL_FALSE;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   simple_mtx_lock(&bufferObj->MinMaxCacheMutex);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   if (bufferObj->MinMaxCacheDirty) {
122bf215546Sopenharmony_ci      /* Disable the cache permanently for this BO if the number of hits
123bf215546Sopenharmony_ci       * is asymptotically less than the number of misses. This happens when
124bf215546Sopenharmony_ci       * applications use the BO for streaming.
125bf215546Sopenharmony_ci       *
126bf215546Sopenharmony_ci       * However, some initial optimism allows applications that interleave
127bf215546Sopenharmony_ci       * draw calls with glBufferSubData during warmup.
128bf215546Sopenharmony_ci       */
129bf215546Sopenharmony_ci      unsigned optimism = bufferObj->Size;
130bf215546Sopenharmony_ci      if (bufferObj->MinMaxCacheMissIndices > optimism &&
131bf215546Sopenharmony_ci          bufferObj->MinMaxCacheHitIndices < bufferObj->MinMaxCacheMissIndices - optimism) {
132bf215546Sopenharmony_ci         bufferObj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
133bf215546Sopenharmony_ci         vbo_delete_minmax_cache(bufferObj);
134bf215546Sopenharmony_ci         goto out_disable;
135bf215546Sopenharmony_ci      }
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci      _mesa_hash_table_clear(bufferObj->MinMaxCache, vbo_minmax_cache_delete_entry);
138bf215546Sopenharmony_ci      bufferObj->MinMaxCacheDirty = false;
139bf215546Sopenharmony_ci      goto out_invalidate;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   key.index_size = index_size;
143bf215546Sopenharmony_ci   key.offset = offset;
144bf215546Sopenharmony_ci   key.count = count;
145bf215546Sopenharmony_ci   hash = vbo_minmax_cache_hash(&key);
146bf215546Sopenharmony_ci   result = _mesa_hash_table_search_pre_hashed(bufferObj->MinMaxCache, hash, &key);
147bf215546Sopenharmony_ci   if (result) {
148bf215546Sopenharmony_ci      struct minmax_cache_entry *entry = result->data;
149bf215546Sopenharmony_ci      *min_index = entry->min;
150bf215546Sopenharmony_ci      *max_index = entry->max;
151bf215546Sopenharmony_ci      found = GL_TRUE;
152bf215546Sopenharmony_ci   }
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ciout_invalidate:
155bf215546Sopenharmony_ci   if (found) {
156bf215546Sopenharmony_ci      /* The hit counter saturates so that we don't accidently disable the
157bf215546Sopenharmony_ci       * cache in a long-running program.
158bf215546Sopenharmony_ci       */
159bf215546Sopenharmony_ci      unsigned new_hit_count = bufferObj->MinMaxCacheHitIndices + count;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci      if (new_hit_count >= bufferObj->MinMaxCacheHitIndices)
162bf215546Sopenharmony_ci         bufferObj->MinMaxCacheHitIndices = new_hit_count;
163bf215546Sopenharmony_ci      else
164bf215546Sopenharmony_ci         bufferObj->MinMaxCacheHitIndices = ~(unsigned)0;
165bf215546Sopenharmony_ci   } else {
166bf215546Sopenharmony_ci      bufferObj->MinMaxCacheMissIndices += count;
167bf215546Sopenharmony_ci   }
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ciout_disable:
170bf215546Sopenharmony_ci   simple_mtx_unlock(&bufferObj->MinMaxCacheMutex);
171bf215546Sopenharmony_ci   return found;
172bf215546Sopenharmony_ci}
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_cistatic void
176bf215546Sopenharmony_civbo_minmax_cache_store(struct gl_context *ctx,
177bf215546Sopenharmony_ci                       struct gl_buffer_object *bufferObj,
178bf215546Sopenharmony_ci                       unsigned index_size, GLintptr offset, GLuint count,
179bf215546Sopenharmony_ci                       GLuint min, GLuint max)
180bf215546Sopenharmony_ci{
181bf215546Sopenharmony_ci   struct minmax_cache_entry *entry;
182bf215546Sopenharmony_ci   struct hash_entry *table_entry;
183bf215546Sopenharmony_ci   uint32_t hash;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   if (!vbo_use_minmax_cache(bufferObj))
186bf215546Sopenharmony_ci      return;
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   simple_mtx_lock(&bufferObj->MinMaxCacheMutex);
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   if (!bufferObj->MinMaxCache) {
191bf215546Sopenharmony_ci      bufferObj->MinMaxCache =
192bf215546Sopenharmony_ci         _mesa_hash_table_create(NULL,
193bf215546Sopenharmony_ci                                 (uint32_t (*)(const void *))vbo_minmax_cache_hash,
194bf215546Sopenharmony_ci                                 (bool (*)(const void *, const void *))vbo_minmax_cache_key_equal);
195bf215546Sopenharmony_ci      if (!bufferObj->MinMaxCache)
196bf215546Sopenharmony_ci         goto out;
197bf215546Sopenharmony_ci   }
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   entry = MALLOC_STRUCT(minmax_cache_entry);
200bf215546Sopenharmony_ci   if (!entry)
201bf215546Sopenharmony_ci      goto out;
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   entry->key.offset = offset;
204bf215546Sopenharmony_ci   entry->key.count = count;
205bf215546Sopenharmony_ci   entry->key.index_size = index_size;
206bf215546Sopenharmony_ci   entry->min = min;
207bf215546Sopenharmony_ci   entry->max = max;
208bf215546Sopenharmony_ci   hash = vbo_minmax_cache_hash(&entry->key);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   table_entry = _mesa_hash_table_search_pre_hashed(bufferObj->MinMaxCache,
211bf215546Sopenharmony_ci                                                    hash, &entry->key);
212bf215546Sopenharmony_ci   if (table_entry) {
213bf215546Sopenharmony_ci      /* It seems like this could happen when two contexts are rendering using
214bf215546Sopenharmony_ci       * the same buffer object from multiple threads.
215bf215546Sopenharmony_ci       */
216bf215546Sopenharmony_ci      _mesa_debug(ctx, "duplicate entry in minmax cache\n");
217bf215546Sopenharmony_ci      free(entry);
218bf215546Sopenharmony_ci      goto out;
219bf215546Sopenharmony_ci   }
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   table_entry = _mesa_hash_table_insert_pre_hashed(bufferObj->MinMaxCache,
222bf215546Sopenharmony_ci                                                    hash, &entry->key, entry);
223bf215546Sopenharmony_ci   if (!table_entry)
224bf215546Sopenharmony_ci      free(entry);
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ciout:
227bf215546Sopenharmony_ci   simple_mtx_unlock(&bufferObj->MinMaxCacheMutex);
228bf215546Sopenharmony_ci}
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_civoid
232bf215546Sopenharmony_civbo_get_minmax_index_mapped(unsigned count, unsigned index_size,
233bf215546Sopenharmony_ci                            unsigned restartIndex, bool restart,
234bf215546Sopenharmony_ci                            const void *indices,
235bf215546Sopenharmony_ci                            unsigned *min_index, unsigned *max_index)
236bf215546Sopenharmony_ci{
237bf215546Sopenharmony_ci   switch (index_size) {
238bf215546Sopenharmony_ci   case 4: {
239bf215546Sopenharmony_ci      const GLuint *ui_indices = (const GLuint *)indices;
240bf215546Sopenharmony_ci      GLuint max_ui = 0;
241bf215546Sopenharmony_ci      GLuint min_ui = ~0U;
242bf215546Sopenharmony_ci      if (restart) {
243bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
244bf215546Sopenharmony_ci            if (ui_indices[i] != restartIndex) {
245bf215546Sopenharmony_ci               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
246bf215546Sopenharmony_ci               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
247bf215546Sopenharmony_ci            }
248bf215546Sopenharmony_ci         }
249bf215546Sopenharmony_ci      }
250bf215546Sopenharmony_ci      else {
251bf215546Sopenharmony_ci#if defined(USE_SSE41)
252bf215546Sopenharmony_ci         if (cpu_has_sse4_1) {
253bf215546Sopenharmony_ci            _mesa_uint_array_min_max(ui_indices, &min_ui, &max_ui, count);
254bf215546Sopenharmony_ci         }
255bf215546Sopenharmony_ci         else
256bf215546Sopenharmony_ci#endif
257bf215546Sopenharmony_ci            for (unsigned i = 0; i < count; i++) {
258bf215546Sopenharmony_ci               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
259bf215546Sopenharmony_ci               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
260bf215546Sopenharmony_ci            }
261bf215546Sopenharmony_ci      }
262bf215546Sopenharmony_ci      *min_index = min_ui;
263bf215546Sopenharmony_ci      *max_index = max_ui;
264bf215546Sopenharmony_ci      break;
265bf215546Sopenharmony_ci   }
266bf215546Sopenharmony_ci   case 2: {
267bf215546Sopenharmony_ci      const GLushort *us_indices = (const GLushort *)indices;
268bf215546Sopenharmony_ci      GLuint max_us = 0;
269bf215546Sopenharmony_ci      GLuint min_us = ~0U;
270bf215546Sopenharmony_ci      if (restart) {
271bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
272bf215546Sopenharmony_ci            if (us_indices[i] != restartIndex) {
273bf215546Sopenharmony_ci               if (us_indices[i] > max_us) max_us = us_indices[i];
274bf215546Sopenharmony_ci               if (us_indices[i] < min_us) min_us = us_indices[i];
275bf215546Sopenharmony_ci            }
276bf215546Sopenharmony_ci         }
277bf215546Sopenharmony_ci      }
278bf215546Sopenharmony_ci      else {
279bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
280bf215546Sopenharmony_ci            if (us_indices[i] > max_us) max_us = us_indices[i];
281bf215546Sopenharmony_ci            if (us_indices[i] < min_us) min_us = us_indices[i];
282bf215546Sopenharmony_ci         }
283bf215546Sopenharmony_ci      }
284bf215546Sopenharmony_ci      *min_index = min_us;
285bf215546Sopenharmony_ci      *max_index = max_us;
286bf215546Sopenharmony_ci      break;
287bf215546Sopenharmony_ci   }
288bf215546Sopenharmony_ci   case 1: {
289bf215546Sopenharmony_ci      const GLubyte *ub_indices = (const GLubyte *)indices;
290bf215546Sopenharmony_ci      GLuint max_ub = 0;
291bf215546Sopenharmony_ci      GLuint min_ub = ~0U;
292bf215546Sopenharmony_ci      if (restart) {
293bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
294bf215546Sopenharmony_ci            if (ub_indices[i] != restartIndex) {
295bf215546Sopenharmony_ci               if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
296bf215546Sopenharmony_ci               if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
297bf215546Sopenharmony_ci            }
298bf215546Sopenharmony_ci         }
299bf215546Sopenharmony_ci      }
300bf215546Sopenharmony_ci      else {
301bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
302bf215546Sopenharmony_ci            if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
303bf215546Sopenharmony_ci            if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
304bf215546Sopenharmony_ci         }
305bf215546Sopenharmony_ci      }
306bf215546Sopenharmony_ci      *min_index = min_ub;
307bf215546Sopenharmony_ci      *max_index = max_ub;
308bf215546Sopenharmony_ci      break;
309bf215546Sopenharmony_ci   }
310bf215546Sopenharmony_ci   default:
311bf215546Sopenharmony_ci      unreachable("not reached");
312bf215546Sopenharmony_ci   }
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci/**
317bf215546Sopenharmony_ci * Compute min and max elements by scanning the index buffer for
318bf215546Sopenharmony_ci * glDraw[Range]Elements() calls.
319bf215546Sopenharmony_ci * If primitive restart is enabled, we need to ignore restart
320bf215546Sopenharmony_ci * indexes when computing min/max.
321bf215546Sopenharmony_ci */
322bf215546Sopenharmony_cistatic void
323bf215546Sopenharmony_civbo_get_minmax_index(struct gl_context *ctx, struct gl_buffer_object *obj,
324bf215546Sopenharmony_ci                     const void *ptr, GLintptr offset, unsigned count,
325bf215546Sopenharmony_ci                     unsigned index_size, bool primitive_restart,
326bf215546Sopenharmony_ci                     unsigned restart_index, GLuint *min_index,
327bf215546Sopenharmony_ci                     GLuint *max_index)
328bf215546Sopenharmony_ci{
329bf215546Sopenharmony_ci   const char *indices;
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   if (!obj) {
332bf215546Sopenharmony_ci      indices = (const char *)ptr + offset;
333bf215546Sopenharmony_ci   } else {
334bf215546Sopenharmony_ci      GLsizeiptr size = MIN2((GLsizeiptr)count * index_size, obj->Size);
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci      if (vbo_get_minmax_cached(obj, index_size, offset, count, min_index,
337bf215546Sopenharmony_ci                                max_index))
338bf215546Sopenharmony_ci         return;
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci      indices = _mesa_bufferobj_map_range(ctx, offset, size, GL_MAP_READ_BIT,
341bf215546Sopenharmony_ci                                          obj, MAP_INTERNAL);
342bf215546Sopenharmony_ci   }
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   vbo_get_minmax_index_mapped(count, index_size, restart_index,
345bf215546Sopenharmony_ci                               primitive_restart, indices,
346bf215546Sopenharmony_ci                               min_index, max_index);
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   if (obj) {
349bf215546Sopenharmony_ci      vbo_minmax_cache_store(ctx, obj, index_size, offset, count, *min_index,
350bf215546Sopenharmony_ci                             *max_index);
351bf215546Sopenharmony_ci      _mesa_bufferobj_unmap(ctx, obj, MAP_INTERNAL);
352bf215546Sopenharmony_ci   }
353bf215546Sopenharmony_ci}
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci/**
356bf215546Sopenharmony_ci * Compute min and max elements for nr_prims
357bf215546Sopenharmony_ci */
358bf215546Sopenharmony_civoid
359bf215546Sopenharmony_civbo_get_minmax_indices(struct gl_context *ctx,
360bf215546Sopenharmony_ci                       const struct _mesa_prim *prims,
361bf215546Sopenharmony_ci                       const struct _mesa_index_buffer *ib,
362bf215546Sopenharmony_ci                       GLuint *min_index,
363bf215546Sopenharmony_ci                       GLuint *max_index,
364bf215546Sopenharmony_ci                       GLuint nr_prims,
365bf215546Sopenharmony_ci                       bool primitive_restart,
366bf215546Sopenharmony_ci                       unsigned restart_index)
367bf215546Sopenharmony_ci{
368bf215546Sopenharmony_ci   GLuint tmp_min, tmp_max;
369bf215546Sopenharmony_ci   GLuint i;
370bf215546Sopenharmony_ci   GLuint count;
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   *min_index = ~0;
373bf215546Sopenharmony_ci   *max_index = 0;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   for (i = 0; i < nr_prims; i++) {
376bf215546Sopenharmony_ci      const struct _mesa_prim *start_prim;
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci      start_prim = &prims[i];
379bf215546Sopenharmony_ci      count = start_prim->count;
380bf215546Sopenharmony_ci      /* Do combination if possible to reduce map/unmap count */
381bf215546Sopenharmony_ci      while ((i + 1 < nr_prims) &&
382bf215546Sopenharmony_ci             (prims[i].start + prims[i].count == prims[i+1].start)) {
383bf215546Sopenharmony_ci         count += prims[i+1].count;
384bf215546Sopenharmony_ci         i++;
385bf215546Sopenharmony_ci      }
386bf215546Sopenharmony_ci      vbo_get_minmax_index(ctx, ib->obj, ib->ptr,
387bf215546Sopenharmony_ci                           (ib->obj ? (GLintptr)ib->ptr : 0) +
388bf215546Sopenharmony_ci                           (start_prim->start << ib->index_size_shift),
389bf215546Sopenharmony_ci                           count, 1 << ib->index_size_shift,
390bf215546Sopenharmony_ci                           primitive_restart, restart_index,
391bf215546Sopenharmony_ci                           &tmp_min, &tmp_max);
392bf215546Sopenharmony_ci      *min_index = MIN2(*min_index, tmp_min);
393bf215546Sopenharmony_ci      *max_index = MAX2(*max_index, tmp_max);
394bf215546Sopenharmony_ci   }
395bf215546Sopenharmony_ci}
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci/**
398bf215546Sopenharmony_ci * Same as vbo_get_minmax_index, but using gallium draw structures.
399bf215546Sopenharmony_ci */
400bf215546Sopenharmony_cibool
401bf215546Sopenharmony_civbo_get_minmax_indices_gallium(struct gl_context *ctx,
402bf215546Sopenharmony_ci                               struct pipe_draw_info *info,
403bf215546Sopenharmony_ci                               const struct pipe_draw_start_count_bias *draws,
404bf215546Sopenharmony_ci                               unsigned num_draws)
405bf215546Sopenharmony_ci{
406bf215546Sopenharmony_ci   info->min_index = ~0;
407bf215546Sopenharmony_ci   info->max_index = 0;
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   for (unsigned i = 0; i < num_draws; i++) {
410bf215546Sopenharmony_ci      struct pipe_draw_start_count_bias draw = draws[i];
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci      /* Do combination if possible to reduce map/unmap count */
413bf215546Sopenharmony_ci      while ((i + 1 < num_draws) &&
414bf215546Sopenharmony_ci             (draws[i].start + draws[i].count == draws[i+1].start)) {
415bf215546Sopenharmony_ci         draw.count += draws[i+1].count;
416bf215546Sopenharmony_ci         i++;
417bf215546Sopenharmony_ci      }
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci      if (!draw.count)
420bf215546Sopenharmony_ci         continue;
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci      unsigned tmp_min, tmp_max;
423bf215546Sopenharmony_ci      vbo_get_minmax_index(ctx, info->has_user_indices ?
424bf215546Sopenharmony_ci                              NULL : info->index.gl_bo,
425bf215546Sopenharmony_ci                           info->index.user,
426bf215546Sopenharmony_ci                           (GLintptr)draw.start * info->index_size,
427bf215546Sopenharmony_ci                           draw.count, info->index_size,
428bf215546Sopenharmony_ci                           info->primitive_restart, info->restart_index,
429bf215546Sopenharmony_ci                           &tmp_min, &tmp_max);
430bf215546Sopenharmony_ci      info->min_index = MIN2(info->min_index, tmp_min);
431bf215546Sopenharmony_ci      info->max_index = MAX2(info->max_index, tmp_max);
432bf215546Sopenharmony_ci   }
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   return info->min_index <= info->max_index;
435bf215546Sopenharmony_ci}
436