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