diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/auxiliary/draw/draw_private.h | 24 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt.c | 9 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt_vsplit.c | 115 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h | 54 |
4 files changed, 159 insertions, 43 deletions
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index f42cded118a..d8cd8ebdb64 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -55,6 +55,10 @@ struct gallivm_state; /** Sum of frustum planes and user-defined planes */ #define DRAW_TOTAL_CLIP_PLANES (6 + PIPE_MAX_CLIP_PLANES) +/** + * The largest possible index of a vertex that can be fetched. + */ +#define DRAW_MAX_FETCH_IDX 0xffffffff struct pipe_context; struct draw_vertex_shader; @@ -468,14 +472,13 @@ void draw_stats_clipper_primitives(struct draw_context *draw, const struct draw_prim_info *prim_info); - /** * Return index i from the index buffer. * If the index buffer would overflow we return the - * index of the first element in the vb. + * maximum possible index. */ #define DRAW_GET_IDX(_elts, _i) \ - (((_i) >= draw->pt.user.eltMax) ? 0 : (_elts)[_i]) + (((_i) >= draw->pt.user.eltMax) ? DRAW_MAX_FETCH_IDX : (_elts)[_i]) /** * Return index of the given viewport clamping it @@ -487,5 +490,20 @@ draw_clamp_viewport_idx(int idx) return ((PIPE_MAX_VIEWPORTS > idx || idx < 0) ? idx : 0); } +/** + * Adds two unsigned integers and if the addition + * overflows then it returns the value from + * from the overflow_value variable. + */ +static INLINE unsigned +draw_overflow_uadd(unsigned a, unsigned b, + unsigned overflow_value) +{ + unsigned res = a + b; + if (res < a || res < b) { + res = overflow_value; + } + return res; +} #endif /* DRAW_PRIVATE_H */ diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index e89ccd25401..d2fe0025bfc 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -345,7 +345,8 @@ draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count) /** Helper code for below */ #define PRIM_RESTART_LOOP(elements) \ do { \ - for (i = start; i < end; i++) { \ + for (j = 0; j < count; j++) { \ + i = draw_overflow_uadd(start, j, MAX_LOOP_IDX); \ if (i < elt_max && elements[i] == info->restart_index) { \ if (cur_count > 0) { \ /* draw elts up to prev pos */ \ @@ -377,9 +378,11 @@ draw_pt_arrays_restart(struct draw_context *draw, const unsigned prim = info->mode; const unsigned start = info->start; const unsigned count = info->count; - const unsigned end = start + count; const unsigned elt_max = draw->pt.user.eltMax; - unsigned i, cur_start, cur_count; + unsigned i, j, cur_start, cur_count; + /* The largest index within a loop using the i variable as the index. + * Used for overflow detection */ + const unsigned MAX_LOOP_IDX = 0xffffffff; assert(info->primitive_restart); diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit.c b/src/gallium/auxiliary/draw/draw_pt_vsplit.c index 114c89c1e9c..625505d1efd 100644 --- a/src/gallium/auxiliary/draw/draw_pt_vsplit.c +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit.c @@ -33,6 +33,9 @@ #define SEGMENT_SIZE 1024 #define MAP_SIZE 256 +/* The largest possible index withing an index buffer */ +#define MAX_ELT_IDX 0xffffffff + struct vsplit_frontend { struct draw_pt_front_end base; struct draw_context *draw; @@ -82,16 +85,15 @@ vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned flags) * Add a fetch element and add it to the draw elements. */ static INLINE void -vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch) +vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch, unsigned ofbias) { - struct draw_context *draw = vsplit->draw; unsigned hash; - fetch = MIN2(fetch, draw->pt.max_index); - hash = fetch % MAP_SIZE; - if (vsplit->cache.fetches[hash] != fetch) { + /* If the value isn't in the cache of it's an overflow due to the + * element bias */ + if (vsplit->cache.fetches[hash] != fetch || ofbias) { /* update cache */ vsplit->cache.fetches[hash] = fetch; vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts; @@ -104,22 +106,109 @@ vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch) vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash]; } +/** + * Returns the base index to the elements array. + * The value is checked for overflows (both integer overflows + * and the elements array overflow). + */ +static INLINE unsigned +vsplit_get_base_idx(struct vsplit_frontend *vsplit, + unsigned start, unsigned fetch, unsigned *ofbit) +{ + struct draw_context *draw = vsplit->draw; + unsigned elt_idx = draw_overflow_uadd(start, fetch, MAX_ELT_IDX); + if (ofbit) + *ofbit = 0; + + /* Overflown indices need to wrap to the first element + * in the index buffer */ + if (elt_idx >= draw->pt.user.eltMax) { + if (ofbit) + *ofbit = 1; + elt_idx = 0; + } + + return elt_idx; +} + +/** + * Returns the element index adjust for the element bias. + * The final element index is created from the actual element + * index, plus the element bias, clamped to maximum elememt + * index if that addition overflows. + */ +static INLINE unsigned +vsplit_get_bias_idx(struct vsplit_frontend *vsplit, + int idx, int bias, unsigned *ofbias) +{ + int res = idx + bias; + + if (ofbias) + *ofbias = 0; + + if (idx > 0 && bias > 0) { + if (res < idx || res < bias) { + res = DRAW_MAX_FETCH_IDX; + if (ofbias) + *ofbias = 1; + } + } else if (idx < 0 && bias < 0) { + if (res > idx || res > bias) { + res = DRAW_MAX_FETCH_IDX; + if (ofbias) + *ofbias = 1; + } + } + + return res; +} + +#define VSPLIT_CREATE_IDX(elts, start, fetch, elt_bias) \ + unsigned elt_idx; \ + unsigned ofbit; \ + unsigned ofbias; \ + elt_idx = vsplit_get_base_idx(vsplit, start, fetch, &ofbit); \ + elt_idx = vsplit_get_bias_idx(vsplit, ofbit ? 0 : DRAW_GET_IDX(elts, elt_idx), elt_bias, &ofbias) + +static INLINE void +vsplit_add_cache_ubyte(struct vsplit_frontend *vsplit, const ubyte *elts, + unsigned start, unsigned fetch, int elt_bias) +{ + struct draw_context *draw = vsplit->draw; + VSPLIT_CREATE_IDX(elts, start, fetch, elt_bias); + vsplit_add_cache(vsplit, elt_idx, ofbias); +} + +static INLINE void +vsplit_add_cache_ushort(struct vsplit_frontend *vsplit, const ushort *elts, + unsigned start, unsigned fetch, int elt_bias) +{ + struct draw_context *draw = vsplit->draw; + VSPLIT_CREATE_IDX(elts, start, fetch, elt_bias); + vsplit_add_cache(vsplit, elt_idx, ofbias); +} + /** * Add a fetch element and add it to the draw elements. The fetch element is * in full range (uint). */ static INLINE void -vsplit_add_cache_uint(struct vsplit_frontend *vsplit, unsigned fetch) +vsplit_add_cache_uint(struct vsplit_frontend *vsplit, const uint *elts, + unsigned start, unsigned fetch, int elt_bias) { - /* special care for 0xffffffff */ - if (fetch == 0xffffffff && !vsplit->cache.has_max_fetch) { + struct draw_context *draw = vsplit->draw; + unsigned raw_elem_idx = start + fetch + elt_bias; + VSPLIT_CREATE_IDX(elts, start, fetch, elt_bias); + + /* special care for DRAW_MAX_FETCH_IDX */ + if (raw_elem_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) { unsigned hash = fetch % MAP_SIZE; - vsplit->cache.fetches[hash] = fetch - 1; /* force update */ + vsplit->cache.fetches[hash] = raw_elem_idx - 1; /* force update */ vsplit->cache.has_max_fetch = TRUE; } - vsplit_add_cache(vsplit, fetch); + vsplit_add_cache(vsplit, elt_idx, ofbias); } @@ -128,17 +217,17 @@ vsplit_add_cache_uint(struct vsplit_frontend *vsplit, unsigned fetch) #define FUNC vsplit_run_ubyte #define ELT_TYPE ubyte -#define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch) +#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_ubyte(vsplit,ib,start,fetch,bias) #include "draw_pt_vsplit_tmp.h" #define FUNC vsplit_run_ushort #define ELT_TYPE ushort -#define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch) +#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_ushort(vsplit,ib,start,fetch, bias) #include "draw_pt_vsplit_tmp.h" #define FUNC vsplit_run_uint #define ELT_TYPE uint -#define ADD_CACHE(vsplit, fetch) vsplit_add_cache_uint(vsplit, fetch) +#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_uint(vsplit, ib, start, fetch, bias) #include "draw_pt_vsplit_tmp.h" diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h b/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h index 34c210c8a43..5d72ac60924 100644 --- a/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h @@ -47,13 +47,20 @@ CONCAT(vsplit_primitive_, ELT_TYPE)(struct vsplit_frontend *vsplit, const unsigned start = istart; const unsigned end = istart + icount; + /* If the index buffer overflows we'll need to run + * through the normal paths */ + if (start >= draw->pt.user.eltMax || + end > draw->pt.user.eltMax || + end < istart || end < icount) + return FALSE; + /* use the ib directly */ if (min_index == 0 && sizeof(ib[0]) == sizeof(draw_elts[0])) { if (icount > vsplit->max_vertices) return FALSE; - for (i = start; i < end; i++) { - ELT_TYPE idx = DRAW_GET_IDX(ib, i); + for (i = 0; i < icount; i++) { + ELT_TYPE idx = DRAW_GET_IDX(ib, start + i); if (idx < min_index || idx > max_index) { debug_printf("warning: index out of range\n"); } @@ -82,25 +89,29 @@ CONCAT(vsplit_primitive_, ELT_TYPE)(struct vsplit_frontend *vsplit, fetch_start = min_index + elt_bias; fetch_count = max_index - min_index + 1; + /* Check for overflow in the fetch_start */ + if (fetch_start < min_index || fetch_start < elt_bias) + return FALSE; + if (!draw_elts) { if (min_index == 0) { - for (i = start; i < end; i++) { - ELT_TYPE idx = DRAW_GET_IDX(ib, i); + for (i = 0; i < icount; i++) { + ELT_TYPE idx = DRAW_GET_IDX(ib, i + start); if (idx < min_index || idx > max_index) { debug_printf("warning: index out of range\n"); } - vsplit->draw_elts[i - start] = (ushort) idx; + vsplit->draw_elts[i] = (ushort) idx; } } else { - for (i = start; i < end; i++) { - ELT_TYPE idx = DRAW_GET_IDX(ib, i); + for (i = 0; i < icount; i++) { + ELT_TYPE idx = DRAW_GET_IDX(ib, i + start); if (idx < min_index || idx > max_index) { debug_printf("warning: index out of range\n"); } - vsplit->draw_elts[i - start] = (ushort) (idx - min_index); + vsplit->draw_elts[i] = (ushort) (idx - min_index); } } @@ -137,41 +148,36 @@ CONCAT(vsplit_segment_cache_, ELT_TYPE)(struct vsplit_frontend *vsplit, spoken = !!spoken; if (ibias == 0) { if (spoken) - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, ispoken)); + ADD_CACHE(vsplit, ib, 0, ispoken, 0); - for (i = spoken; i < icount; i++) - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, istart + i)); + for (i = spoken; i < icount; i++) { + ADD_CACHE(vsplit, ib, istart, i, 0); + } if (close) - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, iclose)); + ADD_CACHE(vsplit, ib, 0, iclose, 0); } else if (ibias > 0) { if (spoken) - ADD_CACHE(vsplit, (uint) DRAW_GET_IDX(ib, ispoken) + ibias); + ADD_CACHE(vsplit, ib, 0, ispoken, ibias); for (i = spoken; i < icount; i++) - ADD_CACHE(vsplit, (uint) DRAW_GET_IDX(ib, istart + i) + ibias); + ADD_CACHE(vsplit, ib, istart, i, ibias); if (close) - ADD_CACHE(vsplit, (uint) DRAW_GET_IDX(ib, iclose) + ibias); + ADD_CACHE(vsplit, ib, 0, iclose, ibias); } else { if (spoken) { - if ((int) ib[ispoken] < -ibias) - return; - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, ispoken) + ibias); + ADD_CACHE(vsplit, ib, 0, ispoken, ibias); } for (i = spoken; i < icount; i++) { - if ((int) DRAW_GET_IDX(ib, istart + i) < -ibias) - return; - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, istart + i) + ibias); + ADD_CACHE(vsplit, ib, istart, i, ibias); } if (close) { - if ((int) DRAW_GET_IDX(ib, iclose) < -ibias) - return; - ADD_CACHE(vsplit, DRAW_GET_IDX(ib, iclose) + ibias); + ADD_CACHE(vsplit, ib, 0, iclose, ibias); } } |