1 /* 2 * Copyright 2014 VMware, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27 28 #include "u_inlines.h" 29 #include "u_memory.h" 30 #include "u_prim_restart.h" 31 32 33 /** 34 * Translate an index buffer for primitive restart. 35 * Create a new index buffer which is a copy of the original index buffer 36 * except that instances of 'restart_index' are converted to 0xffff or 37 * 0xffffffff. 38 * Also, index buffers using 1-byte indexes are converted to 2-byte indexes. 39 */ 40 enum pipe_error 41 util_translate_prim_restart_ib(struct pipe_context *context, 42 struct pipe_index_buffer *src_buffer, 43 struct pipe_resource **dst_buffer, 44 unsigned num_indexes, 45 unsigned restart_index) 46 { 47 struct pipe_screen *screen = context->screen; 48 struct pipe_transfer *src_transfer = NULL, *dst_transfer = NULL; 49 void *src_map = NULL, *dst_map = NULL; 50 const unsigned src_index_size = src_buffer->index_size; 51 unsigned dst_index_size; 52 53 /* 1-byte indexes are converted to 2-byte indexes, 4-byte stays 4-byte */ 54 dst_index_size = MAX2(2, src_buffer->index_size); 55 assert(dst_index_size == 2 || dst_index_size == 4); 56 57 /* no user buffers for now */ 58 assert(src_buffer->user_buffer == NULL); 59 60 /* Create new index buffer */ 61 *dst_buffer = pipe_buffer_create(screen, PIPE_BIND_INDEX_BUFFER, 62 PIPE_USAGE_STREAM, 63 num_indexes * dst_index_size); 64 if (!*dst_buffer) 65 goto error; 66 67 /* Map new / dest index buffer */ 68 dst_map = pipe_buffer_map(context, *dst_buffer, 69 PIPE_TRANSFER_WRITE, &dst_transfer); 70 if (!dst_map) 71 goto error; 72 73 /* Map original / src index buffer */ 74 src_map = pipe_buffer_map_range(context, src_buffer->buffer, 75 src_buffer->offset, 76 num_indexes * src_index_size, 77 PIPE_TRANSFER_READ, 78 &src_transfer); 79 if (!src_map) 80 goto error; 81 82 if (src_index_size == 1 && dst_index_size == 2) { 83 uint8_t *src = (uint8_t *) src_map; 84 uint16_t *dst = (uint16_t *) dst_map; 85 unsigned i; 86 for (i = 0; i < num_indexes; i++) { 87 dst[i] = (src[i] == restart_index) ? 0xffff : src[i]; 88 } 89 } 90 else if (src_index_size == 2 && dst_index_size == 2) { 91 uint16_t *src = (uint16_t *) src_map; 92 uint16_t *dst = (uint16_t *) dst_map; 93 unsigned i; 94 for (i = 0; i < num_indexes; i++) { 95 dst[i] = (src[i] == restart_index) ? 0xffff : src[i]; 96 } 97 } 98 else { 99 uint32_t *src = (uint32_t *) src_map; 100 uint32_t *dst = (uint32_t *) dst_map; 101 unsigned i; 102 assert(src_index_size == 4); 103 assert(dst_index_size == 4); 104 for (i = 0; i < num_indexes; i++) { 105 dst[i] = (src[i] == restart_index) ? 0xffffffff : src[i]; 106 } 107 } 108 109 pipe_buffer_unmap(context, src_transfer); 110 pipe_buffer_unmap(context, dst_transfer); 111 112 return PIPE_OK; 113 114 error: 115 if (src_transfer) 116 pipe_buffer_unmap(context, src_transfer); 117 if (dst_transfer) 118 pipe_buffer_unmap(context, dst_transfer); 119 if (*dst_buffer) 120 screen->resource_destroy(screen, *dst_buffer); 121 return PIPE_ERROR_OUT_OF_MEMORY; 122 } 123 124 125 /** Helper structs for util_draw_vbo_without_prim_restart() */ 126 127 struct range { 128 unsigned start, count; 129 }; 130 131 struct range_info { 132 struct range *ranges; 133 unsigned count, max; 134 }; 135 136 137 /** 138 * Helper function for util_draw_vbo_without_prim_restart() 139 * \return true for success, false if out of memory 140 */ 141 static boolean 142 add_range(struct range_info *info, unsigned start, unsigned count) 143 { 144 if (info->max == 0) { 145 info->max = 10; 146 info->ranges = MALLOC(info->max * sizeof(struct range)); 147 if (!info->ranges) { 148 return FALSE; 149 } 150 } 151 else if (info->count == info->max) { 152 /* grow the ranges[] array */ 153 info->ranges = REALLOC(info->ranges, 154 info->max * sizeof(struct range), 155 2 * info->max * sizeof(struct range)); 156 if (!info->ranges) { 157 return FALSE; 158 } 159 160 info->max *= 2; 161 } 162 163 /* save the range */ 164 info->ranges[info->count].start = start; 165 info->ranges[info->count].count = count; 166 info->count++; 167 168 return TRUE; 169 } 170 171 172 /** 173 * Implement primitive restart by breaking an indexed primitive into 174 * pieces which do not contain restart indexes. Each piece is then 175 * drawn by calling pipe_context::draw_vbo(). 176 * \return PIPE_OK if no error, an error code otherwise. 177 */ 178 enum pipe_error 179 util_draw_vbo_without_prim_restart(struct pipe_context *context, 180 const struct pipe_index_buffer *ib, 181 const struct pipe_draw_info *info) 182 { 183 const void *src_map; 184 struct range_info ranges = {0}; 185 struct pipe_draw_info new_info; 186 struct pipe_transfer *src_transfer = NULL; 187 unsigned i, start, count; 188 189 assert(info->indexed); 190 assert(info->primitive_restart); 191 192 /* Get pointer to the index data */ 193 if (ib->buffer) { 194 /* map the index buffer (only the range we need to scan) */ 195 src_map = pipe_buffer_map_range(context, ib->buffer, 196 ib->offset + info->start * ib->index_size, 197 info->count * ib->index_size, 198 PIPE_TRANSFER_READ, 199 &src_transfer); 200 if (!src_map) { 201 return PIPE_ERROR_OUT_OF_MEMORY; 202 } 203 } 204 else { 205 if (!ib->user_buffer) { 206 debug_printf("User-space index buffer is null!"); 207 return PIPE_ERROR_BAD_INPUT; 208 } 209 src_map = (const uint8_t *) ib->user_buffer 210 + ib->offset 211 + info->start * ib->index_size; 212 } 213 214 #define SCAN_INDEXES(TYPE) \ 215 for (i = 0; i <= info->count; i++) { \ 216 if (i == info->count || \ 217 ((const TYPE *) src_map)[i] == info->restart_index) { \ 218 /* cut / restart */ \ 219 if (count > 0) { \ 220 if (!add_range(&ranges, info->start + start, count)) { \ 221 if (src_transfer) \ 222 pipe_buffer_unmap(context, src_transfer); \ 223 return PIPE_ERROR_OUT_OF_MEMORY; \ 224 } \ 225 } \ 226 start = i + 1; \ 227 count = 0; \ 228 } \ 229 else { \ 230 count++; \ 231 } \ 232 } 233 234 start = info->start; 235 count = 0; 236 switch (ib->index_size) { 237 case 1: 238 SCAN_INDEXES(uint8_t); 239 break; 240 case 2: 241 SCAN_INDEXES(uint16_t); 242 break; 243 case 4: 244 SCAN_INDEXES(uint32_t); 245 break; 246 default: 247 assert(!"Bad index size"); 248 return PIPE_ERROR_BAD_INPUT; 249 } 250 251 /* unmap index buffer */ 252 if (src_transfer) 253 pipe_buffer_unmap(context, src_transfer); 254 255 /* draw ranges between the restart indexes */ 256 new_info = *info; 257 new_info.primitive_restart = FALSE; 258 for (i = 0; i < ranges.count; i++) { 259 new_info.start = ranges.ranges[i].start; 260 new_info.count = ranges.ranges[i].count; 261 context->draw_vbo(context, &new_info); 262 } 263 264 FREE(ranges.ranges); 265 266 return PIPE_OK; 267 } 268