Path: blob/21.2-virgl/src/gallium/auxiliary/draw/draw_pt_vsplit.c
4565 views
/*1* Mesa 3-D graphics library2*3* Copyright 2007-2008 VMware, Inc.4* Copyright (C) 2010 LunarG Inc.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the "Software"),8* to deal in the Software without restriction, including without limitation9* the rights to use, copy, modify, merge, publish, distribute, sublicense,10* and/or sell copies of the Software, and to permit persons to whom the11* Software is furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice shall be included14* in all copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING21* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER22* DEALINGS IN THE SOFTWARE.23*/2425#include "util/u_math.h"26#include "util/u_memory.h"2728#include "draw/draw_context.h"29#include "draw/draw_private.h"30#include "draw/draw_pt.h"3132#define SEGMENT_SIZE 102433#define MAP_SIZE 2563435/* The largest possible index within an index buffer */36#define MAX_ELT_IDX 0xffffffff3738struct vsplit_frontend {39struct draw_pt_front_end base;40struct draw_context *draw;4142unsigned prim;4344struct draw_pt_middle_end *middle;4546unsigned max_vertices;47ushort segment_size;4849/* buffers for splitting */50unsigned fetch_elts[SEGMENT_SIZE];51ushort draw_elts[SEGMENT_SIZE];52ushort identity_draw_elts[SEGMENT_SIZE];5354struct {55/* map a fetch element to a draw element */56unsigned fetches[MAP_SIZE];57ushort draws[MAP_SIZE];58boolean has_max_fetch;5960ushort num_fetch_elts;61ushort num_draw_elts;62} cache;63};646566static void67vsplit_clear_cache(struct vsplit_frontend *vsplit)68{69memset(vsplit->cache.fetches, 0xff, sizeof(vsplit->cache.fetches));70vsplit->cache.has_max_fetch = FALSE;71vsplit->cache.num_fetch_elts = 0;72vsplit->cache.num_draw_elts = 0;73}7475static void76vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned flags)77{78vsplit->middle->run(vsplit->middle,79vsplit->fetch_elts, vsplit->cache.num_fetch_elts,80vsplit->draw_elts, vsplit->cache.num_draw_elts, flags);81}8283/**84* Add a fetch element and add it to the draw elements.85*/86static inline void87vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch)88{89unsigned hash;9091hash = fetch % MAP_SIZE;9293/* If the value isn't in the cache or it's an overflow due to the94* element bias */95if (vsplit->cache.fetches[hash] != fetch) {96/* update cache */97vsplit->cache.fetches[hash] = fetch;98vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts;99100/* add fetch */101assert(vsplit->cache.num_fetch_elts < vsplit->segment_size);102vsplit->fetch_elts[vsplit->cache.num_fetch_elts++] = fetch;103}104105vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash];106}107108/**109* Returns the base index to the elements array.110* The value is checked for integer overflow (not sure it can happen?).111*/112static inline unsigned113vsplit_get_base_idx(unsigned start, unsigned fetch)114{115return draw_overflow_uadd(start, fetch, MAX_ELT_IDX);116}117118119static inline void120vsplit_add_cache_ubyte(struct vsplit_frontend *vsplit, const ubyte *elts,121unsigned start, unsigned fetch, int elt_bias)122{123struct draw_context *draw = vsplit->draw;124unsigned elt_idx;125elt_idx = vsplit_get_base_idx(start, fetch);126elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);127/* unlike the uint case this can only happen with elt_bias */128if (elt_bias && elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {129unsigned hash = elt_idx % MAP_SIZE;130vsplit->cache.fetches[hash] = 0;131vsplit->cache.has_max_fetch = TRUE;132}133vsplit_add_cache(vsplit, elt_idx);134}135136static inline void137vsplit_add_cache_ushort(struct vsplit_frontend *vsplit, const ushort *elts,138unsigned start, unsigned fetch, int elt_bias)139{140struct draw_context *draw = vsplit->draw;141unsigned elt_idx;142elt_idx = vsplit_get_base_idx(start, fetch);143elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);144/* unlike the uint case this can only happen with elt_bias */145if (elt_bias && elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {146unsigned hash = elt_idx % MAP_SIZE;147vsplit->cache.fetches[hash] = 0;148vsplit->cache.has_max_fetch = TRUE;149}150vsplit_add_cache(vsplit, elt_idx);151}152153154/**155* Add a fetch element and add it to the draw elements. The fetch element is156* in full range (uint).157*/158static inline void159vsplit_add_cache_uint(struct vsplit_frontend *vsplit, const uint *elts,160unsigned start, unsigned fetch, int elt_bias)161{162struct draw_context *draw = vsplit->draw;163unsigned elt_idx;164/*165* The final element index is just element index plus element bias.166*/167elt_idx = vsplit_get_base_idx(start, fetch);168elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);169/* Take care for DRAW_MAX_FETCH_IDX (since cache is initialized to -1). */170if (elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {171unsigned hash = elt_idx % MAP_SIZE;172/* force update - any value will do except DRAW_MAX_FETCH_IDX */173vsplit->cache.fetches[hash] = 0;174vsplit->cache.has_max_fetch = TRUE;175}176vsplit_add_cache(vsplit, elt_idx);177}178179180#define FUNC vsplit_run_linear181#include "draw_pt_vsplit_tmp.h"182183#define FUNC vsplit_run_ubyte184#define ELT_TYPE ubyte185#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_ubyte(vsplit,ib,start,fetch,bias)186#include "draw_pt_vsplit_tmp.h"187188#define FUNC vsplit_run_ushort189#define ELT_TYPE ushort190#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_ushort(vsplit,ib,start,fetch, bias)191#include "draw_pt_vsplit_tmp.h"192193#define FUNC vsplit_run_uint194#define ELT_TYPE uint195#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_uint(vsplit, ib, start, fetch, bias)196#include "draw_pt_vsplit_tmp.h"197198199static void vsplit_prepare(struct draw_pt_front_end *frontend,200unsigned in_prim,201struct draw_pt_middle_end *middle,202unsigned opt)203{204struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;205206switch (vsplit->draw->pt.user.eltSize) {207case 0:208vsplit->base.run = vsplit_run_linear;209break;210case 1:211vsplit->base.run = vsplit_run_ubyte;212break;213case 2:214vsplit->base.run = vsplit_run_ushort;215break;216case 4:217vsplit->base.run = vsplit_run_uint;218break;219default:220assert(0);221break;222}223224/* split only */225vsplit->prim = in_prim;226227vsplit->middle = middle;228middle->prepare(middle, vsplit->prim, opt, &vsplit->max_vertices);229230vsplit->segment_size = MIN2(SEGMENT_SIZE, vsplit->max_vertices);231}232233234static void vsplit_flush(struct draw_pt_front_end *frontend, unsigned flags)235{236struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;237238if (flags & DRAW_FLUSH_STATE_CHANGE) {239vsplit->middle->finish(vsplit->middle);240vsplit->middle = NULL;241}242}243244245static void vsplit_destroy(struct draw_pt_front_end *frontend)246{247FREE(frontend);248}249250251struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw)252{253struct vsplit_frontend *vsplit = CALLOC_STRUCT(vsplit_frontend);254ushort i;255256if (!vsplit)257return NULL;258259vsplit->base.prepare = vsplit_prepare;260vsplit->base.run = NULL;261vsplit->base.flush = vsplit_flush;262vsplit->base.destroy = vsplit_destroy;263vsplit->draw = draw;264265for (i = 0; i < SEGMENT_SIZE; i++)266vsplit->identity_draw_elts[i] = i;267268return &vsplit->base;269}270271272