• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3  Intel funded Tungsten Graphics 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 <keithw@vmware.com>
30   */
31 
32 /** @file brw_program_cache.c
33  *
34  * This file implements a simple program cache for 965.  The consumers can
35  *  query the hash table of programs using a cache_id and program key, and
36  * receive the corresponding program buffer object (plus associated auxiliary
37  *  data) in return.  Objects in the cache may not have relocations
38  * (pointers to other BOs) in them.
39  *
40  * The inner workings are a simple hash table based on a FNV-1a of the
41  * key data.
42  *
43  * Replacement is not implemented.  Instead, when the cache gets too
44  * big we throw out all of the cache data and let it get regenerated.
45  */
46 
47 #include "main/streaming-load-memcpy.h"
48 #include "x86/common_x86_asm.h"
49 #include "brw_batch.h"
50 #include "brw_state.h"
51 #include "brw_wm.h"
52 #include "brw_gs.h"
53 #include "brw_cs.h"
54 #include "brw_program.h"
55 #include "compiler/brw_eu.h"
56 #include "util/u_memory.h"
57 #define XXH_INLINE_ALL
58 #include "util/xxhash.h"
59 
60 #define FILE_DEBUG_FLAG DEBUG_STATE
61 
62 struct brw_cache_item {
63    /**
64     * Effectively part of the key, cache_id identifies what kind of state
65     * buffer is involved, and also which dirty flag should set.
66     */
67    enum brw_cache_id cache_id;
68 
69    /** 32-bit hash of the key data */
70    GLuint hash;
71 
72    /** for variable-sized keys */
73    GLuint key_size;
74    GLuint prog_data_size;
75    const struct brw_base_prog_key *key;
76 
77    uint32_t offset;
78    uint32_t size;
79 
80    struct brw_cache_item *next;
81 };
82 
83 enum brw_cache_id
brw_stage_cache_id(gl_shader_stage stage)84 brw_stage_cache_id(gl_shader_stage stage)
85 {
86    static const enum brw_cache_id stage_ids[] = {
87       BRW_CACHE_VS_PROG,
88       BRW_CACHE_TCS_PROG,
89       BRW_CACHE_TES_PROG,
90       BRW_CACHE_GS_PROG,
91       BRW_CACHE_FS_PROG,
92       BRW_CACHE_CS_PROG,
93    };
94    assert((int)stage >= 0 && stage < ARRAY_SIZE(stage_ids));
95    return stage_ids[stage];
96 }
97 
98 static GLuint
hash_key(struct brw_cache_item * item)99 hash_key(struct brw_cache_item *item)
100 {
101     uint32_t hash = 0;
102     hash = XXH32(&item->cache_id, sizeof(item->cache_id), hash);
103     hash = XXH32(item->key, item->key_size, hash);
104 
105    return hash;
106 }
107 
108 static int
brw_cache_item_equals(const struct brw_cache_item * a,const struct brw_cache_item * b)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 }
117 
118 static struct brw_cache_item *
search_cache(struct brw_cache * cache,GLuint hash,struct brw_cache_item * lookup)119 search_cache(struct brw_cache *cache, GLuint hash,
120              struct brw_cache_item *lookup)
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    fprintf(stderr, "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 (brw_cache_item_equals(lookup, c))
136          return c;
137    }
138 
139    return NULL;
140 }
141 
142 
143 static void
rehash(struct brw_cache * cache)144 rehash(struct brw_cache *cache)
145 {
146    struct brw_cache_item **items;
147    struct brw_cache_item *c, *next;
148    GLuint size, i;
149 
150    size = cache->size * 3;
151    items = calloc(size, sizeof(*items));
152 
153    for (i = 0; i < cache->size; i++)
154       for (c = cache->items[i]; c; c = next) {
155          next = c->next;
156          c->next = items[c->hash % size];
157          items[c->hash % size] = c;
158       }
159 
160    free(cache->items);
161    cache->items = items;
162    cache->size = size;
163 }
164 
165 
166 /**
167  * Returns the buffer object matching cache_id and key, or NULL.
168  */
169 bool
brw_search_cache(struct brw_cache * cache,enum brw_cache_id cache_id,const void * key,GLuint key_size,uint32_t * inout_offset,void * inout_prog_data,bool flag_state)170 brw_search_cache(struct brw_cache *cache, enum brw_cache_id cache_id,
171                  const void *key, GLuint key_size, uint32_t *inout_offset,
172                  void *inout_prog_data, bool flag_state)
173 {
174    struct brw_cache_item *item;
175    struct brw_cache_item lookup;
176    GLuint hash;
177 
178    lookup.cache_id = cache_id;
179    lookup.key = key;
180    lookup.key_size = key_size;
181    hash = hash_key(&lookup);
182    lookup.hash = hash;
183 
184    item = search_cache(cache, hash, &lookup);
185 
186    if (item == NULL)
187       return false;
188 
189    void *prog_data = ((char *) item->key) + item->key_size;
190 
191    if (item->offset != *inout_offset ||
192        prog_data != *((void **) inout_prog_data)) {
193       if (likely(flag_state))
194          cache->brw->ctx.NewDriverState |= (1 << cache_id);
195       *inout_offset = item->offset;
196       *((void **) inout_prog_data) = prog_data;
197    }
198 
199    return true;
200 }
201 
202 static void
brw_cache_new_bo(struct brw_cache * cache,uint32_t new_size)203 brw_cache_new_bo(struct brw_cache *cache, uint32_t new_size)
204 {
205    struct brw_context *brw = cache->brw;
206    struct brw_bo *new_bo;
207 
208    perf_debug("Copying to larger program cache: %u kB -> %u kB\n",
209               (unsigned) cache->bo->size / 1024, new_size / 1024);
210 
211    new_bo = brw_bo_alloc(brw->bufmgr, "program cache", new_size,
212                          BRW_MEMZONE_SHADER);
213    if (can_do_exec_capture(brw->screen))
214       new_bo->kflags |= EXEC_OBJECT_CAPTURE;
215 
216    void *map = brw_bo_map(brw, new_bo, MAP_READ | MAP_WRITE |
217                                        MAP_ASYNC | MAP_PERSISTENT);
218 
219    /* Copy any existing data that needs to be saved. */
220    if (cache->next_offset != 0) {
221 #ifdef USE_SSE41
222       if (!cache->bo->cache_coherent && cpu_has_sse4_1)
223          _mesa_streaming_load_memcpy(map, cache->map, cache->next_offset);
224       else
225 #endif
226          memcpy(map, cache->map, cache->next_offset);
227    }
228 
229    brw_bo_unmap(cache->bo);
230    brw_bo_unreference(cache->bo);
231    cache->bo = new_bo;
232    cache->map = map;
233 
234    /* Since we have a new BO in place, we need to signal the units
235     * that depend on it (state base address on gfx5+, or unit state before).
236     */
237    brw->ctx.NewDriverState |= BRW_NEW_PROGRAM_CACHE;
238    brw->batch.state_base_address_emitted = false;
239 }
240 
241 /**
242  * Attempts to find an item in the cache with identical data.
243  */
244 static const struct brw_cache_item *
brw_lookup_prog(const struct brw_cache * cache,enum brw_cache_id cache_id,const void * data,unsigned data_size)245 brw_lookup_prog(const struct brw_cache *cache,
246                 enum brw_cache_id cache_id,
247                 const void *data, unsigned data_size)
248 {
249    unsigned i;
250    const struct brw_cache_item *item;
251 
252    for (i = 0; i < cache->size; i++) {
253       for (item = cache->items[i]; item; item = item->next) {
254          if (item->cache_id != cache_id || item->size != data_size ||
255              memcmp(cache->map + item->offset, data, item->size) != 0)
256             continue;
257 
258          return item;
259       }
260    }
261 
262    return NULL;
263 }
264 
265 static uint32_t
brw_alloc_item_data(struct brw_cache * cache,uint32_t size)266 brw_alloc_item_data(struct brw_cache *cache, uint32_t size)
267 {
268    uint32_t offset;
269 
270    /* Allocate space in the cache BO for our new program. */
271    if (cache->next_offset + size > cache->bo->size) {
272       uint32_t new_size = cache->bo->size * 2;
273 
274       while (cache->next_offset + size > new_size)
275          new_size *= 2;
276 
277       brw_cache_new_bo(cache, new_size);
278    }
279 
280    offset = cache->next_offset;
281 
282    /* Programs are always 64-byte aligned, so set up the next one now */
283    cache->next_offset = ALIGN(offset + size, 64);
284 
285    return offset;
286 }
287 
288 const void *
brw_find_previous_compile(struct brw_cache * cache,enum brw_cache_id cache_id,unsigned program_string_id)289 brw_find_previous_compile(struct brw_cache *cache,
290                           enum brw_cache_id cache_id,
291                           unsigned program_string_id)
292 {
293    for (unsigned i = 0; i < cache->size; i++) {
294       for (struct brw_cache_item *c = cache->items[i]; c; c = c->next) {
295          if (c->cache_id == cache_id &&
296              c->key->program_string_id == program_string_id) {
297             return c->key;
298          }
299       }
300    }
301 
302    return NULL;
303 }
304 
305 void
brw_upload_cache(struct brw_cache * cache,enum brw_cache_id cache_id,const void * key,GLuint key_size,const void * data,GLuint data_size,const void * prog_data,GLuint prog_data_size,uint32_t * out_offset,void * out_prog_data)306 brw_upload_cache(struct brw_cache *cache,
307                  enum brw_cache_id cache_id,
308                  const void *key,
309                  GLuint key_size,
310                  const void *data,
311                  GLuint data_size,
312                  const void *prog_data,
313                  GLuint prog_data_size,
314                  uint32_t *out_offset,
315                  void *out_prog_data)
316 {
317    struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
318    const struct brw_cache_item *matching_data =
319       brw_lookup_prog(cache, cache_id, data, data_size);
320    GLuint hash;
321    void *tmp;
322 
323    item->cache_id = cache_id;
324    item->size = data_size;
325    item->key = key;
326    item->key_size = key_size;
327    item->prog_data_size = prog_data_size;
328    hash = hash_key(item);
329    item->hash = hash;
330 
331    /* If we can find a matching prog in the cache already, then reuse the
332     * existing stuff without creating new copy into the underlying buffer
333     * object. This is notably useful for programs generating shaders at
334     * runtime, where multiple shaders may compile to the same thing in our
335     * backend.
336     */
337    if (matching_data) {
338       item->offset = matching_data->offset;
339    } else {
340       item->offset = brw_alloc_item_data(cache, data_size);
341 
342       /* Copy data to the buffer */
343       memcpy(cache->map + item->offset, data, data_size);
344    }
345 
346    /* Set up the memory containing the key and prog_data */
347    tmp = malloc(key_size + prog_data_size);
348 
349    memcpy(tmp, key, key_size);
350    memcpy(tmp + key_size, prog_data, prog_data_size);
351 
352    item->key = tmp;
353 
354    if (cache->n_items > cache->size * 1.5f)
355       rehash(cache);
356 
357    hash %= cache->size;
358    item->next = cache->items[hash];
359    cache->items[hash] = item;
360    cache->n_items++;
361 
362    *out_offset = item->offset;
363    *(void **)out_prog_data = (void *)((char *)item->key + item->key_size);
364    cache->brw->ctx.NewDriverState |= 1 << cache_id;
365 }
366 
367 void
brw_init_caches(struct brw_context * brw)368 brw_init_caches(struct brw_context *brw)
369 {
370    struct brw_cache *cache = &brw->cache;
371 
372    cache->brw = brw;
373 
374    cache->size = 7;
375    cache->n_items = 0;
376    cache->items =
377       calloc(cache->size, sizeof(struct brw_cache_item *));
378 
379    cache->bo = brw_bo_alloc(brw->bufmgr, "program cache", 16384,
380                             BRW_MEMZONE_SHADER);
381    if (can_do_exec_capture(brw->screen))
382       cache->bo->kflags |= EXEC_OBJECT_CAPTURE;
383 
384    cache->map = brw_bo_map(brw, cache->bo, MAP_READ | MAP_WRITE |
385                                            MAP_ASYNC | MAP_PERSISTENT);
386 }
387 
388 static void
brw_clear_cache(struct brw_context * brw,struct brw_cache * cache)389 brw_clear_cache(struct brw_context *brw, struct brw_cache *cache)
390 {
391    struct brw_cache_item *c, *next;
392    GLuint i;
393 
394    DBG("%s\n", __func__);
395 
396    for (i = 0; i < cache->size; i++) {
397       for (c = cache->items[i]; c; c = next) {
398          next = c->next;
399          if (c->cache_id == BRW_CACHE_VS_PROG ||
400              c->cache_id == BRW_CACHE_TCS_PROG ||
401              c->cache_id == BRW_CACHE_TES_PROG ||
402              c->cache_id == BRW_CACHE_GS_PROG ||
403              c->cache_id == BRW_CACHE_FS_PROG ||
404              c->cache_id == BRW_CACHE_CS_PROG) {
405             const void *item_prog_data = ((char *)c->key) + c->key_size;
406             brw_stage_prog_data_free(item_prog_data);
407          }
408          free((void *)c->key);
409          free(c);
410       }
411       cache->items[i] = NULL;
412    }
413 
414    cache->n_items = 0;
415 
416    /* Start putting programs into the start of the BO again, since
417     * we'll never find the old results.
418     */
419    cache->next_offset = 0;
420 
421    /* We need to make sure that the programs get regenerated, since
422     * any offsets leftover in brw_context will no longer be valid.
423     */
424    brw->NewGLState = ~0;
425    brw->ctx.NewDriverState = ~0ull;
426    brw->state.pipelines[BRW_RENDER_PIPELINE].mesa = ~0;
427    brw->state.pipelines[BRW_RENDER_PIPELINE].brw = ~0ull;
428    brw->state.pipelines[BRW_COMPUTE_PIPELINE].mesa = ~0;
429    brw->state.pipelines[BRW_COMPUTE_PIPELINE].brw = ~0ull;
430 
431    /* Also, NULL out any stale program pointers. */
432    brw->vs.base.prog_data = NULL;
433    brw->tcs.base.prog_data = NULL;
434    brw->tes.base.prog_data = NULL;
435    brw->gs.base.prog_data = NULL;
436    brw->wm.base.prog_data = NULL;
437    brw->cs.base.prog_data = NULL;
438 
439    brw_batch_flush(brw);
440 }
441 
442 void
brw_program_cache_check_size(struct brw_context * brw)443 brw_program_cache_check_size(struct brw_context *brw)
444 {
445    /* un-tuned guess.  Each object is generally a page, so 2000 of them is 8 MB of
446     * state cache.
447     */
448    if (brw->cache.n_items > 2000) {
449       perf_debug("Exceeded state cache size limit.  Clearing the set "
450                  "of compiled programs, which will trigger recompiles\n");
451       brw_clear_cache(brw, &brw->cache);
452       brw_cache_new_bo(&brw->cache, brw->cache.bo->size);
453    }
454 }
455 
456 
457 static void
brw_destroy_cache(struct brw_context * brw,struct brw_cache * cache)458 brw_destroy_cache(struct brw_context *brw, struct brw_cache *cache)
459 {
460 
461    DBG("%s\n", __func__);
462 
463    /* This can be NULL if context creation failed early on */
464    if (cache->bo) {
465       brw_bo_unmap(cache->bo);
466       brw_bo_unreference(cache->bo);
467       cache->bo = NULL;
468       cache->map = NULL;
469    }
470    brw_clear_cache(brw, cache);
471    free(cache->items);
472    cache->items = NULL;
473    cache->size = 0;
474 }
475 
476 
477 void
brw_destroy_caches(struct brw_context * brw)478 brw_destroy_caches(struct brw_context *brw)
479 {
480    brw_destroy_cache(brw, &brw->cache);
481 }
482 
483 static const char *
cache_name(enum brw_cache_id cache_id)484 cache_name(enum brw_cache_id cache_id)
485 {
486    switch (cache_id) {
487    case BRW_CACHE_VS_PROG:
488       return "VS kernel";
489    case BRW_CACHE_TCS_PROG:
490       return "TCS kernel";
491    case BRW_CACHE_TES_PROG:
492       return "TES kernel";
493    case BRW_CACHE_FF_GS_PROG:
494       return "Fixed-function GS kernel";
495    case BRW_CACHE_GS_PROG:
496       return "GS kernel";
497    case BRW_CACHE_CLIP_PROG:
498       return "CLIP kernel";
499    case BRW_CACHE_SF_PROG:
500       return "SF kernel";
501    case BRW_CACHE_FS_PROG:
502       return "FS kernel";
503    case BRW_CACHE_CS_PROG:
504       return "CS kernel";
505    default:
506       return "unknown";
507    }
508 }
509 
510 void
brw_print_program_cache(struct brw_context * brw)511 brw_print_program_cache(struct brw_context *brw)
512 {
513    const struct brw_cache *cache = &brw->cache;
514    struct brw_cache_item *item;
515 
516    for (unsigned i = 0; i < cache->size; i++) {
517       for (item = cache->items[i]; item; item = item->next) {
518          fprintf(stderr, "%s:\n", cache_name(i));
519          brw_disassemble_with_labels(&brw->screen->devinfo, cache->map,
520                                      item->offset, item->size, stderr);
521       }
522    }
523 }
524