Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / mesa / drivers / dri / 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_buf pointers 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
59 #include "main/imports.h"
60 #include "brw_state.h"
61 #include "intel_batchbuffer.h"
62 #include "brw_wm.h"
63
64 #define FILE_DEBUG_FLAG DEBUG_STATE
65
66 static GLuint
67 hash_key(struct brw_cache_item *item)
68 {
69 GLuint *ikey = (GLuint *)item->key;
70 GLuint hash = item->cache_id, i;
71
72 assert(item->key_size % 4 == 0);
73
74 /* I'm sure this can be improved on:
75 */
76 for (i = 0; i < item->key_size/4; i++) {
77 hash ^= ikey[i];
78 hash = (hash << 5) | (hash >> 27);
79 }
80
81 /* Include the BO pointers as key data as well */
82 ikey = (GLuint *)item->reloc_bufs;
83 for (i = 0; i < item->nr_reloc_bufs * sizeof(drm_intel_bo *) / 4; i++) {
84 hash ^= ikey[i];
85 hash = (hash << 5) | (hash >> 27);
86 }
87
88 return hash;
89 }
90
91
92 /**
93 * Marks a new buffer as being chosen for the given cache id.
94 */
95 static void
96 update_cache_last(struct brw_cache *cache, enum brw_cache_id cache_id,
97 drm_intel_bo *bo)
98 {
99 if (bo == cache->last_bo[cache_id])
100 return; /* no change */
101
102 drm_intel_bo_unreference(cache->last_bo[cache_id]);
103 cache->last_bo[cache_id] = bo;
104 drm_intel_bo_reference(cache->last_bo[cache_id]);
105 cache->brw->state.dirty.cache |= 1 << cache_id;
106 }
107
108 static int
109 brw_cache_item_equals(const struct brw_cache_item *a,
110 const struct brw_cache_item *b)
111 {
112 return a->cache_id == b->cache_id &&
113 a->hash == b->hash &&
114 a->key_size == b->key_size &&
115 (memcmp(a->key, b->key, a->key_size) == 0) &&
116 a->nr_reloc_bufs == b->nr_reloc_bufs &&
117 (memcmp(a->reloc_bufs, b->reloc_bufs,
118 a->nr_reloc_bufs * sizeof(drm_intel_bo *)) == 0);
119 }
120
121 static struct brw_cache_item *
122 search_cache(struct brw_cache *cache, GLuint hash,
123 struct brw_cache_item *lookup)
124 {
125 struct brw_cache_item *c;
126
127 #if 0
128 int bucketcount = 0;
129
130 for (c = cache->items[hash % cache->size]; c; c = c->next)
131 bucketcount++;
132
133 fprintf(stderr, "bucket %d/%d = %d/%d items\n", hash % cache->size,
134 cache->size, bucketcount, cache->n_items);
135 #endif
136
137 for (c = cache->items[hash % cache->size]; c; c = c->next) {
138 if (brw_cache_item_equals(lookup, c))
139 return c;
140 }
141
142 return NULL;
143 }
144
145
146 static void
147 rehash(struct brw_cache *cache)
148 {
149 struct brw_cache_item **items;
150 struct brw_cache_item *c, *next;
151 GLuint size, i;
152
153 size = cache->size * 3;
154 items = (struct brw_cache_item**) calloc(1, size * sizeof(*items));
155
156 for (i = 0; i < cache->size; i++)
157 for (c = cache->items[i]; c; c = next) {
158 next = c->next;
159 c->next = items[c->hash % size];
160 items[c->hash % size] = c;
161 }
162
163 FREE(cache->items);
164 cache->items = items;
165 cache->size = size;
166 }
167
168
169 /**
170 * Returns the buffer object matching cache_id and key, or NULL.
171 */
172 drm_intel_bo *
173 brw_search_cache(struct brw_cache *cache,
174 enum brw_cache_id cache_id,
175 const void *key,
176 GLuint key_size,
177 drm_intel_bo **reloc_bufs, GLuint nr_reloc_bufs,
178 void *aux_return)
179 {
180 struct brw_cache_item *item;
181 struct brw_cache_item lookup;
182 GLuint hash;
183
184 lookup.cache_id = cache_id;
185 lookup.key = key;
186 lookup.key_size = key_size;
187 lookup.reloc_bufs = reloc_bufs;
188 lookup.nr_reloc_bufs = nr_reloc_bufs;
189 hash = hash_key(&lookup);
190 lookup.hash = hash;
191
192 item = search_cache(cache, hash, &lookup);
193
194 if (item == NULL)
195 return NULL;
196
197 if (aux_return)
198 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
199
200 update_cache_last(cache, cache_id, item->bo);
201
202 drm_intel_bo_reference(item->bo);
203 return item->bo;
204 }
205
206
207 drm_intel_bo *
208 brw_upload_cache_with_auxdata(struct brw_cache *cache,
209 enum brw_cache_id cache_id,
210 const void *key,
211 GLuint key_size,
212 drm_intel_bo **reloc_bufs,
213 GLuint nr_reloc_bufs,
214 const void *data,
215 GLuint data_size,
216 const void *aux,
217 GLuint aux_size,
218 void *aux_return)
219 {
220 struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
221 GLuint hash;
222 GLuint relocs_size = nr_reloc_bufs * sizeof(drm_intel_bo *);
223 void *tmp;
224 drm_intel_bo *bo;
225 int i;
226
227 item->cache_id = cache_id;
228 item->key = key;
229 item->key_size = key_size;
230 item->reloc_bufs = reloc_bufs;
231 item->nr_reloc_bufs = nr_reloc_bufs;
232 hash = hash_key(item);
233 item->hash = hash;
234
235 /* Create the buffer object to contain the data */
236 bo = drm_intel_bo_alloc(cache->brw->intel.bufmgr,
237 cache->name[cache_id], data_size, 1 << 6);
238
239
240 /* Set up the memory containing the key, aux_data, and reloc_bufs */
241 tmp = malloc(key_size + aux_size + relocs_size);
242
243 memcpy(tmp, key, key_size);
244 memcpy(tmp + key_size, aux, aux_size);
245 memcpy(tmp + key_size + aux_size, reloc_bufs, relocs_size);
246 for (i = 0; i < nr_reloc_bufs; i++) {
247 if (reloc_bufs[i] != NULL)
248 drm_intel_bo_reference(reloc_bufs[i]);
249 }
250
251 item->key = tmp;
252 item->reloc_bufs = tmp + key_size + aux_size;
253
254 item->bo = bo;
255 drm_intel_bo_reference(bo);
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 *(void **)aux_return = (void *)((char *)item->key + item->key_size);
267 }
268
269 DBG("upload %s: %d bytes to cache id %d\n",
270 cache->name[cache_id],
271 data_size, cache_id);
272
273 /* Copy data to the buffer */
274 drm_intel_bo_subdata(bo, 0, data_size, data);
275
276 update_cache_last(cache, cache_id, bo);
277
278 return bo;
279 }
280
281 drm_intel_bo *
282 brw_upload_cache(struct brw_cache *cache,
283 enum brw_cache_id cache_id,
284 const void *key,
285 GLuint key_size,
286 drm_intel_bo **reloc_bufs,
287 GLuint nr_reloc_bufs,
288 const void *data,
289 GLuint data_size)
290 {
291 return brw_upload_cache_with_auxdata(cache, cache_id,
292 key, key_size,
293 reloc_bufs, nr_reloc_bufs,
294 data, data_size,
295 NULL, 0,
296 NULL);
297 }
298
299 /**
300 * Wrapper around brw_cache_data_sz using the cache_id's canonical key size.
301 *
302 * If nr_reloc_bufs is nonzero, brw_search_cache()/brw_upload_cache() would be
303 * better to use, as the potentially changing offsets in the data-used-as-key
304 * will result in excessive cache misses.
305 *
306 * If aux data is involved, use search/upload instead.
307
308 */
309 drm_intel_bo *
310 brw_cache_data(struct brw_cache *cache,
311 enum brw_cache_id cache_id,
312 const void *data,
313 GLuint data_size)
314 {
315 drm_intel_bo *bo;
316 struct brw_cache_item *item, lookup;
317 GLuint hash;
318
319 lookup.cache_id = cache_id;
320 lookup.key = data;
321 lookup.key_size = data_size;
322 lookup.reloc_bufs = NULL;
323 lookup.nr_reloc_bufs = 0;
324 hash = hash_key(&lookup);
325 lookup.hash = hash;
326
327 item = search_cache(cache, hash, &lookup);
328 if (item) {
329 update_cache_last(cache, cache_id, item->bo);
330 drm_intel_bo_reference(item->bo);
331 return item->bo;
332 }
333
334 bo = brw_upload_cache(cache, cache_id,
335 data, data_size,
336 NULL, 0,
337 data, data_size);
338
339 return bo;
340 }
341
342 enum pool_type {
343 DW_SURFACE_STATE,
344 DW_GENERAL_STATE
345 };
346
347
348 static void
349 brw_init_cache_id(struct brw_cache *cache,
350 const char *name,
351 enum brw_cache_id id)
352 {
353 cache->name[id] = strdup(name);
354 }
355
356
357 static void
358 brw_init_non_surface_cache(struct brw_context *brw)
359 {
360 struct brw_cache *cache = &brw->cache;
361
362 cache->brw = brw;
363
364 cache->size = 7;
365 cache->n_items = 0;
366 cache->items = (struct brw_cache_item **)
367 calloc(1, cache->size * sizeof(struct brw_cache_item));
368
369 brw_init_cache_id(cache, "CC_VP", BRW_CC_VP);
370 brw_init_cache_id(cache, "CC_UNIT", BRW_CC_UNIT);
371 brw_init_cache_id(cache, "WM_PROG", BRW_WM_PROG);
372 brw_init_cache_id(cache, "SAMPLER_DEFAULT_COLOR", BRW_SAMPLER_DEFAULT_COLOR);
373 brw_init_cache_id(cache, "SAMPLER", BRW_SAMPLER);
374 brw_init_cache_id(cache, "WM_UNIT", BRW_WM_UNIT);
375 brw_init_cache_id(cache, "SF_PROG", BRW_SF_PROG);
376 brw_init_cache_id(cache, "SF_VP", BRW_SF_VP);
377
378 brw_init_cache_id(cache, "SF_UNIT", BRW_SF_UNIT);
379
380 brw_init_cache_id(cache, "VS_UNIT", BRW_VS_UNIT);
381
382 brw_init_cache_id(cache, "VS_PROG", BRW_VS_PROG);
383
384 brw_init_cache_id(cache, "CLIP_UNIT", BRW_CLIP_UNIT);
385
386 brw_init_cache_id(cache, "CLIP_PROG", BRW_CLIP_PROG);
387 brw_init_cache_id(cache, "CLIP_VP", BRW_CLIP_VP);
388
389 brw_init_cache_id(cache, "GS_UNIT", BRW_GS_UNIT);
390
391 brw_init_cache_id(cache, "GS_PROG", BRW_GS_PROG);
392 brw_init_cache_id(cache, "BLEND_STATE", BRW_BLEND_STATE);
393 brw_init_cache_id(cache, "COLOR_CALC_STATE", BRW_COLOR_CALC_STATE);
394 brw_init_cache_id(cache, "DEPTH_STENCIL_STATE", BRW_DEPTH_STENCIL_STATE);
395 }
396
397 void
398 brw_init_caches(struct brw_context *brw)
399 {
400 brw_init_non_surface_cache(brw);
401 }
402
403
404 static void
405 brw_clear_cache(struct brw_context *brw, struct brw_cache *cache)
406 {
407 struct brw_cache_item *c, *next;
408 GLuint i;
409
410 DBG("%s\n", __FUNCTION__);
411
412 for (i = 0; i < cache->size; i++) {
413 for (c = cache->items[i]; c; c = next) {
414 int j;
415
416 next = c->next;
417 for (j = 0; j < c->nr_reloc_bufs; j++)
418 drm_intel_bo_unreference(c->reloc_bufs[j]);
419 drm_intel_bo_unreference(c->bo);
420 free((void *)c->key);
421 free(c);
422 }
423 cache->items[i] = NULL;
424 }
425
426 cache->n_items = 0;
427
428 brw->state.dirty.mesa |= ~0;
429 brw->state.dirty.brw |= ~0;
430 brw->state.dirty.cache |= ~0;
431 }
432
433 void
434 brw_state_cache_check_size(struct brw_context *brw)
435 {
436 DBG("%s (n_items=%d)\n", __FUNCTION__, brw->cache.n_items);
437
438 /* un-tuned guess. Each object is generally a page, so 1000 of them is 4 MB of
439 * state cache.
440 */
441 if (brw->cache.n_items > 1000)
442 brw_clear_cache(brw, &brw->cache);
443 }
444
445
446 static void
447 brw_destroy_cache(struct brw_context *brw, struct brw_cache *cache)
448 {
449 GLuint i;
450
451 DBG("%s\n", __FUNCTION__);
452
453 brw_clear_cache(brw, cache);
454 for (i = 0; i < BRW_MAX_CACHE; i++) {
455 drm_intel_bo_unreference(cache->last_bo[i]);
456 free(cache->name[i]);
457 }
458 free(cache->items);
459 cache->items = NULL;
460 cache->size = 0;
461 }
462
463
464 void
465 brw_destroy_caches(struct brw_context *brw)
466 {
467 brw_destroy_cache(brw, &brw->cache);
468 }