NV30/NV40 CMP and SCS src == dst handling
[mesa.git] / src / gallium / drivers / i965 / 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 /** @file brw_state_cache.c
33 *
34 * This file implements a simple static state cache for 965. The consumers
35 * can query the hash table of state using a cache_id, opaque key data,
36 * and list of buffers that will be used in relocations, and receive the
37 * corresponding state buffer object of state (plus associated auxiliary
38 * data) in return.
39 *
40 * The inner workings are a simple hash table based on a CRC of the key data.
41 * The cache_id and relocation target buffers associated with the state
42 * buffer are included as auxiliary key data, but are not part of the hash
43 * value (this should be fixed, but will likely be fixed instead by making
44 * consumers use structured keys).
45 *
46 * Replacement is not implemented. Instead, when the cache gets too big, at
47 * a safe point (unlock) we throw out all of the cache data and let it
48 * regenerate for the next rendering operation.
49 *
50 * The reloc structs need to be included as key data, otherwise the
51 * non-unique values stuffed in the offset in key data through
52 * brw_cache_data() may result in successful probe for state buffers
53 * even when the buffer being referenced doesn't match. The result would be
54 * that the same state cache entry is used twice for different buffers,
55 * only one of the two buffers referenced gets put into the offset, and the
56 * incorrect program is run for the other instance.
57 */
58 #include "util/u_memory.h"
59
60 #include "brw_debug.h"
61 #include "brw_state.h"
62 #include "brw_batchbuffer.h"
63
64 /* XXX: Fixme - have to include these to get the sizes of the prog_key
65 * structs:
66 */
67 #include "brw_wm.h"
68 #include "brw_vs.h"
69 #include "brw_clip.h"
70 #include "brw_sf.h"
71 #include "brw_gs.h"
72
73
74 static GLuint
75 hash_key(const void *key, GLuint key_size,
76 struct brw_winsys_reloc *relocs, GLuint nr_relocs)
77 {
78 GLuint *ikey = (GLuint *)key;
79 GLuint hash = 0, i;
80
81 assert(key_size % 4 == 0);
82
83 /* I'm sure this can be improved on:
84 */
85 for (i = 0; i < key_size/4; i++) {
86 hash ^= ikey[i];
87 hash = (hash << 5) | (hash >> 27);
88 }
89
90 /* Include the BO pointers as key data as well */
91 ikey = (GLuint *)relocs;
92 key_size = nr_relocs * sizeof(struct brw_winsys_reloc);
93 for (i = 0; i < key_size/4; i++) {
94 hash ^= ikey[i];
95 hash = (hash << 5) | (hash >> 27);
96 }
97
98 return hash;
99 }
100
101
102 /**
103 * Marks a new buffer as being chosen for the given cache id.
104 */
105 static void
106 update_cache_last(struct brw_cache *cache, enum brw_cache_id cache_id,
107 struct brw_winsys_buffer *bo)
108 {
109 if (bo == cache->last_bo[cache_id])
110 return; /* no change */
111
112 bo_reference( &cache->last_bo[cache_id], bo );
113
114 cache->brw->state.dirty.cache |= 1 << cache_id;
115 }
116
117
118 static struct brw_cache_item *
119 search_cache(struct brw_cache *cache, enum brw_cache_id cache_id,
120 GLuint hash, const void *key, GLuint key_size,
121 struct brw_winsys_reloc *relocs, GLuint nr_relocs)
122 {
123 struct brw_cache_item *c;
124
125 #if 0
126 int bucketcount = 0;
127
128 for (c = cache->items[hash % cache->size]; c; c = c->next)
129 bucketcount++;
130
131 debug_printf("bucket %d/%d = %d/%d items\n", hash % cache->size,
132 cache->size, bucketcount, cache->n_items);
133 #endif
134
135 for (c = cache->items[hash % cache->size]; c; c = c->next) {
136 if (c->cache_id == cache_id &&
137 c->hash == hash &&
138 c->key_size == key_size &&
139 memcmp(c->key, key, key_size) == 0 &&
140 c->nr_relocs == nr_relocs &&
141 memcmp(c->relocs, relocs, nr_relocs * sizeof *relocs) == 0)
142 return c;
143 }
144
145 return NULL;
146 }
147
148
149 static void
150 rehash(struct brw_cache *cache)
151 {
152 struct brw_cache_item **items;
153 struct brw_cache_item *c, *next;
154 GLuint size, i;
155
156 size = cache->size * 3;
157 items = (struct brw_cache_item**) CALLOC(size, sizeof(*items));
158
159 for (i = 0; i < cache->size; i++)
160 for (c = cache->items[i]; c; c = next) {
161 next = c->next;
162 c->next = items[c->hash % size];
163 items[c->hash % size] = c;
164 }
165
166 FREE(cache->items);
167 cache->items = items;
168 cache->size = size;
169 }
170
171
172 /**
173 * Returns the buffer object matching cache_id and key, or NULL.
174 */
175 boolean
176 brw_search_cache(struct brw_cache *cache,
177 enum brw_cache_id cache_id,
178 const void *key,
179 GLuint key_size,
180 struct brw_winsys_reloc *relocs,
181 GLuint nr_relocs,
182 void *aux_return,
183 struct brw_winsys_buffer **bo_out)
184 {
185 struct brw_cache_item *item;
186 GLuint hash = hash_key(key, key_size, relocs, nr_relocs);
187
188 item = search_cache(cache, cache_id, hash, key, key_size,
189 relocs, nr_relocs);
190
191 if (item) {
192 if (aux_return)
193 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
194
195 update_cache_last(cache, cache_id, item->bo);
196 bo_reference(bo_out, item->bo);
197 return TRUE;
198 }
199
200 return FALSE;
201 }
202
203
204 enum pipe_error
205 brw_upload_cache( struct brw_cache *cache,
206 enum brw_cache_id cache_id,
207 const void *key,
208 GLuint key_size,
209 struct brw_winsys_reloc *relocs,
210 GLuint nr_relocs,
211 const void *data,
212 GLuint data_size,
213 const void *aux,
214 void *aux_return,
215 struct brw_winsys_buffer **bo_out)
216 {
217 struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
218 GLuint hash = hash_key(key, key_size, relocs, nr_relocs);
219 GLuint relocs_size = nr_relocs * sizeof relocs[0];
220 GLuint aux_size = cache->aux_size[cache_id];
221 enum pipe_error ret;
222 void *tmp;
223 int i;
224
225 /* Create the buffer object to contain the data. For now, use a
226 * single buffer type to describe all cached state atoms. Later,
227 * may want to take advantage of hardware distinctions between
228 * these various entities.
229 */
230 ret = cache->sws->bo_alloc(cache->sws,
231 cache->buffer_type,
232 data_size, 1 << 6,
233 bo_out);
234 if (ret)
235 return ret;
236
237
238 /* Set up the memory containing the key, aux_data, and relocs */
239 tmp = MALLOC(key_size + aux_size + relocs_size);
240
241 memcpy(tmp, key, key_size);
242 memcpy((char *)tmp + key_size, aux, cache->aux_size[cache_id]);
243 memcpy((char *)tmp + key_size + aux_size, relocs, relocs_size);
244 for (i = 0; i < nr_relocs; i++) {
245 p_atomic_inc(&relocs[i].bo->reference.count);
246 }
247
248 item->cache_id = cache_id;
249 item->key = tmp;
250 item->hash = hash;
251 item->key_size = key_size;
252 item->relocs = (struct brw_winsys_reloc *)((char *)tmp + key_size + aux_size);
253 item->nr_relocs = nr_relocs;
254 bo_reference( &item->bo, *bo_out );
255 item->data_size = data_size;
256
257 if (cache->n_items > cache->size * 1.5)
258 rehash(cache);
259
260 hash %= cache->size;
261 item->next = cache->items[hash];
262 cache->items[hash] = item;
263 cache->n_items++;
264
265 if (aux_return) {
266 assert(cache->aux_size[cache_id]);
267 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
268 }
269
270 if (BRW_DEBUG & DEBUG_STATE)
271 debug_printf("upload %s: %d bytes to cache id %d\n",
272 cache->name[cache_id],
273 data_size, cache_id);
274
275 /* Copy data to the buffer */
276 ret = cache->sws->bo_subdata(item->bo,
277 cache_id,
278 0, data_size, data,
279 relocs, nr_relocs);
280 if (ret)
281 return ret;
282
283 update_cache_last(cache, cache_id, item->bo);
284
285 return PIPE_OK;
286 }
287
288
289 /**
290 * This doesn't really work with aux data. Use search/upload instead
291 */
292 enum pipe_error
293 brw_cache_data_sz(struct brw_cache *cache,
294 enum brw_cache_id cache_id,
295 const void *data,
296 GLuint data_size,
297 struct brw_winsys_reloc *relocs,
298 GLuint nr_relocs,
299 struct brw_winsys_buffer **bo_out)
300 {
301 struct brw_cache_item *item;
302 GLuint hash = hash_key(data, data_size, relocs, nr_relocs);
303
304 item = search_cache(cache, cache_id, hash, data, data_size,
305 relocs, nr_relocs);
306 if (item) {
307 update_cache_last(cache, cache_id, item->bo);
308
309 bo_reference(bo_out, item->bo);
310 return PIPE_OK;
311 }
312
313 return brw_upload_cache(cache, cache_id,
314 data, data_size,
315 relocs, nr_relocs,
316 data, data_size,
317 NULL, NULL,
318 bo_out);
319 }
320
321
322 /**
323 * Wrapper around brw_cache_data_sz using the cache_id's canonical key size.
324 *
325 * If nr_relocs is nonzero, brw_search_cache()/brw_upload_cache() would be
326 * better to use, as the potentially changing offsets in the data-used-as-key
327 * will result in excessive cache misses.
328 *
329 * XXX: above is no longer true -- can we remove some code?
330 */
331 enum pipe_error
332 brw_cache_data(struct brw_cache *cache,
333 enum brw_cache_id cache_id,
334 const void *data,
335 struct brw_winsys_reloc *relocs,
336 GLuint nr_relocs,
337 struct brw_winsys_buffer **bo_out)
338 {
339 return brw_cache_data_sz(cache, cache_id, data, cache->key_size[cache_id],
340 relocs, nr_relocs, bo_out);
341 }
342
343
344 static void
345 brw_init_cache_id(struct brw_cache *cache,
346 const char *name,
347 enum brw_cache_id id,
348 GLuint key_size,
349 GLuint aux_size)
350 {
351 cache->name[id] = strdup(name);
352 cache->key_size[id] = key_size;
353 cache->aux_size[id] = aux_size;
354 }
355
356
357 static void
358 brw_init_general_state_cache(struct brw_context *brw)
359 {
360 struct brw_cache *cache = &brw->cache;
361
362 cache->brw = brw;
363 cache->sws = brw->sws;
364
365 cache->buffer_type = BRW_BUFFER_TYPE_GENERAL_STATE;
366
367 cache->size = 7;
368 cache->n_items = 0;
369 cache->items = (struct brw_cache_item **)
370 CALLOC(cache->size, sizeof(struct brw_cache_item));
371
372 brw_init_cache_id(cache,
373 "CC_VP",
374 BRW_CC_VP,
375 sizeof(struct brw_cc_viewport),
376 0);
377
378 brw_init_cache_id(cache,
379 "CC_UNIT",
380 BRW_CC_UNIT,
381 sizeof(struct brw_cc_unit_state),
382 0);
383
384 brw_init_cache_id(cache,
385 "WM_PROG",
386 BRW_WM_PROG,
387 sizeof(struct brw_wm_prog_key),
388 sizeof(struct brw_wm_prog_data));
389
390 brw_init_cache_id(cache,
391 "SAMPLER_DEFAULT_COLOR",
392 BRW_SAMPLER_DEFAULT_COLOR,
393 sizeof(struct brw_sampler_default_color),
394 0);
395
396 brw_init_cache_id(cache,
397 "SAMPLER",
398 BRW_SAMPLER,
399 0, /* variable key/data size */
400 0);
401
402 brw_init_cache_id(cache,
403 "WM_UNIT",
404 BRW_WM_UNIT,
405 sizeof(struct brw_wm_unit_state),
406 0);
407
408 brw_init_cache_id(cache,
409 "SF_PROG",
410 BRW_SF_PROG,
411 sizeof(struct brw_sf_prog_key),
412 sizeof(struct brw_sf_prog_data));
413
414 brw_init_cache_id(cache,
415 "SF_VP",
416 BRW_SF_VP,
417 sizeof(struct brw_sf_viewport),
418 0);
419
420 brw_init_cache_id(cache,
421 "SF_UNIT",
422 BRW_SF_UNIT,
423 sizeof(struct brw_sf_unit_state),
424 0);
425
426 brw_init_cache_id(cache,
427 "VS_UNIT",
428 BRW_VS_UNIT,
429 sizeof(struct brw_vs_unit_state),
430 0);
431
432 brw_init_cache_id(cache,
433 "VS_PROG",
434 BRW_VS_PROG,
435 sizeof(struct brw_vs_prog_key),
436 sizeof(struct brw_vs_prog_data));
437
438 brw_init_cache_id(cache,
439 "CLIP_UNIT",
440 BRW_CLIP_UNIT,
441 sizeof(struct brw_clip_unit_state),
442 0);
443
444 brw_init_cache_id(cache,
445 "CLIP_PROG",
446 BRW_CLIP_PROG,
447 sizeof(struct brw_clip_prog_key),
448 sizeof(struct brw_clip_prog_data));
449
450 brw_init_cache_id(cache,
451 "GS_UNIT",
452 BRW_GS_UNIT,
453 sizeof(struct brw_gs_unit_state),
454 0);
455
456 brw_init_cache_id(cache,
457 "GS_PROG",
458 BRW_GS_PROG,
459 sizeof(struct brw_gs_prog_key),
460 sizeof(struct brw_gs_prog_data));
461 }
462
463
464 static void
465 brw_init_surface_state_cache(struct brw_context *brw)
466 {
467 struct brw_cache *cache = &brw->surface_cache;
468
469 cache->brw = brw;
470 cache->sws = brw->sws;
471
472 cache->buffer_type = BRW_BUFFER_TYPE_SURFACE_STATE;
473
474 cache->size = 7;
475 cache->n_items = 0;
476 cache->items = (struct brw_cache_item **)
477 CALLOC(cache->size, sizeof(struct brw_cache_item));
478
479 brw_init_cache_id(cache,
480 "SS_SURFACE",
481 BRW_SS_SURFACE,
482 sizeof(struct brw_surface_state),
483 0);
484
485 brw_init_cache_id(cache,
486 "SS_SURF_BIND",
487 BRW_SS_SURF_BIND,
488 0,
489 0);
490 }
491
492
493 void
494 brw_init_caches(struct brw_context *brw)
495 {
496 brw_init_general_state_cache(brw);
497 brw_init_surface_state_cache(brw);
498 }
499
500
501 static void
502 brw_clear_cache(struct brw_context *brw, struct brw_cache *cache)
503 {
504 struct brw_cache_item *c, *next;
505 GLuint i;
506
507 if (BRW_DEBUG & DEBUG_STATE)
508 debug_printf("%s\n", __FUNCTION__);
509
510 for (i = 0; i < cache->size; i++) {
511 for (c = cache->items[i]; c; c = next) {
512 int j;
513
514 next = c->next;
515
516 for (j = 0; j < c->nr_relocs; j++)
517 bo_reference(&c->relocs[j].bo, NULL);
518
519 bo_reference(&c->bo, NULL);
520 FREE((void *)c->key);
521 FREE(c);
522 }
523 cache->items[i] = NULL;
524 }
525
526 cache->n_items = 0;
527
528 if (brw->curbe.last_buf) {
529 FREE(brw->curbe.last_buf);
530 brw->curbe.last_buf = NULL;
531 }
532
533 brw->state.dirty.mesa |= ~0;
534 brw->state.dirty.brw |= ~0;
535 brw->state.dirty.cache |= ~0;
536 }
537
538 /* Clear all entries from the cache that point to the given bo.
539 *
540 * This lets us release memory for reuse earlier for known-dead buffers,
541 * at the cost of walking the entire hash table.
542 */
543 void
544 brw_state_cache_bo_delete(struct brw_cache *cache, struct brw_winsys_buffer *bo)
545 {
546 struct brw_cache_item **prev;
547 GLuint i;
548
549 if (BRW_DEBUG & DEBUG_STATE)
550 debug_printf("%s\n", __FUNCTION__);
551
552 for (i = 0; i < cache->size; i++) {
553 for (prev = &cache->items[i]; *prev;) {
554 struct brw_cache_item *c = *prev;
555
556 if (cache->sws->bo_references(c->bo, bo)) {
557 int j;
558
559 *prev = c->next;
560
561 for (j = 0; j < c->nr_relocs; j++)
562 bo_reference(&c->relocs[j].bo, NULL);
563
564 bo_reference(&c->bo, NULL);
565
566 FREE((void *)c->key);
567 FREE(c);
568 cache->n_items--;
569 } else {
570 prev = &c->next;
571 }
572 }
573 }
574 }
575
576 void
577 brw_state_cache_check_size(struct brw_context *brw)
578 {
579 if (BRW_DEBUG & DEBUG_STATE)
580 debug_printf("%s (n_items=%d)\n", __FUNCTION__, brw->cache.n_items);
581
582 /* un-tuned guess. We've got around 20 state objects for a total of around
583 * 32k, so 1000 of them is around 1.5MB.
584 */
585 if (brw->cache.n_items > 1000)
586 brw_clear_cache(brw, &brw->cache);
587
588 if (brw->surface_cache.n_items > 1000)
589 brw_clear_cache(brw, &brw->surface_cache);
590 }
591
592
593 static void
594 brw_destroy_cache(struct brw_context *brw, struct brw_cache *cache)
595 {
596 GLuint i;
597
598 if (BRW_DEBUG & DEBUG_STATE)
599 debug_printf("%s\n", __FUNCTION__);
600
601 brw_clear_cache(brw, cache);
602 for (i = 0; i < BRW_MAX_CACHE; i++) {
603 bo_reference(&cache->last_bo[i], NULL);
604 FREE(cache->name[i]);
605 }
606 FREE(cache->items);
607 cache->items = NULL;
608 cache->size = 0;
609 }
610
611
612 void
613 brw_destroy_caches(struct brw_context *brw)
614 {
615 brw_destroy_cache(brw, &brw->cache);
616 brw_destroy_cache(brw, &brw->surface_cache);
617 }