Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the |
||
8 | * "Software"), to deal in the Software without restriction, including |
||
9 | * without limitation the rights to use, copy, modify, merge, publish, |
||
10 | * distribute, sub license, and/or sell copies of the Software, and to |
||
11 | * permit persons to whom the Software is furnished to do so, subject to |
||
12 | * the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice (including the |
||
15 | * next paragraph) shall be included in all copies or substantial portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
21 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | /* Authors: Zack Rusin |
||
29 | */ |
||
30 | |||
31 | #include "util/u_debug.h" |
||
32 | |||
33 | #include "util/u_memory.h" |
||
34 | |||
35 | #include "cso_cache.h" |
||
36 | #include "cso_hash.h" |
||
37 | |||
38 | |||
39 | struct cso_cache { |
||
40 | struct cso_hash *hashes[CSO_CACHE_MAX]; |
||
41 | int max_size; |
||
42 | |||
43 | cso_sanitize_callback sanitize_cb; |
||
44 | void *sanitize_data; |
||
45 | }; |
||
46 | |||
47 | #if 1 |
||
48 | static unsigned hash_key(const void *key, unsigned key_size) |
||
49 | { |
||
50 | unsigned *ikey = (unsigned *)key; |
||
51 | unsigned hash = 0, i; |
||
52 | |||
53 | assert(key_size % 4 == 0); |
||
54 | |||
55 | /* I'm sure this can be improved on: |
||
56 | */ |
||
57 | for (i = 0; i < key_size/4; i++) |
||
58 | hash ^= ikey[i]; |
||
59 | |||
60 | return hash; |
||
61 | } |
||
62 | #else |
||
63 | static unsigned hash_key(const unsigned char *p, int n) |
||
64 | { |
||
65 | unsigned h = 0; |
||
66 | unsigned g; |
||
67 | |||
68 | while (n--) { |
||
69 | h = (h << 4) + *p++; |
||
70 | if ((g = (h & 0xf0000000)) != 0) |
||
71 | h ^= g >> 23; |
||
72 | h &= ~g; |
||
73 | } |
||
74 | return h; |
||
75 | } |
||
76 | #endif |
||
77 | |||
78 | unsigned cso_construct_key(void *item, int item_size) |
||
79 | { |
||
80 | return hash_key((item), item_size); |
||
81 | } |
||
82 | |||
83 | static INLINE struct cso_hash *_cso_hash_for_type(struct cso_cache *sc, enum cso_cache_type type) |
||
84 | { |
||
85 | struct cso_hash *hash; |
||
86 | hash = sc->hashes[type]; |
||
87 | return hash; |
||
88 | } |
||
89 | |||
90 | static void delete_blend_state(void *state, void *data) |
||
91 | { |
||
92 | struct cso_blend *cso = (struct cso_blend *)state; |
||
93 | if (cso->delete_state) |
||
94 | cso->delete_state(cso->context, cso->data); |
||
95 | FREE(state); |
||
96 | } |
||
97 | |||
98 | static void delete_depth_stencil_state(void *state, void *data) |
||
99 | { |
||
100 | struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state; |
||
101 | if (cso->delete_state) |
||
102 | cso->delete_state(cso->context, cso->data); |
||
103 | FREE(state); |
||
104 | } |
||
105 | |||
106 | static void delete_sampler_state(void *state, void *data) |
||
107 | { |
||
108 | struct cso_sampler *cso = (struct cso_sampler *)state; |
||
109 | if (cso->delete_state) |
||
110 | cso->delete_state(cso->context, cso->data); |
||
111 | FREE(state); |
||
112 | } |
||
113 | |||
114 | static void delete_rasterizer_state(void *state, void *data) |
||
115 | { |
||
116 | struct cso_rasterizer *cso = (struct cso_rasterizer *)state; |
||
117 | if (cso->delete_state) |
||
118 | cso->delete_state(cso->context, cso->data); |
||
119 | FREE(state); |
||
120 | } |
||
121 | |||
122 | static void delete_velements(void *state, void *data) |
||
123 | { |
||
124 | struct cso_velements *cso = (struct cso_velements *)state; |
||
125 | if (cso->delete_state) |
||
126 | cso->delete_state(cso->context, cso->data); |
||
127 | FREE(state); |
||
128 | } |
||
129 | |||
130 | static INLINE void delete_cso(void *state, enum cso_cache_type type) |
||
131 | { |
||
132 | switch (type) { |
||
133 | case CSO_BLEND: |
||
134 | delete_blend_state(state, 0); |
||
135 | break; |
||
136 | case CSO_SAMPLER: |
||
137 | delete_sampler_state(state, 0); |
||
138 | break; |
||
139 | case CSO_DEPTH_STENCIL_ALPHA: |
||
140 | delete_depth_stencil_state(state, 0); |
||
141 | break; |
||
142 | case CSO_RASTERIZER: |
||
143 | delete_rasterizer_state(state, 0); |
||
144 | break; |
||
145 | case CSO_VELEMENTS: |
||
146 | delete_velements(state, 0); |
||
147 | break; |
||
148 | default: |
||
149 | assert(0); |
||
150 | FREE(state); |
||
151 | } |
||
152 | } |
||
153 | |||
154 | |||
155 | static INLINE void sanitize_hash(struct cso_cache *sc, |
||
156 | struct cso_hash *hash, |
||
157 | enum cso_cache_type type, |
||
158 | int max_size) |
||
159 | { |
||
160 | if (sc->sanitize_cb) |
||
161 | sc->sanitize_cb(hash, type, max_size, sc->sanitize_data); |
||
162 | } |
||
163 | |||
164 | |||
165 | static INLINE void sanitize_cb(struct cso_hash *hash, enum cso_cache_type type, |
||
166 | int max_size, void *user_data) |
||
167 | { |
||
168 | /* if we're approach the maximum size, remove fourth of the entries |
||
169 | * otherwise every subsequent call will go through the same */ |
||
170 | int hash_size = cso_hash_size(hash); |
||
171 | int max_entries = (max_size > hash_size) ? max_size : hash_size; |
||
172 | int to_remove = (max_size < max_entries) * max_entries/4; |
||
173 | if (hash_size > max_size) |
||
174 | to_remove += hash_size - max_size; |
||
175 | while (to_remove) { |
||
176 | /*remove elements until we're good */ |
||
177 | /*fixme: currently we pick the nodes to remove at random*/ |
||
178 | struct cso_hash_iter iter = cso_hash_first_node(hash); |
||
179 | void *cso = cso_hash_take(hash, cso_hash_iter_key(iter)); |
||
180 | delete_cso(cso, type); |
||
181 | --to_remove; |
||
182 | } |
||
183 | } |
||
184 | |||
185 | struct cso_hash_iter |
||
186 | cso_insert_state(struct cso_cache *sc, |
||
187 | unsigned hash_key, enum cso_cache_type type, |
||
188 | void *state) |
||
189 | { |
||
190 | struct cso_hash *hash = _cso_hash_for_type(sc, type); |
||
191 | sanitize_hash(sc, hash, type, sc->max_size); |
||
192 | |||
193 | return cso_hash_insert(hash, hash_key, state); |
||
194 | } |
||
195 | |||
196 | struct cso_hash_iter |
||
197 | cso_find_state(struct cso_cache *sc, |
||
198 | unsigned hash_key, enum cso_cache_type type) |
||
199 | { |
||
200 | struct cso_hash *hash = _cso_hash_for_type(sc, type); |
||
201 | |||
202 | return cso_hash_find(hash, hash_key); |
||
203 | } |
||
204 | |||
205 | |||
206 | void *cso_hash_find_data_from_template( struct cso_hash *hash, |
||
207 | unsigned hash_key, |
||
208 | void *templ, |
||
209 | int size ) |
||
210 | { |
||
211 | struct cso_hash_iter iter = cso_hash_find(hash, hash_key); |
||
212 | while (!cso_hash_iter_is_null(iter)) { |
||
213 | void *iter_data = cso_hash_iter_data(iter); |
||
214 | if (!memcmp(iter_data, templ, size)) { |
||
215 | /* We found a match |
||
216 | */ |
||
217 | return iter_data; |
||
218 | } |
||
219 | iter = cso_hash_iter_next(iter); |
||
220 | } |
||
221 | return NULL; |
||
222 | } |
||
223 | |||
224 | |||
225 | struct cso_hash_iter cso_find_state_template(struct cso_cache *sc, |
||
226 | unsigned hash_key, enum cso_cache_type type, |
||
227 | void *templ, unsigned size) |
||
228 | { |
||
229 | struct cso_hash_iter iter = cso_find_state(sc, hash_key, type); |
||
230 | while (!cso_hash_iter_is_null(iter)) { |
||
231 | void *iter_data = cso_hash_iter_data(iter); |
||
232 | if (!memcmp(iter_data, templ, size)) |
||
233 | return iter; |
||
234 | iter = cso_hash_iter_next(iter); |
||
235 | } |
||
236 | return iter; |
||
237 | } |
||
238 | |||
239 | void * cso_take_state(struct cso_cache *sc, |
||
240 | unsigned hash_key, enum cso_cache_type type) |
||
241 | { |
||
242 | struct cso_hash *hash = _cso_hash_for_type(sc, type); |
||
243 | return cso_hash_take(hash, hash_key); |
||
244 | } |
||
245 | |||
246 | struct cso_cache *cso_cache_create(void) |
||
247 | { |
||
248 | struct cso_cache *sc = MALLOC_STRUCT(cso_cache); |
||
249 | int i; |
||
250 | if (sc == NULL) |
||
251 | return NULL; |
||
252 | |||
253 | sc->max_size = 4096; |
||
254 | for (i = 0; i < CSO_CACHE_MAX; i++) |
||
255 | sc->hashes[i] = cso_hash_create(); |
||
256 | |||
257 | sc->sanitize_cb = sanitize_cb; |
||
258 | sc->sanitize_data = 0; |
||
259 | |||
260 | return sc; |
||
261 | } |
||
262 | |||
263 | void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type, |
||
264 | cso_state_callback func, void *user_data) |
||
265 | { |
||
266 | struct cso_hash *hash = _cso_hash_for_type(sc, type); |
||
267 | struct cso_hash_iter iter; |
||
268 | |||
269 | iter = cso_hash_first_node(hash); |
||
270 | while (!cso_hash_iter_is_null(iter)) { |
||
271 | void *state = cso_hash_iter_data(iter); |
||
272 | iter = cso_hash_iter_next(iter); |
||
273 | if (state) { |
||
274 | func(state, user_data); |
||
275 | } |
||
276 | } |
||
277 | } |
||
278 | |||
279 | void cso_cache_delete(struct cso_cache *sc) |
||
280 | { |
||
281 | int i; |
||
282 | assert(sc); |
||
283 | |||
284 | if (!sc) |
||
285 | return; |
||
286 | |||
287 | /* delete driver data */ |
||
288 | cso_for_each_state(sc, CSO_BLEND, delete_blend_state, 0); |
||
289 | cso_for_each_state(sc, CSO_DEPTH_STENCIL_ALPHA, delete_depth_stencil_state, 0); |
||
290 | cso_for_each_state(sc, CSO_RASTERIZER, delete_rasterizer_state, 0); |
||
291 | cso_for_each_state(sc, CSO_SAMPLER, delete_sampler_state, 0); |
||
292 | cso_for_each_state(sc, CSO_VELEMENTS, delete_velements, 0); |
||
293 | |||
294 | for (i = 0; i < CSO_CACHE_MAX; i++) |
||
295 | cso_hash_delete(sc->hashes[i]); |
||
296 | |||
297 | FREE(sc); |
||
298 | } |
||
299 | |||
300 | void cso_set_maximum_cache_size(struct cso_cache *sc, int number) |
||
301 | { |
||
302 | int i; |
||
303 | |||
304 | sc->max_size = number; |
||
305 | |||
306 | for (i = 0; i < CSO_CACHE_MAX; i++) |
||
307 | sanitize_hash(sc, sc->hashes[i], i, sc->max_size); |
||
308 | } |
||
309 | |||
310 | int cso_maximum_cache_size(const struct cso_cache *sc) |
||
311 | { |
||
312 | return sc->max_size; |
||
313 | } |
||
314 | |||
315 | void cso_cache_set_sanitize_callback(struct cso_cache *sc, |
||
316 | cso_sanitize_callback cb, |
||
317 | void *user_data) |
||
318 | { |
||
319 | sc->sanitize_cb = cb; |
||
320 | sc->sanitize_data = user_data; |
||
321 | }>>>>><>> |
||
322 |