Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2011 Lauri Kasanen |
||
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 THE AUTHORS OR COPYRIGHT HOLDERS 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 | #include "pipe/p_compiler.h" |
||
29 | |||
30 | #include "postprocess/filters.h" |
||
31 | |||
32 | #include "pipe/p_screen.h" |
||
33 | #include "util/u_inlines.h" |
||
34 | #include "util/u_math.h" |
||
35 | #include "util/u_debug.h" |
||
36 | #include "util/u_memory.h" |
||
37 | #include "cso_cache/cso_context.h" |
||
38 | |||
39 | /** Initialize the post-processing queue. */ |
||
40 | struct pp_queue_t * |
||
41 | pp_init(struct pipe_context *pipe, const unsigned int *enabled, |
||
42 | struct cso_context *cso) |
||
43 | { |
||
44 | unsigned int num_filters = 0; |
||
45 | unsigned int curpos = 0, i, tmp_req = 0; |
||
46 | struct pp_queue_t *ppq; |
||
47 | |||
48 | pp_debug("Initializing the post-processing queue.\n"); |
||
49 | |||
50 | /* How many filters were requested? */ |
||
51 | for (i = 0; i < PP_FILTERS; i++) { |
||
52 | if (enabled[i]) |
||
53 | num_filters++; |
||
54 | } |
||
55 | if (num_filters == 0) |
||
56 | return NULL; |
||
57 | |||
58 | ppq = CALLOC(1, sizeof(struct pp_queue_t)); |
||
59 | |||
60 | if (ppq == NULL) { |
||
61 | pp_debug("Unable to allocate memory for ppq.\n"); |
||
62 | goto error; |
||
63 | } |
||
64 | |||
65 | ppq->pp_queue = CALLOC(num_filters, sizeof(pp_func)); |
||
66 | if (ppq->pp_queue == NULL) { |
||
67 | pp_debug("Unable to allocate memory for pp_queue.\n"); |
||
68 | goto error; |
||
69 | } |
||
70 | |||
71 | ppq->shaders = CALLOC(num_filters, sizeof(void *)); |
||
72 | ppq->filters = CALLOC(num_filters, sizeof(unsigned int)); |
||
73 | |||
74 | if ((ppq->shaders == NULL) || |
||
75 | (ppq->filters == NULL)) { |
||
76 | pp_debug("Unable to allocate memory for shaders and filter arrays.\n"); |
||
77 | goto error; |
||
78 | } |
||
79 | |||
80 | ppq->p = pp_init_prog(ppq, pipe, cso); |
||
81 | if (ppq->p == NULL) { |
||
82 | pp_debug("pp_init_prog returned NULL.\n"); |
||
83 | goto error; |
||
84 | } |
||
85 | |||
86 | /* Add the enabled filters to the queue, in order */ |
||
87 | curpos = 0; |
||
88 | for (i = 0; i < PP_FILTERS; i++) { |
||
89 | if (enabled[i]) { |
||
90 | ppq->pp_queue[curpos] = pp_filters[i].main; |
||
91 | tmp_req = MAX2(tmp_req, pp_filters[i].inner_tmps); |
||
92 | ppq->filters[curpos] = i; |
||
93 | |||
94 | if (pp_filters[i].shaders) { |
||
95 | ppq->shaders[curpos] = |
||
96 | CALLOC(pp_filters[i].shaders + 1, sizeof(void *)); |
||
97 | if (!ppq->shaders[curpos]) { |
||
98 | pp_debug("Unable to allocate memory for shader list.\n"); |
||
99 | goto error; |
||
100 | } |
||
101 | } |
||
102 | |||
103 | /* Call the initialization function for the filter. */ |
||
104 | if (!pp_filters[i].init(ppq, curpos, enabled[i])) { |
||
105 | pp_debug("Initialization for filter %u failed.\n", i); |
||
106 | goto error; |
||
107 | } |
||
108 | |||
109 | curpos++; |
||
110 | } |
||
111 | } |
||
112 | |||
113 | ppq->n_filters = curpos; |
||
114 | ppq->n_tmp = (curpos > 2 ? 2 : 1); |
||
115 | ppq->n_inner_tmp = tmp_req; |
||
116 | |||
117 | ppq->fbos_init = false; |
||
118 | |||
119 | for (i = 0; i < curpos; i++) |
||
120 | ppq->shaders[i][0] = ppq->p->passvs; |
||
121 | |||
122 | pp_debug("Queue successfully allocated. %u filter(s).\n", curpos); |
||
123 | |||
124 | return ppq; |
||
125 | |||
126 | error: |
||
127 | |||
128 | if (ppq) { |
||
129 | /* Assign curpos, since we only need to destroy initialized filters. */ |
||
130 | ppq->n_filters = curpos; |
||
131 | |||
132 | /* Call the common free function which must handle partial initialization. */ |
||
133 | pp_free(ppq); |
||
134 | } |
||
135 | |||
136 | return NULL; |
||
137 | } |
||
138 | |||
139 | /** Free any allocated FBOs (temp buffers). Called after resizing for example. */ |
||
140 | void |
||
141 | pp_free_fbos(struct pp_queue_t *ppq) |
||
142 | { |
||
143 | |||
144 | unsigned int i; |
||
145 | |||
146 | if (!ppq->fbos_init) |
||
147 | return; |
||
148 | |||
149 | for (i = 0; i < ppq->n_tmp; i++) { |
||
150 | pipe_surface_reference(&ppq->tmps[i], NULL); |
||
151 | pipe_resource_reference(&ppq->tmp[i], NULL); |
||
152 | } |
||
153 | for (i = 0; i < ppq->n_inner_tmp; i++) { |
||
154 | pipe_surface_reference(&ppq->inner_tmps[i], NULL); |
||
155 | pipe_resource_reference(&ppq->inner_tmp[i], NULL); |
||
156 | } |
||
157 | pipe_surface_reference(&ppq->stencils, NULL); |
||
158 | pipe_resource_reference(&ppq->stencil, NULL); |
||
159 | |||
160 | ppq->fbos_init = false; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Free the pp queue. Called on context termination and failure in |
||
165 | * pp_init. |
||
166 | */ |
||
167 | void |
||
168 | pp_free(struct pp_queue_t *ppq) |
||
169 | { |
||
170 | unsigned int i, j; |
||
171 | |||
172 | pp_free_fbos(ppq); |
||
173 | |||
174 | if (ppq && ppq->p) { |
||
175 | if (ppq->p->pipe && ppq->filters && ppq->shaders) { |
||
176 | for (i = 0; i < ppq->n_filters; i++) { |
||
177 | unsigned int filter = ppq->filters[i]; |
||
178 | |||
179 | if (ppq->shaders[i] == NULL) { |
||
180 | continue; |
||
181 | } |
||
182 | |||
183 | /* |
||
184 | * Common shader destruction code for all postprocessing |
||
185 | * filters. |
||
186 | */ |
||
187 | for (j = 0; j < pp_filters[filter].shaders; j++) { |
||
188 | if (ppq->shaders[i][j] == NULL) { |
||
189 | /* We reached the end of initialized shaders. */ |
||
190 | break; |
||
191 | } |
||
192 | |||
193 | if (ppq->shaders[i][j] == ppq->p->passvs) { |
||
194 | continue; |
||
195 | } |
||
196 | |||
197 | assert(ppq); |
||
198 | assert(ppq->p); |
||
199 | assert(ppq->p->pipe); |
||
200 | |||
201 | if (j >= pp_filters[filter].verts) { |
||
202 | assert(ppq->p->pipe->delete_fs_state); |
||
203 | ppq->p->pipe->delete_fs_state(ppq->p->pipe, |
||
204 | ppq->shaders[i][j]); |
||
205 | ppq->shaders[i][j] = NULL; |
||
206 | } else { |
||
207 | assert(ppq->p->pipe->delete_vs_state); |
||
208 | ppq->p->pipe->delete_vs_state(ppq->p->pipe, |
||
209 | ppq->shaders[i][j]); |
||
210 | ppq->shaders[i][j] = NULL; |
||
211 | } |
||
212 | } |
||
213 | |||
214 | /* Finally call each filter type's free functionality. */ |
||
215 | pp_filters[filter].free(ppq, i); |
||
216 | } |
||
217 | } |
||
218 | |||
219 | FREE(ppq->p); |
||
220 | } |
||
221 | |||
222 | if (ppq) { |
||
223 | /* |
||
224 | * Handle partial initialization for common resource destruction |
||
225 | * in the create path. |
||
226 | */ |
||
227 | FREE(ppq->filters); |
||
228 | FREE(ppq->shaders); |
||
229 | FREE(ppq->pp_queue); |
||
230 | |||
231 | FREE(ppq); |
||
232 | } |
||
233 | |||
234 | pp_debug("Queue taken down.\n"); |
||
235 | } |
||
236 | |||
237 | /** Internal debug function. Should be available to final users. */ |
||
238 | void |
||
239 | pp_debug(const char *fmt, ...) |
||
240 | { |
||
241 | va_list ap; |
||
242 | |||
243 | if (!debug_get_bool_option("PP_DEBUG", FALSE)) |
||
244 | return; |
||
245 | |||
246 | va_start(ap, fmt); |
||
247 | _debug_vprintf(fmt, ap); |
||
248 | va_end(ap); |
||
249 | } |
||
250 | |||
251 | /** Allocate the temp FBOs. Called on makecurrent and resize. */ |
||
252 | void |
||
253 | pp_init_fbos(struct pp_queue_t *ppq, unsigned int w, |
||
254 | unsigned int h) |
||
255 | { |
||
256 | |||
257 | struct program *p = ppq->p; /* The lazy will inherit the earth */ |
||
258 | |||
259 | unsigned int i; |
||
260 | struct pipe_resource tmp_res; |
||
261 | |||
262 | if (ppq->fbos_init) |
||
263 | return; |
||
264 | |||
265 | pp_debug("Initializing FBOs, size %ux%u\n", w, h); |
||
266 | pp_debug("Requesting %u temps and %u inner temps\n", ppq->n_tmp, |
||
267 | ppq->n_inner_tmp); |
||
268 | |||
269 | memset(&tmp_res, 0, sizeof(tmp_res)); |
||
270 | tmp_res.target = PIPE_TEXTURE_2D; |
||
271 | tmp_res.format = p->surf.format = PIPE_FORMAT_B8G8R8A8_UNORM; |
||
272 | tmp_res.width0 = w; |
||
273 | tmp_res.height0 = h; |
||
274 | tmp_res.depth0 = 1; |
||
275 | tmp_res.array_size = 1; |
||
276 | tmp_res.last_level = 0; |
||
277 | tmp_res.bind = PIPE_BIND_RENDER_TARGET; |
||
278 | |||
279 | if (!p->screen->is_format_supported(p->screen, tmp_res.format, |
||
280 | tmp_res.target, 1, tmp_res.bind)) |
||
281 | pp_debug("Temp buffers' format fail\n"); |
||
282 | |||
283 | for (i = 0; i < ppq->n_tmp; i++) { |
||
284 | ppq->tmp[i] = p->screen->resource_create(p->screen, &tmp_res); |
||
285 | ppq->tmps[i] = p->pipe->create_surface(p->pipe, ppq->tmp[i], &p->surf); |
||
286 | |||
287 | if (!ppq->tmp[i] || !ppq->tmps[i]) |
||
288 | goto error; |
||
289 | } |
||
290 | |||
291 | for (i = 0; i < ppq->n_inner_tmp; i++) { |
||
292 | ppq->inner_tmp[i] = p->screen->resource_create(p->screen, &tmp_res); |
||
293 | ppq->inner_tmps[i] = p->pipe->create_surface(p->pipe, |
||
294 | ppq->inner_tmp[i], |
||
295 | &p->surf); |
||
296 | |||
297 | if (!ppq->inner_tmp[i] || !ppq->inner_tmps[i]) |
||
298 | goto error; |
||
299 | } |
||
300 | |||
301 | tmp_res.bind = PIPE_BIND_DEPTH_STENCIL; |
||
302 | |||
303 | tmp_res.format = p->surf.format = PIPE_FORMAT_S8_UINT_Z24_UNORM; |
||
304 | |||
305 | if (!p->screen->is_format_supported(p->screen, tmp_res.format, |
||
306 | tmp_res.target, 1, tmp_res.bind)) { |
||
307 | |||
308 | tmp_res.format = p->surf.format = PIPE_FORMAT_Z24_UNORM_S8_UINT; |
||
309 | |||
310 | if (!p->screen->is_format_supported(p->screen, tmp_res.format, |
||
311 | tmp_res.target, 1, tmp_res.bind)) |
||
312 | pp_debug("Temp Sbuffer format fail\n"); |
||
313 | } |
||
314 | |||
315 | ppq->stencil = p->screen->resource_create(p->screen, &tmp_res); |
||
316 | ppq->stencils = p->pipe->create_surface(p->pipe, ppq->stencil, &p->surf); |
||
317 | if (!ppq->stencil || !ppq->stencils) |
||
318 | goto error; |
||
319 | |||
320 | p->framebuffer.width = w; |
||
321 | p->framebuffer.height = h; |
||
322 | |||
323 | p->viewport.scale[0] = p->viewport.translate[0] = (float) w / 2.0f; |
||
324 | p->viewport.scale[1] = p->viewport.translate[1] = (float) h / 2.0f; |
||
325 | p->viewport.scale[3] = 1.0f; |
||
326 | p->viewport.translate[3] = 0.0f; |
||
327 | |||
328 | ppq->fbos_init = true; |
||
329 | |||
330 | return; |
||
331 | |||
332 | error: |
||
333 | pp_debug("Failed to allocate temp buffers!\n"); |
||
334 | }>>>>>>>>> |