draw: clear the draw buffers in draw
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_vsplit.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "util/u_math.h"
27 #include "util/u_memory.h"
28
29 #include "draw/draw_context.h"
30 #include "draw/draw_private.h"
31 #include "draw/draw_pt.h"
32
33 #define SEGMENT_SIZE 1024
34 #define MAP_SIZE 256
35
36 struct vsplit_frontend {
37 struct draw_pt_front_end base;
38 struct draw_context *draw;
39
40 unsigned prim;
41
42 struct draw_pt_middle_end *middle;
43
44 unsigned max_vertices;
45 ushort segment_size;
46
47 /* buffers for splitting */
48 unsigned fetch_elts[SEGMENT_SIZE];
49 ushort draw_elts[SEGMENT_SIZE];
50 ushort identity_draw_elts[SEGMENT_SIZE];
51
52 struct {
53 /* map a fetch element to a draw element */
54 unsigned fetches[MAP_SIZE];
55 ushort draws[MAP_SIZE];
56 boolean has_max_fetch;
57
58 ushort num_fetch_elts;
59 ushort num_draw_elts;
60 } cache;
61 };
62
63
64 static void
65 vsplit_clear_cache(struct vsplit_frontend *vsplit)
66 {
67 memset(vsplit->cache.fetches, 0xff, sizeof(vsplit->cache.fetches));
68 vsplit->cache.has_max_fetch = FALSE;
69 vsplit->cache.num_fetch_elts = 0;
70 vsplit->cache.num_draw_elts = 0;
71 }
72
73 static void
74 vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned flags)
75 {
76 vsplit->middle->run(vsplit->middle,
77 vsplit->fetch_elts, vsplit->cache.num_fetch_elts,
78 vsplit->draw_elts, vsplit->cache.num_draw_elts, flags);
79 }
80
81 /**
82 * Add a fetch element and add it to the draw elements.
83 */
84 static INLINE void
85 vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch)
86 {
87 struct draw_context *draw = vsplit->draw;
88 unsigned hash;
89
90 fetch = MIN2(fetch, draw->pt.max_index);
91
92 hash = fetch % MAP_SIZE;
93
94 if (vsplit->cache.fetches[hash] != fetch) {
95 /* update cache */
96 vsplit->cache.fetches[hash] = fetch;
97 vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts;
98
99 /* add fetch */
100 assert(vsplit->cache.num_fetch_elts < vsplit->segment_size);
101 vsplit->fetch_elts[vsplit->cache.num_fetch_elts++] = fetch;
102 }
103
104 vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash];
105 }
106
107
108 /**
109 * Add a fetch element and add it to the draw elements. The fetch element is
110 * in full range (uint).
111 */
112 static INLINE void
113 vsplit_add_cache_uint(struct vsplit_frontend *vsplit, unsigned fetch)
114 {
115 /* special care for 0xffffffff */
116 if (fetch == 0xffffffff && !vsplit->cache.has_max_fetch) {
117 unsigned hash = fetch % MAP_SIZE;
118 vsplit->cache.fetches[hash] = fetch - 1; /* force update */
119 vsplit->cache.has_max_fetch = TRUE;
120 }
121
122 vsplit_add_cache(vsplit, fetch);
123 }
124
125
126 #define FUNC vsplit_run_linear
127 #include "draw_pt_vsplit_tmp.h"
128
129 #define FUNC vsplit_run_ubyte
130 #define ELT_TYPE ubyte
131 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch)
132 #include "draw_pt_vsplit_tmp.h"
133
134 #define FUNC vsplit_run_ushort
135 #define ELT_TYPE ushort
136 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch)
137 #include "draw_pt_vsplit_tmp.h"
138
139 #define FUNC vsplit_run_uint
140 #define ELT_TYPE uint
141 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache_uint(vsplit, fetch)
142 #include "draw_pt_vsplit_tmp.h"
143
144
145 static void vsplit_prepare(struct draw_pt_front_end *frontend,
146 unsigned in_prim,
147 struct draw_pt_middle_end *middle,
148 unsigned opt)
149 {
150 struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
151
152 switch (vsplit->draw->pt.user.eltSize) {
153 case 0:
154 vsplit->base.run = vsplit_run_linear;
155 break;
156 case 1:
157 vsplit->base.run = vsplit_run_ubyte;
158 break;
159 case 2:
160 vsplit->base.run = vsplit_run_ushort;
161 break;
162 case 4:
163 vsplit->base.run = vsplit_run_uint;
164 break;
165 default:
166 assert(0);
167 break;
168 }
169
170 /* split only */
171 vsplit->prim = in_prim;
172
173 vsplit->middle = middle;
174 middle->prepare(middle, vsplit->prim, opt, &vsplit->max_vertices);
175
176 vsplit->segment_size = MIN2(SEGMENT_SIZE, vsplit->max_vertices);
177 }
178
179
180 static void vsplit_flush(struct draw_pt_front_end *frontend, unsigned flags)
181 {
182 struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
183
184 if (flags & DRAW_FLUSH_STATE_CHANGE) {
185 vsplit->middle->finish(vsplit->middle);
186 vsplit->middle = NULL;
187 }
188 }
189
190
191 static void vsplit_destroy(struct draw_pt_front_end *frontend)
192 {
193 FREE(frontend);
194 }
195
196
197 struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw)
198 {
199 struct vsplit_frontend *vsplit = CALLOC_STRUCT(vsplit_frontend);
200 ushort i;
201
202 if (!vsplit)
203 return NULL;
204
205 vsplit->base.prepare = vsplit_prepare;
206 vsplit->base.run = NULL;
207 vsplit->base.flush = vsplit_flush;
208 vsplit->base.destroy = vsplit_destroy;
209 vsplit->draw = draw;
210
211 for (i = 0; i < SEGMENT_SIZE; i++)
212 vsplit->identity_draw_elts[i] = i;
213
214 return &vsplit->base;
215 }