trace: Implement separate vertex sampler state.
[mesa.git] / src / gallium / drivers / svga / svga_screen_cache.c
1 /**********************************************************
2 * Copyright 2008-2009 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26 #include "util/u_memory.h"
27
28 #include "svga_debug.h"
29 #include "svga_winsys.h"
30 #include "svga_screen.h"
31 #include "svga_screen_cache.h"
32
33
34 #define SVGA_SURFACE_CACHE_ENABLED 1
35
36
37 /**
38 * Compute the bucket for this key.
39 *
40 * We simply compute log2(width) for now, but
41 */
42 static INLINE unsigned
43 svga_screen_cache_bucket(const struct svga_host_surface_cache_key *key)
44 {
45 unsigned bucket = 0;
46 unsigned size = key->size.width;
47
48 while ((size >>= 1))
49 ++bucket;
50
51 if(key->flags & SVGA3D_SURFACE_HINT_INDEXBUFFER)
52 bucket += 32;
53
54 assert(bucket < SVGA_HOST_SURFACE_CACHE_BUCKETS);
55
56 return bucket;
57 }
58
59
60 static INLINE struct svga_winsys_surface *
61 svga_screen_cache_lookup(struct svga_screen *svgascreen,
62 const struct svga_host_surface_cache_key *key)
63 {
64 struct svga_host_surface_cache *cache = &svgascreen->cache;
65 struct svga_winsys_screen *sws = svgascreen->sws;
66 struct svga_host_surface_cache_entry *entry;
67 struct svga_winsys_surface *handle = NULL;
68 struct list_head *curr, *next;
69 unsigned bucket;
70 unsigned tries = 0;
71
72 bucket = svga_screen_cache_bucket(key);
73
74 pipe_mutex_lock(cache->mutex);
75
76 curr = cache->bucket[bucket].next;
77 next = curr->next;
78 while(curr != &cache->bucket[bucket]) {
79 ++tries;
80
81 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, bucket_head);
82
83 assert(entry->handle);
84
85 if(memcmp(&entry->key, key, sizeof *key) == 0 &&
86 sws->fence_signalled( sws, entry->fence, 0 ) == 0) {
87 assert(sws->surface_is_flushed(sws, entry->handle));
88
89 handle = entry->handle; // Reference is transfered here.
90 entry->handle = NULL;
91
92 LIST_DEL(&entry->bucket_head);
93
94 LIST_DEL(&entry->head);
95
96 LIST_ADD(&entry->head, &cache->empty);
97
98 break;
99 }
100
101 curr = next;
102 next = curr->next;
103 }
104
105 pipe_mutex_unlock(cache->mutex);
106
107 #if 0
108 _debug_printf("%s: cache %s after %u tries\n", __FUNCTION__, handle ? "hit" : "miss", tries);
109 #else
110 (void)tries;
111 #endif
112
113 return handle;
114 }
115
116
117 /*
118 * Transfers a handle reference.
119 */
120
121 static INLINE void
122 svga_screen_cache_add(struct svga_screen *svgascreen,
123 const struct svga_host_surface_cache_key *key,
124 struct svga_winsys_surface **p_handle)
125 {
126 struct svga_host_surface_cache *cache = &svgascreen->cache;
127 struct svga_winsys_screen *sws = svgascreen->sws;
128 struct svga_host_surface_cache_entry *entry = NULL;
129 struct svga_winsys_surface *handle = *p_handle;
130
131
132 assert(handle);
133 if(!handle)
134 return;
135
136 *p_handle = NULL;
137 pipe_mutex_lock(cache->mutex);
138
139 if(!LIST_IS_EMPTY(&cache->empty)) {
140 /* use the first empty entry */
141 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->empty.next, head);
142
143 LIST_DEL(&entry->head);
144 }
145 else if(!LIST_IS_EMPTY(&cache->unused)) {
146 /* free the last used buffer and reuse its entry */
147 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->unused.prev, head);
148 SVGA_DBG(DEBUG_DMA, "unref sid %p\n", entry->handle);
149 sws->surface_reference(sws, &entry->handle, NULL);
150
151 LIST_DEL(&entry->bucket_head);
152
153 LIST_DEL(&entry->head);
154 }
155
156 if(entry) {
157 entry->handle = handle;
158 memcpy(&entry->key, key, sizeof entry->key);
159
160 LIST_ADD(&entry->head, &cache->validated);
161 }
162 else {
163 /* Couldn't cache the buffer -- this really shouldn't happen */
164 SVGA_DBG(DEBUG_DMA, "unref sid %p\n", handle);
165 sws->surface_reference(sws, &handle, NULL);
166 }
167
168 pipe_mutex_unlock(cache->mutex);
169 }
170
171
172 /**
173 * Called during the screen flush to move all buffers not in a validate list
174 * into the unused list.
175 */
176 void
177 svga_screen_cache_flush(struct svga_screen *svgascreen,
178 struct pipe_fence_handle *fence)
179 {
180 struct svga_host_surface_cache *cache = &svgascreen->cache;
181 struct svga_winsys_screen *sws = svgascreen->sws;
182 struct svga_host_surface_cache_entry *entry;
183 struct list_head *curr, *next;
184 unsigned bucket;
185
186 pipe_mutex_lock(cache->mutex);
187
188 curr = cache->validated.next;
189 next = curr->next;
190 while(curr != &cache->validated) {
191 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head);
192
193 assert(entry->handle);
194
195 if(sws->surface_is_flushed(sws, entry->handle)) {
196 LIST_DEL(&entry->head);
197
198 svgascreen->sws->fence_reference(svgascreen->sws, &entry->fence, fence);
199
200 LIST_ADD(&entry->head, &cache->unused);
201
202 bucket = svga_screen_cache_bucket(&entry->key);
203 LIST_ADD(&entry->bucket_head, &cache->bucket[bucket]);
204 }
205
206 curr = next;
207 next = curr->next;
208 }
209
210 pipe_mutex_unlock(cache->mutex);
211 }
212
213
214 void
215 svga_screen_cache_cleanup(struct svga_screen *svgascreen)
216 {
217 struct svga_host_surface_cache *cache = &svgascreen->cache;
218 struct svga_winsys_screen *sws = svgascreen->sws;
219 unsigned i;
220
221 for(i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) {
222 if(cache->entries[i].handle) {
223 SVGA_DBG(DEBUG_DMA, "unref sid %p\n", cache->entries[i].handle);
224 sws->surface_reference(sws, &cache->entries[i].handle, NULL);
225 }
226
227 if(cache->entries[i].fence)
228 svgascreen->sws->fence_reference(svgascreen->sws, &cache->entries[i].fence, NULL);
229 }
230
231 pipe_mutex_destroy(cache->mutex);
232 }
233
234
235 enum pipe_error
236 svga_screen_cache_init(struct svga_screen *svgascreen)
237 {
238 struct svga_host_surface_cache *cache = &svgascreen->cache;
239 unsigned i;
240
241 pipe_mutex_init(cache->mutex);
242
243 for(i = 0; i < SVGA_HOST_SURFACE_CACHE_BUCKETS; ++i)
244 LIST_INITHEAD(&cache->bucket[i]);
245
246 LIST_INITHEAD(&cache->unused);
247
248 LIST_INITHEAD(&cache->validated);
249
250 LIST_INITHEAD(&cache->empty);
251 for(i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i)
252 LIST_ADDTAIL(&cache->entries[i].head, &cache->empty);
253
254 return PIPE_OK;
255 }
256
257
258 struct svga_winsys_surface *
259 svga_screen_surface_create(struct svga_screen *svgascreen,
260 struct svga_host_surface_cache_key *key)
261 {
262 struct svga_winsys_screen *sws = svgascreen->sws;
263 struct svga_winsys_surface *handle = NULL;
264
265 if (SVGA_SURFACE_CACHE_ENABLED && key->format == SVGA3D_BUFFER) {
266 /* round the buffer size up to the nearest power of two to increase the
267 * probability of cache hits */
268 uint32_t size = 1;
269 while(size < key->size.width)
270 size <<= 1;
271 key->size.width = size;
272
273 handle = svga_screen_cache_lookup(svgascreen, key);
274 if (handle)
275 SVGA_DBG(DEBUG_DMA, " reuse sid %p sz %d\n", handle, size);
276 }
277
278 if (!handle) {
279 handle = sws->surface_create(sws,
280 key->flags,
281 key->format,
282 key->size,
283 key->numFaces,
284 key->numMipLevels);
285 if (handle)
286 SVGA_DBG(DEBUG_DMA, "create sid %p sz %d\n", handle, key->size);
287 }
288
289 return handle;
290 }
291
292
293 void
294 svga_screen_surface_destroy(struct svga_screen *svgascreen,
295 const struct svga_host_surface_cache_key *key,
296 struct svga_winsys_surface **p_handle)
297 {
298 struct svga_winsys_screen *sws = svgascreen->sws;
299
300 if(SVGA_SURFACE_CACHE_ENABLED && key->format == SVGA3D_BUFFER) {
301 svga_screen_cache_add(svgascreen, key, p_handle);
302 }
303 else {
304 SVGA_DBG(DEBUG_DMA, "unref sid %p\n", *p_handle);
305 sws->surface_reference(sws, p_handle, NULL);
306 }
307 }