Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / gallium / auxiliary / sct / sct.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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, sub license, 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 portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include "util/u_memory.h"
30 #include "pipe/p_state.h"
31 #include "pipe/p_inlines.h"
32 #include "sct.h"
33
34
35 struct texture_list
36 {
37 struct pipe_texture *texture;
38 struct texture_list *next;
39 };
40
41
42
43 #define MAX_SURFACES ((PIPE_MAX_COLOR_BUFS) + 1)
44
45 struct sct_context
46 {
47 const struct pipe_context *context;
48
49 /** surfaces the context is drawing into */
50 struct pipe_surface *surfaces[MAX_SURFACES];
51
52 /** currently bound textures */
53 struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
54
55 /** previously bound textures, used but not flushed */
56 struct texture_list *textures_used;
57
58 boolean needs_flush;
59
60 struct sct_context *next;
61 };
62
63
64
65 struct sct_surface
66 {
67 const struct pipe_surface *surface;
68
69 /** list of contexts drawing to this surface */
70 struct sct_context_list *contexts;
71
72 struct sct_surface *next;
73 };
74
75
76
77 /**
78 * Find the surface_info for the given pipe_surface
79 */
80 static struct sct_surface *
81 find_surface_info(struct surface_context_tracker *sct,
82 const struct pipe_surface *surface)
83 {
84 struct sct_surface *si;
85 for (si = sct->surfaces; si; si = si->next)
86 if (si->surface == surface)
87 return si;
88 return NULL;
89 }
90
91
92 /**
93 * As above, but create new surface_info if surface is new.
94 */
95 static struct sct_surface *
96 find_create_surface_info(struct surface_context_tracker *sct,
97 const struct pipe_surface *surface)
98 {
99 struct sct_surface *si = find_surface_info(sct, surface);
100 if (si)
101 return si;
102
103 /* alloc new */
104 si = CALLOC_STRUCT(sct_surface);
105 if (si) {
106 si->surface = surface;
107
108 /* insert at head */
109 si->next = sct->surfaces;
110 sct->surfaces = si;
111 }
112
113 return si;
114 }
115
116
117 /**
118 * Find a context_info for the given context.
119 */
120 static struct sct_context *
121 find_context_info(struct surface_context_tracker *sct,
122 const struct pipe_context *context)
123 {
124 struct sct_context *ci;
125 for (ci = sct->contexts; ci; ci = ci->next)
126 if (ci->context == context)
127 return ci;
128 return NULL;
129 }
130
131
132 /**
133 * As above, but create new context_info if context is new.
134 */
135 static struct sct_context *
136 find_create_context_info(struct surface_context_tracker *sct,
137 const struct pipe_context *context)
138 {
139 struct sct_context *ci = find_context_info(sct, context);
140 if (ci)
141 return ci;
142
143 /* alloc new */
144 ci = CALLOC_STRUCT(sct_context);
145 if (ci) {
146 ci->context = context;
147
148 /* insert at head */
149 ci->next = sct->contexts;
150 sct->contexts = ci;
151 }
152
153 return ci;
154 }
155
156
157 /**
158 * Is the context already bound to the surface?
159 */
160 static boolean
161 find_surface_context(const struct sct_surface *si,
162 const struct pipe_context *context)
163 {
164 const struct sct_context_list *cl;
165 for (cl = si->contexts; cl; cl = cl->next) {
166 if (cl->context == context) {
167 return TRUE;
168 }
169 }
170 return FALSE;
171 }
172
173
174 /**
175 * Add a context to the list of contexts associated with a surface.
176 */
177 static void
178 add_context_to_surface(struct sct_surface *si,
179 const struct pipe_context *context)
180 {
181 struct sct_context_list *cl = CALLOC_STRUCT(sct_context_list);
182 if (cl) {
183 cl->context = context;
184 /* insert at head of list of contexts */
185 cl->next = si->contexts;
186 si->contexts = cl;
187 }
188 }
189
190
191 /**
192 * Remove a context from the list of contexts associated with a surface.
193 */
194 static void
195 remove_context_from_surface(struct sct_surface *si,
196 const struct pipe_context *context)
197 {
198 struct sct_context_list *prev = NULL, *curr, *next;
199
200 for (curr = si->contexts; curr; curr = next) {
201 if (curr->context == context) {
202 /* remove */
203 if (prev)
204 prev->next = curr->next;
205 else
206 si->contexts = curr->next;
207 next = curr->next;
208 FREE(curr);
209 }
210 else {
211 prev = curr;
212 next = curr->next;
213 }
214 }
215 }
216
217
218 /**
219 * Unbind context from surface.
220 */
221 static void
222 unbind_context_surface(struct surface_context_tracker *sct,
223 struct pipe_context *context,
224 struct pipe_surface *surface)
225 {
226 struct sct_surface *si = find_surface_info(sct, surface);
227 if (si) {
228 remove_context_from_surface(si, context);
229 }
230 }
231
232
233 /**
234 * Bind context to a set of surfaces (color + Z).
235 * Like MakeCurrent().
236 */
237 void
238 sct_bind_surfaces(struct surface_context_tracker *sct,
239 struct pipe_context *context,
240 uint num_surf,
241 struct pipe_surface **surfaces)
242 {
243 struct sct_context *ci = find_create_context_info(sct, context);
244 uint i;
245
246 if (!ci) {
247 return; /* out of memory */
248 }
249
250 /* unbind currently bound surfaces */
251 for (i = 0; i < MAX_SURFACES; i++) {
252 if (ci->surfaces[i]) {
253 unbind_context_surface(sct, context, ci->surfaces[i]);
254 }
255 }
256
257 /* bind new surfaces */
258 for (i = 0; i < num_surf; i++) {
259 struct sct_surface *si = find_create_surface_info(sct, surfaces[i]);
260 if (!find_surface_context(si, context)) {
261 add_context_to_surface(si, context);
262 }
263 }
264 }
265
266
267 /**
268 * Return list of contexts bound to a surface.
269 */
270 const struct sct_context_list *
271 sct_get_surface_contexts(struct surface_context_tracker *sct,
272 const struct pipe_surface *surface)
273 {
274 const struct sct_surface *si = find_surface_info(sct, surface);
275 return si->contexts;
276 }
277
278
279
280 static boolean
281 find_texture(const struct sct_context *ci,
282 const struct pipe_texture *texture)
283 {
284 const struct texture_list *tl;
285
286 for (tl = ci->textures_used; tl; tl = tl->next) {
287 if (tl->texture == texture) {
288 return TRUE;
289 }
290 }
291 return FALSE;
292 }
293
294
295 /**
296 * Add the given texture to the context's list of used textures.
297 */
298 static void
299 add_texture_used(struct sct_context *ci,
300 struct pipe_texture *texture)
301 {
302 if (!find_texture(ci, texture)) {
303 /* add to list */
304 struct texture_list *tl = CALLOC_STRUCT(texture_list);
305 if (tl) {
306 pipe_texture_reference(&tl->texture, texture);
307 /* insert at head */
308 tl->next = ci->textures_used;
309 ci->textures_used = tl;
310 }
311 }
312 }
313
314
315 /**
316 * Bind a texture to a rendering context.
317 */
318 void
319 sct_bind_texture(struct surface_context_tracker *sct,
320 struct pipe_context *context,
321 uint unit,
322 struct pipe_texture *tex)
323 {
324 struct sct_context *ci = find_context_info(sct, context);
325
326 if (ci->textures[unit] != tex) {
327 /* put texture on the 'used' list */
328 add_texture_used(ci, tex);
329 /* bind new */
330 pipe_texture_reference(&ci->textures[unit], tex);
331 }
332 }
333
334
335 /**
336 * Check if the given texture has been used by the rendering context
337 * since the last call to sct_flush_textures().
338 */
339 boolean
340 sct_is_texture_used(struct surface_context_tracker *sct,
341 const struct pipe_context *context,
342 const struct pipe_texture *texture)
343 {
344 const struct sct_context *ci = find_context_info(sct, context);
345 return find_texture(ci, texture);
346 }
347
348
349 /**
350 * To be called when the image contents of a texture are changed, such
351 * as for gl[Copy]TexSubImage().
352 * XXX this may not be needed
353 */
354 void
355 sct_update_texture(struct pipe_texture *tex)
356 {
357
358 }
359
360
361 /**
362 * When a scene is flushed/rendered we can release the list of
363 * used textures.
364 */
365 void
366 sct_flush_textures(struct surface_context_tracker *sct,
367 struct pipe_context *context)
368 {
369 struct sct_context *ci = find_context_info(sct, context);
370 struct texture_list *tl, *next;
371 uint i;
372
373 for (tl = ci->textures_used; tl; tl = next) {
374 next = tl->next;
375 pipe_texture_release(&tl->texture);
376 FREE(tl);
377 }
378 ci->textures_used = NULL;
379
380 /* put the currently bound textures on the 'used' list */
381 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
382 add_texture_used(ci, ci->textures[i]);
383 }
384 }
385
386
387
388 void
389 sct_destroy_context(struct surface_context_tracker *sct,
390 struct pipe_context *context)
391 {
392 /* XXX should we require an unbinding first? */
393 {
394 struct sct_surface *si;
395 for (si = sct->surfaces; si; si = si->next) {
396 remove_context_from_surface(si, context);
397 }
398 }
399
400 /* remove context from context_info list */
401 {
402 struct sct_context *ci, *next, *prev = NULL;
403 for (ci = sct->contexts; ci; ci = next) {
404 next = ci->next;
405 if (ci->context == context) {
406 if (prev)
407 prev->next = ci->next;
408 else
409 sct->contexts = ci->next;
410 FREE(ci);
411 }
412 else {
413 prev = ci;
414 }
415 }
416 }
417
418 }
419
420
421 void
422 sct_destroy_surface(struct surface_context_tracker *sct,
423 struct pipe_surface *surface)
424 {
425 if (1) {
426 /* debug/sanity: no context should be bound to surface */
427 struct sct_context *ci;
428 uint i;
429 for (ci = sct->contexts; ci; ci = ci->next) {
430 for (i = 0; i < MAX_SURFACES; i++) {
431 assert(ci->surfaces[i] != surface);
432 }
433 }
434 }
435
436 /* remove surface from sct_surface list */
437 {
438 struct sct_surface *si, *next, *prev = NULL;
439 for (si = sct->surfaces; si; si = next) {
440 next = si->next;
441 if (si->surface == surface) {
442 /* unlink */
443 if (prev)
444 prev->next = si->next;
445 else
446 sct->surfaces = si->next;
447 FREE(si);
448 }
449 else {
450 prev = si;
451 }
452 }
453 }
454 }