2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
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:
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.
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.
26 **********************************************************************/
29 * Keith Whitwell <keith@tungstengraphics.com>
32 /** @file brw_state_cache.c
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
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).
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.
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.
58 #include "util/u_memory.h"
60 #include "brw_debug.h"
61 #include "brw_state.h"
63 /* XXX: Fixme - have to include these to get the sizes of the prog_key
74 hash_key(const void *key
, GLuint key_size
,
75 struct brw_winsys_reloc
*relocs
, GLuint nr_relocs
)
77 GLuint
*ikey
= (GLuint
*)key
;
80 assert(key_size
% 4 == 0);
82 /* I'm sure this can be improved on:
84 for (i
= 0; i
< key_size
/4; i
++) {
86 hash
= (hash
<< 5) | (hash
>> 27);
89 /* Include the BO pointers as key data as well */
90 ikey
= (GLuint
*)relocs
;
91 key_size
= nr_relocs
* sizeof(struct brw_winsys_reloc
);
92 for (i
= 0; i
< key_size
/4; i
++) {
94 hash
= (hash
<< 5) | (hash
>> 27);
102 * Marks a new buffer as being chosen for the given cache id.
105 update_cache_last(struct brw_cache
*cache
, enum brw_cache_id cache_id
,
106 struct brw_winsys_buffer
*bo
)
108 if (bo
== cache
->last_bo
[cache_id
])
109 return; /* no change */
111 bo_reference( &cache
->last_bo
[cache_id
], bo
);
113 cache
->brw
->state
.dirty
.cache
|= 1 << cache_id
;
117 static struct brw_cache_item
*
118 search_cache(struct brw_cache
*cache
, enum brw_cache_id cache_id
,
119 GLuint hash
, const void *key
, GLuint key_size
,
120 struct brw_winsys_reloc
*relocs
, GLuint nr_relocs
)
122 struct brw_cache_item
*c
;
127 for (c
= cache
->items
[hash
% cache
->size
]; c
; c
= c
->next
)
130 debug_printf("bucket %d/%d = %d/%d items\n", hash
% cache
->size
,
131 cache
->size
, bucketcount
, cache
->n_items
);
134 for (c
= cache
->items
[hash
% cache
->size
]; c
; c
= c
->next
) {
135 if (c
->cache_id
== cache_id
&&
137 c
->key_size
== key_size
&&
138 memcmp(c
->key
, key
, key_size
) == 0 &&
139 c
->nr_relocs
== nr_relocs
&&
140 memcmp(c
->relocs
, relocs
, nr_relocs
* sizeof *relocs
) == 0)
149 rehash(struct brw_cache
*cache
)
151 struct brw_cache_item
**items
;
152 struct brw_cache_item
*c
, *next
;
155 size
= cache
->size
* 3;
156 items
= (struct brw_cache_item
**) CALLOC(size
, sizeof(*items
));
158 for (i
= 0; i
< cache
->size
; i
++)
159 for (c
= cache
->items
[i
]; c
; c
= next
) {
161 c
->next
= items
[c
->hash
% size
];
162 items
[c
->hash
% size
] = c
;
166 cache
->items
= items
;
172 * Returns the buffer object matching cache_id and key, or NULL.
175 brw_search_cache(struct brw_cache
*cache
,
176 enum brw_cache_id cache_id
,
179 struct brw_winsys_reloc
*relocs
,
182 struct brw_winsys_buffer
**bo_out
)
184 struct brw_cache_item
*item
;
185 GLuint hash
= hash_key(key
, key_size
, relocs
, nr_relocs
);
187 item
= search_cache(cache
, cache_id
, hash
, key
, key_size
,
192 *(void **)aux_return
= (void *)((char *)item
->key
+ item
->key_size
);
194 update_cache_last(cache
, cache_id
, item
->bo
);
195 bo_reference(bo_out
, item
->bo
);
204 brw_upload_cache( struct brw_cache
*cache
,
205 enum brw_cache_id cache_id
,
208 struct brw_winsys_reloc
*relocs
,
214 struct brw_winsys_buffer
**bo_out
)
216 struct brw_cache_item
*item
;
217 GLuint hash
= hash_key(key
, key_size
, relocs
, nr_relocs
);
218 GLuint relocs_size
= nr_relocs
* sizeof relocs
[0];
219 GLuint aux_size
= cache
->aux_size
[cache_id
];
224 /* Create the buffer object to contain the data. For now, use a
225 * single buffer type to describe all cached state atoms. Later,
226 * may want to take advantage of hardware distinctions between
227 * these various entities.
229 ret
= cache
->sws
->bo_alloc(cache
->sws
,
236 item
= CALLOC_STRUCT(brw_cache_item
);
238 /* Set up the memory containing the key, aux_data, and relocs */
239 tmp
= MALLOC(key_size
+ aux_size
+ relocs_size
);
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
);
248 item
->cache_id
= cache_id
;
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
;
257 if (cache
->n_items
> cache
->size
* 1.5)
261 item
->next
= cache
->items
[hash
];
262 cache
->items
[hash
] = item
;
266 assert(cache
->aux_size
[cache_id
]);
267 *(void **)aux_return
= (void *)((char *)item
->key
+ item
->key_size
);
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
);
275 /* Copy data to the buffer */
276 ret
= cache
->sws
->bo_subdata(item
->bo
,
283 update_cache_last(cache
, cache_id
, item
->bo
);
290 * This doesn't really work with aux data. Use search/upload instead
293 brw_cache_data_sz(struct brw_cache
*cache
,
294 enum brw_cache_id cache_id
,
297 struct brw_winsys_reloc
*relocs
,
299 struct brw_winsys_buffer
**bo_out
)
301 struct brw_cache_item
*item
;
302 GLuint hash
= hash_key(data
, data_size
, relocs
, nr_relocs
);
304 item
= search_cache(cache
, cache_id
, hash
, data
, data_size
,
307 update_cache_last(cache
, cache_id
, item
->bo
);
309 bo_reference(bo_out
, item
->bo
);
313 return brw_upload_cache(cache
, cache_id
,
323 * Wrapper around brw_cache_data_sz using the cache_id's canonical key size.
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.
329 * XXX: above is no longer true -- can we remove some code?
332 brw_cache_data(struct brw_cache
*cache
,
333 enum brw_cache_id cache_id
,
335 struct brw_winsys_reloc
*relocs
,
337 struct brw_winsys_buffer
**bo_out
)
339 return brw_cache_data_sz(cache
, cache_id
, data
, cache
->key_size
[cache_id
],
340 relocs
, nr_relocs
, bo_out
);
345 brw_init_cache_id(struct brw_cache
*cache
,
347 enum brw_cache_id id
,
351 cache
->name
[id
] = strdup(name
);
352 cache
->key_size
[id
] = key_size
;
353 cache
->aux_size
[id
] = aux_size
;
358 brw_init_general_state_cache(struct brw_context
*brw
)
360 struct brw_cache
*cache
= &brw
->cache
;
363 cache
->sws
= brw
->sws
;
365 cache
->buffer_type
= BRW_BUFFER_TYPE_GENERAL_STATE
;
369 cache
->items
= (struct brw_cache_item
**)
370 CALLOC(cache
->size
, sizeof(struct brw_cache_item
));
372 brw_init_cache_id(cache
,
375 sizeof(struct brw_cc_viewport
),
378 brw_init_cache_id(cache
,
381 sizeof(struct brw_cc_unit_state
),
384 brw_init_cache_id(cache
,
387 sizeof(struct brw_wm_prog_key
),
388 sizeof(struct brw_wm_prog_data
));
390 brw_init_cache_id(cache
,
391 "SAMPLER_DEFAULT_COLOR",
392 BRW_SAMPLER_DEFAULT_COLOR
,
393 sizeof(struct brw_sampler_default_color
),
396 brw_init_cache_id(cache
,
399 0, /* variable key/data size */
402 brw_init_cache_id(cache
,
405 sizeof(struct brw_wm_unit_state
),
408 brw_init_cache_id(cache
,
411 sizeof(struct brw_sf_prog_key
),
412 sizeof(struct brw_sf_prog_data
));
414 brw_init_cache_id(cache
,
417 sizeof(struct brw_sf_viewport
),
420 brw_init_cache_id(cache
,
423 sizeof(struct brw_sf_unit_state
),
426 brw_init_cache_id(cache
,
429 sizeof(struct brw_vs_unit_state
),
432 brw_init_cache_id(cache
,
435 sizeof(struct brw_vs_prog_key
),
436 sizeof(struct brw_vs_prog_data
));
438 brw_init_cache_id(cache
,
441 sizeof(struct brw_clip_unit_state
),
444 brw_init_cache_id(cache
,
447 sizeof(struct brw_clip_prog_key
),
448 sizeof(struct brw_clip_prog_data
));
450 brw_init_cache_id(cache
,
453 sizeof(struct brw_gs_unit_state
),
456 brw_init_cache_id(cache
,
459 sizeof(struct brw_gs_prog_key
),
460 sizeof(struct brw_gs_prog_data
));
465 brw_init_surface_state_cache(struct brw_context
*brw
)
467 struct brw_cache
*cache
= &brw
->surface_cache
;
470 cache
->sws
= brw
->sws
;
472 cache
->buffer_type
= BRW_BUFFER_TYPE_SURFACE_STATE
;
476 cache
->items
= (struct brw_cache_item
**)
477 CALLOC(cache
->size
, sizeof(struct brw_cache_item
));
479 brw_init_cache_id(cache
,
482 sizeof(struct brw_surface_state
),
485 brw_init_cache_id(cache
,
494 brw_init_caches(struct brw_context
*brw
)
496 brw_init_general_state_cache(brw
);
497 brw_init_surface_state_cache(brw
);
502 brw_clear_cache(struct brw_context
*brw
, struct brw_cache
*cache
)
504 struct brw_cache_item
*c
, *next
;
507 if (BRW_DEBUG
& DEBUG_STATE
)
508 debug_printf("%s\n", __FUNCTION__
);
510 for (i
= 0; i
< cache
->size
; i
++) {
511 for (c
= cache
->items
[i
]; c
; c
= next
) {
516 for (j
= 0; j
< c
->nr_relocs
; j
++)
517 bo_reference(&c
->relocs
[j
].bo
, NULL
);
519 bo_reference(&c
->bo
, NULL
);
520 FREE((void *)c
->key
);
523 cache
->items
[i
] = NULL
;
528 if (brw
->curbe
.last_buf
) {
529 FREE(brw
->curbe
.last_buf
);
530 brw
->curbe
.last_buf
= NULL
;
533 brw
->state
.dirty
.mesa
|= ~0;
534 brw
->state
.dirty
.brw
|= ~0;
535 brw
->state
.dirty
.cache
|= ~0;
538 /* Clear all entries from the cache that point to the given bo.
540 * This lets us release memory for reuse earlier for known-dead buffers,
541 * at the cost of walking the entire hash table.
544 brw_state_cache_bo_delete(struct brw_cache
*cache
, struct brw_winsys_buffer
*bo
)
546 struct brw_cache_item
**prev
;
549 if (BRW_DEBUG
& DEBUG_STATE
)
550 debug_printf("%s\n", __FUNCTION__
);
552 for (i
= 0; i
< cache
->size
; i
++) {
553 for (prev
= &cache
->items
[i
]; *prev
;) {
554 struct brw_cache_item
*c
= *prev
;
556 if (cache
->sws
->bo_references(c
->bo
, bo
)) {
561 for (j
= 0; j
< c
->nr_relocs
; j
++)
562 bo_reference(&c
->relocs
[j
].bo
, NULL
);
564 bo_reference(&c
->bo
, NULL
);
566 FREE((void *)c
->key
);
577 brw_state_cache_check_size(struct brw_context
*brw
)
579 if (BRW_DEBUG
& DEBUG_STATE
)
580 debug_printf("%s (n_items=%d)\n", __FUNCTION__
, brw
->cache
.n_items
);
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.
585 if (brw
->cache
.n_items
> 1000)
586 brw_clear_cache(brw
, &brw
->cache
);
588 if (brw
->surface_cache
.n_items
> 1000)
589 brw_clear_cache(brw
, &brw
->surface_cache
);
594 brw_destroy_cache(struct brw_context
*brw
, struct brw_cache
*cache
)
598 if (BRW_DEBUG
& DEBUG_STATE
)
599 debug_printf("%s\n", __FUNCTION__
);
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
]);
613 brw_destroy_caches(struct brw_context
*brw
)
615 brw_destroy_cache(brw
, &brw
->cache
);
616 brw_destroy_cache(brw
, &brw
->surface_cache
);