Tizen 2.0 Release
[profile/ivi/osmesa.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
63 /* XXX: Fixme - have to include these to get the sizes of the prog_key
64  * structs:
65  */
66 #include "brw_wm.h"
67 #include "brw_vs.h"
68 #include "brw_clip.h"
69 #include "brw_sf.h"
70 #include "brw_gs.h"
71
72
73 static GLuint
74 hash_key(const void *key, GLuint key_size,
75          struct brw_winsys_reloc *relocs, GLuint nr_relocs)
76 {
77    GLuint *ikey = (GLuint *)key;
78    GLuint hash = 0, i;
79
80    assert(key_size % 4 == 0);
81
82    /* I'm sure this can be improved on:
83     */
84    for (i = 0; i < key_size/4; i++) {
85       hash ^= ikey[i];
86       hash = (hash << 5) | (hash >> 27);
87    }
88
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++) {
93       hash ^= ikey[i];
94       hash = (hash << 5) | (hash >> 27);
95    }
96
97    return hash;
98 }
99
100
101 /**
102  * Marks a new buffer as being chosen for the given cache id.
103  */
104 static void
105 update_cache_last(struct brw_cache *cache, enum brw_cache_id cache_id,
106                   struct brw_winsys_buffer *bo)
107 {
108    if (bo == cache->last_bo[cache_id])
109       return; /* no change */
110
111    bo_reference( &cache->last_bo[cache_id],  bo );
112
113    cache->brw->state.dirty.cache |= 1 << cache_id;
114 }
115
116
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)
121 {
122    struct brw_cache_item *c;
123
124 #if 0
125    int bucketcount = 0;
126
127    for (c = cache->items[hash % cache->size]; c; c = c->next)
128       bucketcount++;
129
130    debug_printf("bucket %d/%d = %d/%d items\n", hash % cache->size,
131            cache->size, bucketcount, cache->n_items);
132 #endif
133
134    for (c = cache->items[hash % cache->size]; c; c = c->next) {
135       if (c->cache_id == cache_id &&
136           c->hash == hash &&
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)
141          return c;
142    }
143
144    return NULL;
145 }
146
147
148 static void
149 rehash(struct brw_cache *cache)
150 {
151    struct brw_cache_item **items;
152    struct brw_cache_item *c, *next;
153    GLuint size, i;
154
155    size = cache->size * 3;
156    items = (struct brw_cache_item**) CALLOC(size, sizeof(*items));
157
158    for (i = 0; i < cache->size; i++)
159       for (c = cache->items[i]; c; c = next) {
160          next = c->next;
161          c->next = items[c->hash % size];
162          items[c->hash % size] = c;
163       }
164
165    FREE(cache->items);
166    cache->items = items;
167    cache->size = size;
168 }
169
170
171 /**
172  * Returns the buffer object matching cache_id and key, or NULL.
173  */
174 boolean
175 brw_search_cache(struct brw_cache *cache,
176                  enum brw_cache_id cache_id,
177                  const void *key,
178                  GLuint key_size,
179                  struct brw_winsys_reloc *relocs, 
180                  GLuint nr_relocs,
181                  void *aux_return,
182                  struct brw_winsys_buffer **bo_out)
183 {
184    struct brw_cache_item *item;
185    GLuint hash = hash_key(key, key_size, relocs, nr_relocs);
186
187    item = search_cache(cache, cache_id, hash, key, key_size,
188                        relocs, nr_relocs);
189
190    if (item) {
191       if (aux_return)
192          *(void **)aux_return = (void *)((char *)item->key + item->key_size);
193       
194       update_cache_last(cache, cache_id, item->bo);
195       bo_reference(bo_out, item->bo);
196       return TRUE;
197    }
198    
199    return FALSE;      
200 }
201
202
203 enum pipe_error
204 brw_upload_cache( struct brw_cache *cache,
205                   enum brw_cache_id cache_id,
206                   const void *key,
207                   GLuint key_size,
208                   struct brw_winsys_reloc *relocs,
209                   GLuint nr_relocs,
210                   const void *data,
211                   GLuint data_size,
212                   const void *aux,
213                   void *aux_return,
214                   struct brw_winsys_buffer **bo_out)
215 {
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];
220    enum pipe_error ret;
221    void *tmp;
222    int i;
223
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.
228     */
229    ret = cache->sws->bo_alloc(cache->sws,
230                               cache->buffer_type,
231                               data_size, 1 << 6, 
232                               bo_out);
233    if (ret)
234       return ret;
235
236    item = CALLOC_STRUCT(brw_cache_item);
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 }