1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2014 VMware, Inc. 3bf215546Sopenharmony_ci * All Rights Reserved. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 7bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 8bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 9bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 10bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 11bf215546Sopenharmony_ci * the following conditions: 12bf215546Sopenharmony_ci * 13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 14bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 15bf215546Sopenharmony_ci * of the Software. 16bf215546Sopenharmony_ci * 17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "u_inlines.h" 29bf215546Sopenharmony_ci#include "util/u_memory.h" 30bf215546Sopenharmony_ci#include "u_prim_restart.h" 31bf215546Sopenharmony_ci#include "u_prim.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_citypedef struct { 34bf215546Sopenharmony_ci uint32_t count; 35bf215546Sopenharmony_ci uint32_t primCount; 36bf215546Sopenharmony_ci uint32_t firstIndex; 37bf215546Sopenharmony_ci int32_t baseVertex; 38bf215546Sopenharmony_ci uint32_t reservedMustBeZero; 39bf215546Sopenharmony_ci} DrawElementsIndirectCommand; 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic DrawElementsIndirectCommand 42bf215546Sopenharmony_ciread_indirect_elements(struct pipe_context *context, const struct pipe_draw_indirect_info *indirect) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci DrawElementsIndirectCommand ret; 45bf215546Sopenharmony_ci struct pipe_transfer *transfer = NULL; 46bf215546Sopenharmony_ci void *map = NULL; 47bf215546Sopenharmony_ci /* we only need the first 3 members */ 48bf215546Sopenharmony_ci unsigned read_size = 3 * sizeof(uint32_t); 49bf215546Sopenharmony_ci assert(indirect->buffer->width0 > 3 * sizeof(uint32_t)); 50bf215546Sopenharmony_ci map = pipe_buffer_map_range(context, indirect->buffer, 51bf215546Sopenharmony_ci indirect->offset, 52bf215546Sopenharmony_ci read_size, 53bf215546Sopenharmony_ci PIPE_MAP_READ, 54bf215546Sopenharmony_ci &transfer); 55bf215546Sopenharmony_ci assert(map); 56bf215546Sopenharmony_ci memcpy(&ret, map, read_size); 57bf215546Sopenharmony_ci pipe_buffer_unmap(context, transfer); 58bf215546Sopenharmony_ci return ret; 59bf215546Sopenharmony_ci} 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_civoid 62bf215546Sopenharmony_ciutil_translate_prim_restart_data(unsigned index_size, 63bf215546Sopenharmony_ci void *src_map, void *dst_map, 64bf215546Sopenharmony_ci unsigned count, unsigned restart_index) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci if (index_size == 1) { 67bf215546Sopenharmony_ci uint8_t *src = (uint8_t *) src_map; 68bf215546Sopenharmony_ci uint16_t *dst = (uint16_t *) dst_map; 69bf215546Sopenharmony_ci unsigned i; 70bf215546Sopenharmony_ci for (i = 0; i < count; i++) { 71bf215546Sopenharmony_ci dst[i] = (src[i] == restart_index) ? 0xffff : src[i]; 72bf215546Sopenharmony_ci } 73bf215546Sopenharmony_ci } 74bf215546Sopenharmony_ci else if (index_size == 2) { 75bf215546Sopenharmony_ci uint16_t *src = (uint16_t *) src_map; 76bf215546Sopenharmony_ci uint16_t *dst = (uint16_t *) dst_map; 77bf215546Sopenharmony_ci unsigned i; 78bf215546Sopenharmony_ci for (i = 0; i < count; i++) { 79bf215546Sopenharmony_ci dst[i] = (src[i] == restart_index) ? 0xffff : src[i]; 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci } 82bf215546Sopenharmony_ci else { 83bf215546Sopenharmony_ci uint32_t *src = (uint32_t *) src_map; 84bf215546Sopenharmony_ci uint32_t *dst = (uint32_t *) dst_map; 85bf215546Sopenharmony_ci unsigned i; 86bf215546Sopenharmony_ci assert(index_size == 4); 87bf215546Sopenharmony_ci for (i = 0; i < count; i++) { 88bf215546Sopenharmony_ci dst[i] = (src[i] == restart_index) ? 0xffffffff : src[i]; 89bf215546Sopenharmony_ci } 90bf215546Sopenharmony_ci } 91bf215546Sopenharmony_ci} 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci/** 94bf215546Sopenharmony_ci * Translate an index buffer for primitive restart. 95bf215546Sopenharmony_ci * Create a new index buffer which is a copy of the original index buffer 96bf215546Sopenharmony_ci * except that instances of 'restart_index' are converted to 0xffff or 97bf215546Sopenharmony_ci * 0xffffffff. 98bf215546Sopenharmony_ci * Also, index buffers using 1-byte indexes are converted to 2-byte indexes. 99bf215546Sopenharmony_ci */ 100bf215546Sopenharmony_cienum pipe_error 101bf215546Sopenharmony_ciutil_translate_prim_restart_ib(struct pipe_context *context, 102bf215546Sopenharmony_ci const struct pipe_draw_info *info, 103bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect_info, 104bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw, 105bf215546Sopenharmony_ci struct pipe_resource **dst_buffer) 106bf215546Sopenharmony_ci{ 107bf215546Sopenharmony_ci struct pipe_screen *screen = context->screen; 108bf215546Sopenharmony_ci struct pipe_transfer *src_transfer = NULL, *dst_transfer = NULL; 109bf215546Sopenharmony_ci void *src_map = NULL, *dst_map = NULL; 110bf215546Sopenharmony_ci const unsigned src_index_size = info->index_size; 111bf215546Sopenharmony_ci unsigned dst_index_size; 112bf215546Sopenharmony_ci DrawElementsIndirectCommand indirect; 113bf215546Sopenharmony_ci unsigned count = draw->count; 114bf215546Sopenharmony_ci unsigned start = draw->start; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci /* 1-byte indexes are converted to 2-byte indexes, 4-byte stays 4-byte */ 117bf215546Sopenharmony_ci dst_index_size = MAX2(2, info->index_size); 118bf215546Sopenharmony_ci assert(dst_index_size == 2 || dst_index_size == 4); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci if (indirect_info && indirect_info->buffer) { 121bf215546Sopenharmony_ci indirect = read_indirect_elements(context, indirect_info); 122bf215546Sopenharmony_ci count = indirect.count; 123bf215546Sopenharmony_ci start = indirect.firstIndex; 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci /* Create new index buffer */ 127bf215546Sopenharmony_ci *dst_buffer = pipe_buffer_create(screen, PIPE_BIND_INDEX_BUFFER, 128bf215546Sopenharmony_ci PIPE_USAGE_STREAM, 129bf215546Sopenharmony_ci count * dst_index_size); 130bf215546Sopenharmony_ci if (!*dst_buffer) 131bf215546Sopenharmony_ci goto error; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci /* Map new / dest index buffer */ 134bf215546Sopenharmony_ci dst_map = pipe_buffer_map(context, *dst_buffer, 135bf215546Sopenharmony_ci PIPE_MAP_WRITE, &dst_transfer); 136bf215546Sopenharmony_ci if (!dst_map) 137bf215546Sopenharmony_ci goto error; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci if (info->has_user_indices) 140bf215546Sopenharmony_ci src_map = (unsigned char*)info->index.user + start * src_index_size; 141bf215546Sopenharmony_ci else 142bf215546Sopenharmony_ci /* Map original / src index buffer */ 143bf215546Sopenharmony_ci src_map = pipe_buffer_map_range(context, info->index.resource, 144bf215546Sopenharmony_ci start * src_index_size, 145bf215546Sopenharmony_ci count * src_index_size, 146bf215546Sopenharmony_ci PIPE_MAP_READ, 147bf215546Sopenharmony_ci &src_transfer); 148bf215546Sopenharmony_ci if (!src_map) 149bf215546Sopenharmony_ci goto error; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci util_translate_prim_restart_data(src_index_size, src_map, dst_map, 152bf215546Sopenharmony_ci count, info->restart_index); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (src_transfer) 155bf215546Sopenharmony_ci pipe_buffer_unmap(context, src_transfer); 156bf215546Sopenharmony_ci pipe_buffer_unmap(context, dst_transfer); 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci return PIPE_OK; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_cierror: 161bf215546Sopenharmony_ci if (src_transfer) 162bf215546Sopenharmony_ci pipe_buffer_unmap(context, src_transfer); 163bf215546Sopenharmony_ci if (dst_transfer) 164bf215546Sopenharmony_ci pipe_buffer_unmap(context, dst_transfer); 165bf215546Sopenharmony_ci if (*dst_buffer) 166bf215546Sopenharmony_ci pipe_resource_reference(dst_buffer, NULL); 167bf215546Sopenharmony_ci return PIPE_ERROR_OUT_OF_MEMORY; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci/** Helper structs for util_draw_vbo_without_prim_restart() */ 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_cistruct range_info { 174bf215546Sopenharmony_ci struct pipe_draw_start_count_bias *draws; 175bf215546Sopenharmony_ci unsigned count, max; 176bf215546Sopenharmony_ci unsigned min_index, max_index; 177bf215546Sopenharmony_ci unsigned total_index_count; 178bf215546Sopenharmony_ci}; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci/** 182bf215546Sopenharmony_ci * Helper function for util_draw_vbo_without_prim_restart() 183bf215546Sopenharmony_ci * \return true for success, false if out of memory 184bf215546Sopenharmony_ci */ 185bf215546Sopenharmony_cistatic boolean 186bf215546Sopenharmony_ciadd_range(enum pipe_prim_type mode, struct range_info *info, unsigned start, unsigned count, unsigned index_bias) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci /* degenerate primitive: ignore */ 189bf215546Sopenharmony_ci if (!u_trim_pipe_prim(mode, (unsigned*)&count)) 190bf215546Sopenharmony_ci return TRUE; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci if (info->max == 0) { 193bf215546Sopenharmony_ci info->max = 10; 194bf215546Sopenharmony_ci info->draws = MALLOC(info->max * sizeof(struct pipe_draw_start_count_bias)); 195bf215546Sopenharmony_ci if (!info->draws) { 196bf215546Sopenharmony_ci return FALSE; 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci } 199bf215546Sopenharmony_ci else if (info->count == info->max) { 200bf215546Sopenharmony_ci /* grow the draws[] array */ 201bf215546Sopenharmony_ci info->draws = REALLOC(info->draws, 202bf215546Sopenharmony_ci info->max * sizeof(struct pipe_draw_start_count_bias), 203bf215546Sopenharmony_ci 2 * info->max * sizeof(struct pipe_draw_start_count_bias)); 204bf215546Sopenharmony_ci if (!info->draws) { 205bf215546Sopenharmony_ci return FALSE; 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci info->max *= 2; 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci info->min_index = MIN2(info->min_index, start); 211bf215546Sopenharmony_ci info->max_index = MAX2(info->max_index, start + count - 1); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci /* save the range */ 214bf215546Sopenharmony_ci info->draws[info->count].start = start; 215bf215546Sopenharmony_ci info->draws[info->count].count = count; 216bf215546Sopenharmony_ci info->draws[info->count].index_bias = index_bias; 217bf215546Sopenharmony_ci info->count++; 218bf215546Sopenharmony_ci info->total_index_count += count; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci return TRUE; 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_cistruct pipe_draw_start_count_bias * 224bf215546Sopenharmony_ciutil_prim_restart_convert_to_direct(const void *index_map, 225bf215546Sopenharmony_ci const struct pipe_draw_info *info, 226bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw, 227bf215546Sopenharmony_ci unsigned *num_draws, 228bf215546Sopenharmony_ci unsigned *min_index, 229bf215546Sopenharmony_ci unsigned *max_index, 230bf215546Sopenharmony_ci unsigned *total_index_count) 231bf215546Sopenharmony_ci{ 232bf215546Sopenharmony_ci struct range_info ranges = { .min_index = UINT32_MAX, 0 }; 233bf215546Sopenharmony_ci unsigned i, start, count; 234bf215546Sopenharmony_ci ranges.min_index = UINT32_MAX; 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci assert(info->index_size); 237bf215546Sopenharmony_ci assert(info->primitive_restart); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci#define SCAN_INDEXES(TYPE) \ 240bf215546Sopenharmony_ci for (i = 0; i <= draw->count; i++) { \ 241bf215546Sopenharmony_ci if (i == draw->count || \ 242bf215546Sopenharmony_ci ((const TYPE *) index_map)[i] == info->restart_index) { \ 243bf215546Sopenharmony_ci /* cut / restart */ \ 244bf215546Sopenharmony_ci if (count > 0) { \ 245bf215546Sopenharmony_ci if (!add_range(info->mode, &ranges, draw->start + start, count, draw->index_bias)) { \ 246bf215546Sopenharmony_ci return NULL; \ 247bf215546Sopenharmony_ci } \ 248bf215546Sopenharmony_ci } \ 249bf215546Sopenharmony_ci start = i + 1; \ 250bf215546Sopenharmony_ci count = 0; \ 251bf215546Sopenharmony_ci } \ 252bf215546Sopenharmony_ci else { \ 253bf215546Sopenharmony_ci count++; \ 254bf215546Sopenharmony_ci } \ 255bf215546Sopenharmony_ci } 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci start = 0; 258bf215546Sopenharmony_ci count = 0; 259bf215546Sopenharmony_ci switch (info->index_size) { 260bf215546Sopenharmony_ci case 1: 261bf215546Sopenharmony_ci SCAN_INDEXES(uint8_t); 262bf215546Sopenharmony_ci break; 263bf215546Sopenharmony_ci case 2: 264bf215546Sopenharmony_ci SCAN_INDEXES(uint16_t); 265bf215546Sopenharmony_ci break; 266bf215546Sopenharmony_ci case 4: 267bf215546Sopenharmony_ci SCAN_INDEXES(uint32_t); 268bf215546Sopenharmony_ci break; 269bf215546Sopenharmony_ci default: 270bf215546Sopenharmony_ci assert(!"Bad index size"); 271bf215546Sopenharmony_ci return NULL; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci *num_draws = ranges.count; 275bf215546Sopenharmony_ci *min_index = ranges.min_index; 276bf215546Sopenharmony_ci *max_index = ranges.max_index; 277bf215546Sopenharmony_ci *total_index_count = ranges.total_index_count; 278bf215546Sopenharmony_ci return ranges.draws; 279bf215546Sopenharmony_ci} 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci/** 282bf215546Sopenharmony_ci * Implement primitive restart by breaking an indexed primitive into 283bf215546Sopenharmony_ci * pieces which do not contain restart indexes. Each piece is then 284bf215546Sopenharmony_ci * drawn by calling pipe_context::draw_vbo(). 285bf215546Sopenharmony_ci * \return PIPE_OK if no error, an error code otherwise. 286bf215546Sopenharmony_ci */ 287bf215546Sopenharmony_cienum pipe_error 288bf215546Sopenharmony_ciutil_draw_vbo_without_prim_restart(struct pipe_context *context, 289bf215546Sopenharmony_ci const struct pipe_draw_info *info, 290bf215546Sopenharmony_ci unsigned drawid_offset, 291bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect_info, 292bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci const void *src_map; 295bf215546Sopenharmony_ci struct pipe_draw_info new_info = *info; 296bf215546Sopenharmony_ci struct pipe_draw_start_count_bias new_draw = *draw; 297bf215546Sopenharmony_ci struct pipe_transfer *src_transfer = NULL; 298bf215546Sopenharmony_ci DrawElementsIndirectCommand indirect; 299bf215546Sopenharmony_ci struct pipe_draw_start_count_bias *direct_draws; 300bf215546Sopenharmony_ci unsigned num_draws = 0; 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci assert(info->index_size); 303bf215546Sopenharmony_ci assert(info->primitive_restart); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci switch (info->index_size) { 306bf215546Sopenharmony_ci case 1: 307bf215546Sopenharmony_ci case 2: 308bf215546Sopenharmony_ci case 4: 309bf215546Sopenharmony_ci break; 310bf215546Sopenharmony_ci default: 311bf215546Sopenharmony_ci assert(!"Bad index size"); 312bf215546Sopenharmony_ci return PIPE_ERROR_BAD_INPUT; 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci if (indirect_info && indirect_info->buffer) { 316bf215546Sopenharmony_ci indirect = read_indirect_elements(context, indirect_info); 317bf215546Sopenharmony_ci new_draw.count = indirect.count; 318bf215546Sopenharmony_ci new_draw.start = indirect.firstIndex; 319bf215546Sopenharmony_ci new_info.instance_count = indirect.primCount; 320bf215546Sopenharmony_ci } 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci /* Get pointer to the index data */ 323bf215546Sopenharmony_ci if (!info->has_user_indices) { 324bf215546Sopenharmony_ci /* map the index buffer (only the range we need to scan) */ 325bf215546Sopenharmony_ci src_map = pipe_buffer_map_range(context, info->index.resource, 326bf215546Sopenharmony_ci new_draw.start * info->index_size, 327bf215546Sopenharmony_ci new_draw.count * info->index_size, 328bf215546Sopenharmony_ci PIPE_MAP_READ, 329bf215546Sopenharmony_ci &src_transfer); 330bf215546Sopenharmony_ci if (!src_map) { 331bf215546Sopenharmony_ci return PIPE_ERROR_OUT_OF_MEMORY; 332bf215546Sopenharmony_ci } 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci else { 335bf215546Sopenharmony_ci if (!info->index.user) { 336bf215546Sopenharmony_ci debug_printf("User-space index buffer is null!"); 337bf215546Sopenharmony_ci return PIPE_ERROR_BAD_INPUT; 338bf215546Sopenharmony_ci } 339bf215546Sopenharmony_ci src_map = (const uint8_t *) info->index.user 340bf215546Sopenharmony_ci + new_draw.start * info->index_size; 341bf215546Sopenharmony_ci } 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci unsigned total_index_count; 344bf215546Sopenharmony_ci direct_draws = util_prim_restart_convert_to_direct(src_map, &new_info, &new_draw, &num_draws, 345bf215546Sopenharmony_ci &new_info.min_index, &new_info.max_index, 346bf215546Sopenharmony_ci &total_index_count); 347bf215546Sopenharmony_ci /* unmap index buffer */ 348bf215546Sopenharmony_ci if (src_transfer) 349bf215546Sopenharmony_ci pipe_buffer_unmap(context, src_transfer); 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci new_info.primitive_restart = FALSE; 352bf215546Sopenharmony_ci new_info.index_bounds_valid = true; 353bf215546Sopenharmony_ci if (direct_draws) 354bf215546Sopenharmony_ci context->draw_vbo(context, &new_info, drawid_offset, NULL, direct_draws, num_draws); 355bf215546Sopenharmony_ci free(direct_draws); 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci return num_draws > 0 ? PIPE_OK : PIPE_ERROR_OUT_OF_MEMORY; 358bf215546Sopenharmony_ci} 359