gallium: added new u_draw_quad.c and u_gen_mipmap.c files.
[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 "pipe/p_util.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 }
213 }
214 }
215
216
217 /**
218 * Unbind context from surface.
219 */
220 static void
221 unbind_context_surface(struct surface_context_tracker *sct,
222 struct pipe_context *context,
223 struct pipe_surface *surface)
224 {
225 struct sct_surface *si = find_surface_info(sct, surface);
226 if (si) {
227 remove_context_from_surface(si, context);
228 }
229 }
230
231
232 /**
233 * Bind context to a set of surfaces (color + Z).
234 * Like MakeCurrent().
235 */
236 void
237 sct_bind_surfaces(struct surface_context_tracker *sct,
238 struct pipe_context *context,
239 uint num_surf,
240 struct pipe_surface **surfaces)
241 {
242 struct sct_context *ci = find_create_context_info(sct, context);
243 uint i;
244
245 if (!ci) {
246 return; /* out of memory */
247 }
248
249 /* unbind currently bound surfaces */
250 for (i = 0; i < MAX_SURFACES; i++) {
251 if (ci->surfaces[i]) {
252 unbind_context_surface(sct, context, ci->surfaces[i]);
253 }
254 }
255
256 /* bind new surfaces */
257 for (i = 0; i < num_surf; i++) {
258 struct sct_surface *si = find_create_surface_info(sct, surfaces[i]);
259 if (!find_surface_context(si, context)) {
260 add_context_to_surface(si, context);
261 }
262 }
263 }
264
265
266 /**
267 * Return list of contexts bound to a surface.
268 */
269 const struct sct_context_list *
270 sct_get_surface_contexts(struct surface_context_tracker *sct,
271 const struct pipe_surface *surface)
272 {
273 const struct sct_surface *si = find_surface_info(sct, surface);
274 return si->contexts;
275 }
276
277
278
279 static boolean
280 find_texture(const struct sct_context *ci,
281 const struct pipe_texture *texture)
282 {
283 const struct texture_list *tl;
284
285 for (tl = ci->textures_used; tl; tl = tl->next) {
286 if (tl->texture == texture) {
287 return TRUE;
288 }
289 }
290 return FALSE;
291 }
292
293
294 /**
295 * Add the given texture to the context's list of used textures.
296 */
297 static void
298 add_texture_used(struct sct_context *ci,
299 struct pipe_texture *texture)
300 {
301 if (!find_texture(ci, texture)) {
302 /* add to list */
303 struct texture_list *tl = CALLOC_STRUCT(texture_list);
304 if (tl) {
305 pipe_texture_reference(&tl->texture, texture);
306 /* insert at head */
307 tl->next = ci->textures_used;
308 ci->textures_used = tl;
309 }
310 }
311 }
312
313
314 /**
315 * Bind a texture to a rendering context.
316 */
317 void
318 sct_bind_texture(struct surface_context_tracker *sct,
319 struct pipe_context *context,
320 uint unit,
321 struct pipe_texture *tex)
322 {
323 struct sct_context *ci = find_context_info(sct, context);
324
325 if (ci->textures[unit] != tex) {
326 /* put texture on the 'used' list */
327 add_texture_used(ci, tex);
328 /* bind new */
329 pipe_texture_reference(&ci->textures[unit], tex);
330 }
331 }
332
333
334 /**
335 * Check if the given texture has been used by the rendering context
336 * since the last call to sct_flush_textures().
337 */
338 boolean
339 sct_is_texture_used(struct surface_context_tracker *sct,
340 const struct pipe_context *context,
341 const struct pipe_texture *texture)
342 {
343 const struct sct_context *ci = find_context_info(sct, context);
344 return find_texture(ci, texture);
345 }
346
347
348 /**
349 * To be called when the image contents of a texture are changed, such
350 * as for gl[Copy]TexSubImage().
351 * XXX this may not be needed
352 */
353 void
354 sct_update_texture(struct pipe_texture *tex)
355 {
356
357 }
358
359
360 /**
361 * When a scene is flushed/rendered we can release the list of
362 * used textures.
363 */
364 void
365 sct_flush_textures(struct surface_context_tracker *sct,
366 struct pipe_context *context)
367 {
368 struct sct_context *ci = find_context_info(sct, context);
369 struct texture_list *tl, *next;
370 uint i;
371
372 for (tl = ci->textures_used; tl; tl = next) {
373 next = tl->next;
374 pipe_texture_release(&tl->texture);
375 FREE(tl);
376 }
377 ci->textures_used = NULL;
378
379 /* put the currently bound textures on the 'used' list */
380 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
381 add_texture_used(ci, ci->textures[i]);
382 }
383 }
384
385
386
387 void
388 sct_destroy_context(struct surface_context_tracker *sct,
389 struct pipe_context *context)
390 {
391 /* XXX should we require an unbinding first? */
392 {
393 struct sct_surface *si;
394 for (si = sct->surfaces; si; si = si->next) {
395 remove_context_from_surface(si, context);
396 }
397 }
398
399 /* remove context from context_info list */
400 {
401 struct sct_context *ci, *next, *prev = NULL;
402 for (ci = sct->contexts; ci; ci = next) {
403 next = ci->next;
404 if (ci->context == context) {
405 if (prev)
406 prev->next = ci->next;
407 else
408 sct->contexts = ci->next;
409 FREE(ci);
410 }
411 else {
412 prev = ci;
413 }
414 }
415 }
416
417 }
418
419
420 void
421 sct_destroy_surface(struct surface_context_tracker *sct,
422 struct pipe_surface *surface)
423 {
424 if (1) {
425 /* debug/sanity: no context should be bound to surface */
426 struct sct_context *ci;
427 uint i;
428 for (ci = sct->contexts; ci; ci = ci->next) {
429 for (i = 0; i < MAX_SURFACES; i++) {
430 assert(ci->surfaces[i] != surface);
431 }
432 }
433 }
434
435 /* remove surface from sct_surface list */
436 {
437 struct sct_surface *si, *next, *prev = NULL;
438 for (si = sct->surfaces; si; si = next) {
439 next = si->next;
440 if (si->surface == surface) {
441 /* unlink */
442 if (prev)
443 prev->next = si->next;
444 else
445 sct->surfaces = si->next;
446 FREE(si);
447 }
448 else {
449 prev = si;
450 }
451 }
452 }
453 }