• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
util_translate_prim_restart_ib(struct pipe_context * context,const struct pipe_draw_info * info,struct pipe_resource ** dst_buffer)41 util_translate_prim_restart_ib(struct pipe_context *context,
42                                const struct pipe_draw_info *info,
43                                struct pipe_resource **dst_buffer)
44 {
45    struct pipe_screen *screen = context->screen;
46    struct pipe_transfer *src_transfer = NULL, *dst_transfer = NULL;
47    void *src_map = NULL, *dst_map = NULL;
48    const unsigned src_index_size = info->index_size;
49    unsigned dst_index_size;
50 
51    /* 1-byte indexes are converted to 2-byte indexes, 4-byte stays 4-byte */
52    dst_index_size = MAX2(2, info->index_size);
53    assert(dst_index_size == 2 || dst_index_size == 4);
54 
55    /* no user buffers for now */
56    assert(!info->has_user_indices);
57 
58    /* Create new index buffer */
59    *dst_buffer = pipe_buffer_create(screen, PIPE_BIND_INDEX_BUFFER,
60                                     PIPE_USAGE_STREAM,
61                                     info->count * dst_index_size);
62    if (!*dst_buffer)
63       goto error;
64 
65    /* Map new / dest index buffer */
66    dst_map = pipe_buffer_map(context, *dst_buffer,
67                              PIPE_TRANSFER_WRITE, &dst_transfer);
68    if (!dst_map)
69       goto error;
70 
71    /* Map original / src index buffer */
72    src_map = pipe_buffer_map_range(context, info->index.resource,
73                                    info->start * src_index_size,
74                                    info->count * src_index_size,
75                                    PIPE_TRANSFER_READ,
76                                    &src_transfer);
77    if (!src_map)
78       goto error;
79 
80    if (src_index_size == 1 && dst_index_size == 2) {
81       uint8_t *src = (uint8_t *) src_map;
82       uint16_t *dst = (uint16_t *) dst_map;
83       unsigned i;
84       for (i = 0; i < info->count; i++) {
85          dst[i] = (src[i] == info->restart_index) ? 0xffff : src[i];
86       }
87    }
88    else if (src_index_size == 2 && dst_index_size == 2) {
89       uint16_t *src = (uint16_t *) src_map;
90       uint16_t *dst = (uint16_t *) dst_map;
91       unsigned i;
92       for (i = 0; i < info->count; i++) {
93          dst[i] = (src[i] == info->restart_index) ? 0xffff : src[i];
94       }
95    }
96    else {
97       uint32_t *src = (uint32_t *) src_map;
98       uint32_t *dst = (uint32_t *) dst_map;
99       unsigned i;
100       assert(src_index_size == 4);
101       assert(dst_index_size == 4);
102       for (i = 0; i < info->count; i++) {
103          dst[i] = (src[i] == info->restart_index) ? 0xffffffff : src[i];
104       }
105    }
106 
107    pipe_buffer_unmap(context, src_transfer);
108    pipe_buffer_unmap(context, dst_transfer);
109 
110    return PIPE_OK;
111 
112 error:
113    if (src_transfer)
114       pipe_buffer_unmap(context, src_transfer);
115    if (dst_transfer)
116       pipe_buffer_unmap(context, dst_transfer);
117    if (*dst_buffer)
118       pipe_resource_reference(dst_buffer, NULL);
119    return PIPE_ERROR_OUT_OF_MEMORY;
120 }
121 
122 
123 /** Helper structs for util_draw_vbo_without_prim_restart() */
124 
125 struct range {
126    unsigned start, count;
127 };
128 
129 struct range_info {
130    struct range *ranges;
131    unsigned count, max;
132 };
133 
134 
135 /**
136  * Helper function for util_draw_vbo_without_prim_restart()
137  * \return true for success, false if out of memory
138  */
139 static boolean
add_range(struct range_info * info,unsigned start,unsigned count)140 add_range(struct range_info *info, unsigned start, unsigned count)
141 {
142    if (info->max == 0) {
143       info->max = 10;
144       info->ranges = MALLOC(info->max * sizeof(struct range));
145       if (!info->ranges) {
146          return FALSE;
147       }
148    }
149    else if (info->count == info->max) {
150       /* grow the ranges[] array */
151       info->ranges = REALLOC(info->ranges,
152                              info->max * sizeof(struct range),
153                              2 * info->max * sizeof(struct range));
154       if (!info->ranges) {
155          return FALSE;
156       }
157 
158       info->max *= 2;
159    }
160 
161    /* save the range */
162    info->ranges[info->count].start = start;
163    info->ranges[info->count].count = count;
164    info->count++;
165 
166    return TRUE;
167 }
168 
169 
170 /**
171  * Implement primitive restart by breaking an indexed primitive into
172  * pieces which do not contain restart indexes.  Each piece is then
173  * drawn by calling pipe_context::draw_vbo().
174  * \return PIPE_OK if no error, an error code otherwise.
175  */
176 enum pipe_error
util_draw_vbo_without_prim_restart(struct pipe_context * context,const struct pipe_draw_info * info)177 util_draw_vbo_without_prim_restart(struct pipe_context *context,
178                                    const struct pipe_draw_info *info)
179 {
180    const void *src_map;
181    struct range_info ranges = {0};
182    struct pipe_draw_info new_info;
183    struct pipe_transfer *src_transfer = NULL;
184    unsigned i, start, count;
185 
186    assert(info->index_size);
187    assert(info->primitive_restart);
188 
189    /* Get pointer to the index data */
190    if (!info->has_user_indices) {
191       /* map the index buffer (only the range we need to scan) */
192       src_map = pipe_buffer_map_range(context, info->index.resource,
193                                       info->start * info->index_size,
194                                       info->count * info->index_size,
195                                       PIPE_TRANSFER_READ,
196                                       &src_transfer);
197       if (!src_map) {
198          return PIPE_ERROR_OUT_OF_MEMORY;
199       }
200    }
201    else {
202       if (!info->index.user) {
203          debug_printf("User-space index buffer is null!");
204          return PIPE_ERROR_BAD_INPUT;
205       }
206       src_map = (const uint8_t *) info->index.user
207          + info->start * info->index_size;
208    }
209 
210 #define SCAN_INDEXES(TYPE) \
211    for (i = 0; i <= info->count; i++) { \
212       if (i == info->count || \
213           ((const TYPE *) src_map)[i] == info->restart_index) { \
214          /* cut / restart */ \
215          if (count > 0) { \
216             if (!add_range(&ranges, info->start + start, count)) { \
217                if (src_transfer) \
218                   pipe_buffer_unmap(context, src_transfer); \
219                return PIPE_ERROR_OUT_OF_MEMORY; \
220             } \
221          } \
222          start = i + 1; \
223          count = 0; \
224       } \
225       else { \
226          count++; \
227       } \
228    }
229 
230    start = 0;
231    count = 0;
232    switch (info->index_size) {
233    case 1:
234       SCAN_INDEXES(uint8_t);
235       break;
236    case 2:
237       SCAN_INDEXES(uint16_t);
238       break;
239    case 4:
240       SCAN_INDEXES(uint32_t);
241       break;
242    default:
243       assert(!"Bad index size");
244       return PIPE_ERROR_BAD_INPUT;
245    }
246 
247    /* unmap index buffer */
248    if (src_transfer)
249       pipe_buffer_unmap(context, src_transfer);
250 
251    /* draw ranges between the restart indexes */
252    new_info = *info;
253    new_info.primitive_restart = FALSE;
254    for (i = 0; i < ranges.count; i++) {
255       new_info.start = ranges.ranges[i].start;
256       new_info.count = ranges.ranges[i].count;
257       context->draw_vbo(context, &new_info);
258    }
259 
260    FREE(ranges.ranges);
261 
262    return PIPE_OK;
263 }
264