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