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