Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / gallium / drivers / i965simple / brw_state_cache.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a 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, sublicense, 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
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 */
31
32
33 #include "brw_state.h"
34
35 #include "brw_wm.h"
36 #include "brw_vs.h"
37 #include "brw_clip.h"
38 #include "brw_sf.h"
39 #include "brw_gs.h"
40
41 #include "util/u_memory.h"
42
43
44
45 /***********************************************************************
46 * Check cache for uploaded version of struct, else upload new one.
47 * Fail when memory is exhausted.
48 *
49 * XXX: FIXME: Currently search is so slow it would be quicker to
50 * regenerate the data every time...
51 */
52
53 static unsigned hash_key( const void *key, unsigned key_size )
54 {
55 unsigned *ikey = (unsigned *)key;
56 unsigned hash = 0, i;
57
58 assert(key_size % 4 == 0);
59
60 /* I'm sure this can be improved on:
61 */
62 for (i = 0; i < key_size/4; i++)
63 hash ^= ikey[i];
64
65 return hash;
66 }
67
68 static struct brw_cache_item *search_cache( struct brw_cache *cache,
69 unsigned hash,
70 const void *key,
71 unsigned key_size)
72 {
73 struct brw_cache_item *c;
74
75 for (c = cache->items[hash % cache->size]; c; c = c->next) {
76 if (c->hash == hash &&
77 c->key_size == key_size &&
78 memcmp(c->key, key, key_size) == 0)
79 return c;
80 }
81
82 return NULL;
83 }
84
85
86 static void rehash( struct brw_cache *cache )
87 {
88 struct brw_cache_item **items;
89 struct brw_cache_item *c, *next;
90 unsigned size, i;
91
92 size = cache->size * 3;
93 items = (struct brw_cache_item**) MALLOC(size * sizeof(*items));
94 memset(items, 0, size * sizeof(*items));
95
96 for (i = 0; i < cache->size; i++)
97 for (c = cache->items[i]; c; c = next) {
98 next = c->next;
99 c->next = items[c->hash % size];
100 items[c->hash % size] = c;
101 }
102
103 FREE(cache->items);
104 cache->items = items;
105 cache->size = size;
106 }
107
108
109 boolean brw_search_cache( struct brw_cache *cache,
110 const void *key,
111 unsigned key_size,
112 void *aux_return,
113 unsigned *offset_return)
114 {
115 struct brw_cache_item *item;
116 unsigned addr = 0;
117 unsigned hash = hash_key(key, key_size);
118
119 item = search_cache(cache, hash, key, key_size);
120
121 if (item) {
122 if (aux_return)
123 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
124
125 *offset_return = addr = item->offset;
126 }
127
128 if (item == NULL || addr != cache->last_addr) {
129 cache->brw->state.dirty.cache |= 1<<cache->id;
130 cache->last_addr = addr;
131 }
132
133 return item != NULL;
134 }
135
136 unsigned brw_upload_cache( struct brw_cache *cache,
137 const void *key,
138 unsigned key_size,
139 const void *data,
140 unsigned data_size,
141 const void *aux,
142 void *aux_return )
143 {
144 unsigned offset;
145 struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
146 unsigned hash = hash_key(key, key_size);
147 void *tmp = MALLOC(key_size + cache->aux_size);
148
149 if (!brw_pool_alloc(cache->pool, data_size, 1 << 6, &offset)) {
150 /* Should not be possible:
151 */
152 debug_printf("brw_pool_alloc failed\n");
153 exit(1);
154 }
155
156 memcpy(tmp, key, key_size);
157
158 if (cache->aux_size)
159 memcpy(tmp+key_size, aux, cache->aux_size);
160
161 item->key = tmp;
162 item->hash = hash;
163 item->key_size = key_size;
164 item->offset = offset;
165 item->data_size = data_size;
166
167 if (++cache->n_items > cache->size * 1.5)
168 rehash(cache);
169
170 hash %= cache->size;
171 item->next = cache->items[hash];
172 cache->items[hash] = item;
173
174 if (aux_return) {
175 assert(cache->aux_size);
176 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
177 }
178
179 if (BRW_DEBUG & DEBUG_STATE)
180 debug_printf("upload %s: %d bytes to pool buffer %p offset %x\n",
181 cache->name,
182 data_size,
183 (void*)cache->pool->buffer,
184 offset);
185
186 /* Copy data to the buffer:
187 */
188 cache->brw->winsys->buffer_subdata_typed(cache->brw->winsys,
189 cache->pool->buffer,
190 offset,
191 data_size,
192 data,
193 cache->id);
194
195 cache->brw->state.dirty.cache |= 1<<cache->id;
196 cache->last_addr = offset;
197
198 return offset;
199 }
200
201 /* This doesn't really work with aux data. Use search/upload instead
202 */
203 unsigned brw_cache_data_sz(struct brw_cache *cache,
204 const void *data,
205 unsigned data_size)
206 {
207 unsigned addr;
208
209 if (!brw_search_cache(cache, data, data_size, NULL, &addr)) {
210 addr = brw_upload_cache(cache,
211 data, data_size,
212 data, data_size,
213 NULL, NULL);
214 }
215
216 return addr;
217 }
218
219 unsigned brw_cache_data(struct brw_cache *cache,
220 const void *data)
221 {
222 return brw_cache_data_sz(cache, data, cache->key_size);
223 }
224
225 enum pool_type {
226 DW_SURFACE_STATE,
227 DW_GENERAL_STATE
228 };
229
230 static void brw_init_cache( struct brw_context *brw,
231 const char *name,
232 unsigned id,
233 unsigned key_size,
234 unsigned aux_size,
235 enum pool_type pool_type)
236 {
237 struct brw_cache *cache = &brw->cache[id];
238 cache->brw = brw;
239 cache->id = id;
240 cache->name = name;
241 cache->items = NULL;
242
243 cache->size = 7;
244 cache->n_items = 0;
245 cache->items = (struct brw_cache_item **)
246 CALLOC(cache->size, sizeof(struct brw_cache_item));
247
248
249 cache->key_size = key_size;
250 cache->aux_size = aux_size;
251 switch (pool_type) {
252 case DW_GENERAL_STATE: cache->pool = &brw->pool[BRW_GS_POOL]; break;
253 case DW_SURFACE_STATE: cache->pool = &brw->pool[BRW_SS_POOL]; break;
254 default: assert(0); break;
255 }
256 }
257
258 void brw_init_caches( struct brw_context *brw )
259 {
260
261 brw_init_cache(brw,
262 "CC_VP",
263 BRW_CC_VP,
264 sizeof(struct brw_cc_viewport),
265 0,
266 DW_GENERAL_STATE);
267
268 brw_init_cache(brw,
269 "CC_UNIT",
270 BRW_CC_UNIT,
271 sizeof(struct brw_cc_unit_state),
272 0,
273 DW_GENERAL_STATE);
274
275 brw_init_cache(brw,
276 "WM_PROG",
277 BRW_WM_PROG,
278 sizeof(struct brw_wm_prog_key),
279 sizeof(struct brw_wm_prog_data),
280 DW_GENERAL_STATE);
281
282 brw_init_cache(brw,
283 "SAMPLER_DEFAULT_COLOR",
284 BRW_SAMPLER_DEFAULT_COLOR,
285 sizeof(struct brw_sampler_default_color),
286 0,
287 DW_GENERAL_STATE);
288
289 brw_init_cache(brw,
290 "SAMPLER",
291 BRW_SAMPLER,
292 0, /* variable key/data size */
293 0,
294 DW_GENERAL_STATE);
295
296 brw_init_cache(brw,
297 "WM_UNIT",
298 BRW_WM_UNIT,
299 sizeof(struct brw_wm_unit_state),
300 0,
301 DW_GENERAL_STATE);
302
303 brw_init_cache(brw,
304 "SF_PROG",
305 BRW_SF_PROG,
306 sizeof(struct brw_sf_prog_key),
307 sizeof(struct brw_sf_prog_data),
308 DW_GENERAL_STATE);
309
310 brw_init_cache(brw,
311 "SF_VP",
312 BRW_SF_VP,
313 sizeof(struct brw_sf_viewport),
314 0,
315 DW_GENERAL_STATE);
316
317 brw_init_cache(brw,
318 "SF_UNIT",
319 BRW_SF_UNIT,
320 sizeof(struct brw_sf_unit_state),
321 0,
322 DW_GENERAL_STATE);
323
324 brw_init_cache(brw,
325 "VS_UNIT",
326 BRW_VS_UNIT,
327 sizeof(struct brw_vs_unit_state),
328 0,
329 DW_GENERAL_STATE);
330
331 brw_init_cache(brw,
332 "VS_PROG",
333 BRW_VS_PROG,
334 sizeof(struct brw_vs_prog_key),
335 sizeof(struct brw_vs_prog_data),
336 DW_GENERAL_STATE);
337
338 brw_init_cache(brw,
339 "CLIP_UNIT",
340 BRW_CLIP_UNIT,
341 sizeof(struct brw_clip_unit_state),
342 0,
343 DW_GENERAL_STATE);
344
345 brw_init_cache(brw,
346 "CLIP_PROG",
347 BRW_CLIP_PROG,
348 sizeof(struct brw_clip_prog_key),
349 sizeof(struct brw_clip_prog_data),
350 DW_GENERAL_STATE);
351
352 brw_init_cache(brw,
353 "GS_UNIT",
354 BRW_GS_UNIT,
355 sizeof(struct brw_gs_unit_state),
356 0,
357 DW_GENERAL_STATE);
358
359 brw_init_cache(brw,
360 "GS_PROG",
361 BRW_GS_PROG,
362 sizeof(struct brw_gs_prog_key),
363 sizeof(struct brw_gs_prog_data),
364 DW_GENERAL_STATE);
365
366 brw_init_cache(brw,
367 "SS_SURFACE",
368 BRW_SS_SURFACE,
369 sizeof(struct brw_surface_state),
370 0,
371 DW_SURFACE_STATE);
372
373 brw_init_cache(brw,
374 "SS_SURF_BIND",
375 BRW_SS_SURF_BIND,
376 sizeof(struct brw_surface_binding_table),
377 0,
378 DW_SURFACE_STATE);
379 }
380
381
382 /* When we lose hardware context, need to invalidate the surface cache
383 * as these structs must be explicitly re-uploaded. They are subject
384 * to fixup by the memory manager as they contain absolute agp
385 * offsets, so we need to ensure there is a fresh version of the
386 * struct available to receive the fixup.
387 *
388 * XXX: Need to ensure that there aren't two versions of a surface or
389 * bufferobj with different backing data active in the same buffer at
390 * once? Otherwise the cache could confuse them. Maybe better not to
391 * cache at all?
392 *
393 * --> Isn't this the same as saying need to ensure batch is flushed
394 * before new data is uploaded to an existing buffer? We
395 * already try to make sure of that.
396 */
397 static void clear_cache( struct brw_cache *cache )
398 {
399 struct brw_cache_item *c, *next;
400 unsigned i;
401
402 for (i = 0; i < cache->size; i++) {
403 for (c = cache->items[i]; c; c = next) {
404 next = c->next;
405 free((void *)c->key);
406 free(c);
407 }
408 cache->items[i] = NULL;
409 }
410
411 cache->n_items = 0;
412 }
413
414 void brw_clear_all_caches( struct brw_context *brw )
415 {
416 int i;
417
418 if (BRW_DEBUG & DEBUG_STATE)
419 debug_printf("%s\n", __FUNCTION__);
420
421 for (i = 0; i < BRW_MAX_CACHE; i++)
422 clear_cache(&brw->cache[i]);
423
424 if (brw->curbe.last_buf) {
425 FREE(brw->curbe.last_buf);
426 brw->curbe.last_buf = NULL;
427 }
428
429 brw->state.dirty.brw |= ~0;
430 brw->state.dirty.cache |= ~0;
431 }
432
433
434
435
436
437 void brw_destroy_caches( struct brw_context *brw )
438 {
439 unsigned i;
440
441 for (i = 0; i < BRW_MAX_CACHE; i++)
442 clear_cache(&brw->cache[i]);
443 }