1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2011 Lauri Kasanen
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "pipe/p_compiler.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "postprocess/filters.h"
31bf215546Sopenharmony_ci#include "postprocess/pp_private.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "pipe/p_screen.h"
34bf215546Sopenharmony_ci#include "util/u_inlines.h"
35bf215546Sopenharmony_ci#include "util/u_math.h"
36bf215546Sopenharmony_ci#include "util/u_debug.h"
37bf215546Sopenharmony_ci#include "util/u_memory.h"
38bf215546Sopenharmony_ci#include "cso_cache/cso_context.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci/** Initialize the post-processing queue. */
41bf215546Sopenharmony_cistruct pp_queue_t *
42bf215546Sopenharmony_cipp_init(struct pipe_context *pipe, const unsigned int *enabled,
43bf215546Sopenharmony_ci        struct cso_context *cso, struct st_context_iface *st)
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci   unsigned int num_filters = 0;
46bf215546Sopenharmony_ci   unsigned int curpos = 0, i, tmp_req = 0;
47bf215546Sopenharmony_ci   struct pp_queue_t *ppq;
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci   pp_debug("Initializing the post-processing queue.\n");
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   /* How many filters were requested? */
52bf215546Sopenharmony_ci   for (i = 0; i < PP_FILTERS; i++) {
53bf215546Sopenharmony_ci      if (enabled[i])
54bf215546Sopenharmony_ci         num_filters++;
55bf215546Sopenharmony_ci   }
56bf215546Sopenharmony_ci   if (num_filters == 0)
57bf215546Sopenharmony_ci      return NULL;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   ppq = CALLOC(1, sizeof(struct pp_queue_t));
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   if (!ppq) {
62bf215546Sopenharmony_ci      pp_debug("Unable to allocate memory for ppq.\n");
63bf215546Sopenharmony_ci      goto error;
64bf215546Sopenharmony_ci   }
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   ppq->pp_queue = CALLOC(num_filters, sizeof(pp_func));
67bf215546Sopenharmony_ci   if (ppq->pp_queue == NULL) {
68bf215546Sopenharmony_ci      pp_debug("Unable to allocate memory for pp_queue.\n");
69bf215546Sopenharmony_ci      goto error;
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   ppq->shaders = CALLOC(num_filters, sizeof(void *));
73bf215546Sopenharmony_ci   ppq->filters = CALLOC(num_filters, sizeof(unsigned int));
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   if ((ppq->shaders == NULL) ||
76bf215546Sopenharmony_ci       (ppq->filters == NULL)) {
77bf215546Sopenharmony_ci      pp_debug("Unable to allocate memory for shaders and filter arrays.\n");
78bf215546Sopenharmony_ci      goto error;
79bf215546Sopenharmony_ci   }
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   ppq->p = pp_init_prog(ppq, pipe, cso, st);
82bf215546Sopenharmony_ci   if (ppq->p == NULL) {
83bf215546Sopenharmony_ci      pp_debug("pp_init_prog returned NULL.\n");
84bf215546Sopenharmony_ci      goto error;
85bf215546Sopenharmony_ci   }
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   /* Add the enabled filters to the queue, in order */
88bf215546Sopenharmony_ci   curpos = 0;
89bf215546Sopenharmony_ci   for (i = 0; i < PP_FILTERS; i++) {
90bf215546Sopenharmony_ci      if (enabled[i]) {
91bf215546Sopenharmony_ci         ppq->pp_queue[curpos] = pp_filters[i].main;
92bf215546Sopenharmony_ci         tmp_req = MAX2(tmp_req, pp_filters[i].inner_tmps);
93bf215546Sopenharmony_ci         ppq->filters[curpos] = i;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci         if (pp_filters[i].shaders) {
96bf215546Sopenharmony_ci            ppq->shaders[curpos] =
97bf215546Sopenharmony_ci               CALLOC(pp_filters[i].shaders + 1, sizeof(void *));
98bf215546Sopenharmony_ci            if (!ppq->shaders[curpos]) {
99bf215546Sopenharmony_ci               pp_debug("Unable to allocate memory for shader list.\n");
100bf215546Sopenharmony_ci               goto error;
101bf215546Sopenharmony_ci            }
102bf215546Sopenharmony_ci         }
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci         /* Call the initialization function for the filter. */
105bf215546Sopenharmony_ci         if (!pp_filters[i].init(ppq, curpos, enabled[i])) {
106bf215546Sopenharmony_ci            pp_debug("Initialization for filter %u failed.\n", i);
107bf215546Sopenharmony_ci            goto error;
108bf215546Sopenharmony_ci         }
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci         curpos++;
111bf215546Sopenharmony_ci      }
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   ppq->n_filters = curpos;
115bf215546Sopenharmony_ci   ppq->n_tmp = (curpos > 2 ? 2 : 1);
116bf215546Sopenharmony_ci   ppq->n_inner_tmp = tmp_req;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   ppq->fbos_init = false;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   for (i = 0; i < curpos; i++)
121bf215546Sopenharmony_ci      ppq->shaders[i][0] = ppq->p->passvs;
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   pp_debug("Queue successfully allocated. %u filter(s).\n", curpos);
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   return ppq;
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci error:
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   if (ppq) {
130bf215546Sopenharmony_ci      /* Assign curpos, since we only need to destroy initialized filters. */
131bf215546Sopenharmony_ci      ppq->n_filters = curpos;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci      /* Call the common free function which must handle partial initialization. */
134bf215546Sopenharmony_ci      pp_free(ppq);
135bf215546Sopenharmony_ci   }
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   return NULL;
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci/** Free any allocated FBOs (temp buffers). Called after resizing for example. */
141bf215546Sopenharmony_civoid
142bf215546Sopenharmony_cipp_free_fbos(struct pp_queue_t *ppq)
143bf215546Sopenharmony_ci{
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   unsigned int i;
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   if (!ppq->fbos_init)
148bf215546Sopenharmony_ci      return;
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   for (i = 0; i < ppq->n_tmp; i++) {
151bf215546Sopenharmony_ci      pipe_surface_reference(&ppq->tmps[i], NULL);
152bf215546Sopenharmony_ci      pipe_resource_reference(&ppq->tmp[i], NULL);
153bf215546Sopenharmony_ci   }
154bf215546Sopenharmony_ci   for (i = 0; i < ppq->n_inner_tmp; i++) {
155bf215546Sopenharmony_ci      pipe_surface_reference(&ppq->inner_tmps[i], NULL);
156bf215546Sopenharmony_ci      pipe_resource_reference(&ppq->inner_tmp[i], NULL);
157bf215546Sopenharmony_ci   }
158bf215546Sopenharmony_ci   pipe_surface_reference(&ppq->stencils, NULL);
159bf215546Sopenharmony_ci   pipe_resource_reference(&ppq->stencil, NULL);
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   ppq->fbos_init = false;
162bf215546Sopenharmony_ci}
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci/**
165bf215546Sopenharmony_ci * Free the pp queue. Called on context termination and failure in
166bf215546Sopenharmony_ci * pp_init.
167bf215546Sopenharmony_ci */
168bf215546Sopenharmony_civoid
169bf215546Sopenharmony_cipp_free(struct pp_queue_t *ppq)
170bf215546Sopenharmony_ci{
171bf215546Sopenharmony_ci   unsigned int i, j;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   if (!ppq)
174bf215546Sopenharmony_ci      return;
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   pp_free_fbos(ppq);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   if (ppq->p) {
179bf215546Sopenharmony_ci      if (ppq->p->pipe && ppq->filters && ppq->shaders) {
180bf215546Sopenharmony_ci         for (i = 0; i < ppq->n_filters; i++) {
181bf215546Sopenharmony_ci            unsigned int filter = ppq->filters[i];
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci            if (ppq->shaders[i] == NULL) {
184bf215546Sopenharmony_ci               continue;
185bf215546Sopenharmony_ci            }
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci            /*
188bf215546Sopenharmony_ci             * Common shader destruction code for all postprocessing
189bf215546Sopenharmony_ci             * filters.
190bf215546Sopenharmony_ci             */
191bf215546Sopenharmony_ci            for (j = 0; j < pp_filters[filter].shaders; j++) {
192bf215546Sopenharmony_ci               if (ppq->shaders[i][j] == NULL) {
193bf215546Sopenharmony_ci                  /* We reached the end of initialized shaders. */
194bf215546Sopenharmony_ci                  break;
195bf215546Sopenharmony_ci               }
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci               if (ppq->shaders[i][j] == ppq->p->passvs) {
198bf215546Sopenharmony_ci                  continue;
199bf215546Sopenharmony_ci               }
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci               assert(ppq);
202bf215546Sopenharmony_ci               assert(ppq->p);
203bf215546Sopenharmony_ci               assert(ppq->p->pipe);
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci               if (j >= pp_filters[filter].verts) {
206bf215546Sopenharmony_ci                  assert(ppq->p->pipe->delete_fs_state);
207bf215546Sopenharmony_ci                  ppq->p->pipe->delete_fs_state(ppq->p->pipe,
208bf215546Sopenharmony_ci                                                ppq->shaders[i][j]);
209bf215546Sopenharmony_ci                  ppq->shaders[i][j] = NULL;
210bf215546Sopenharmony_ci               } else {
211bf215546Sopenharmony_ci                  assert(ppq->p->pipe->delete_vs_state);
212bf215546Sopenharmony_ci                  ppq->p->pipe->delete_vs_state(ppq->p->pipe,
213bf215546Sopenharmony_ci                                                ppq->shaders[i][j]);
214bf215546Sopenharmony_ci                  ppq->shaders[i][j] = NULL;
215bf215546Sopenharmony_ci               }
216bf215546Sopenharmony_ci            }
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci            /* Finally call each filter type's free functionality. */
219bf215546Sopenharmony_ci            pp_filters[filter].free(ppq, i);
220bf215546Sopenharmony_ci         }
221bf215546Sopenharmony_ci      }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci      FREE(ppq->p);
224bf215546Sopenharmony_ci   }
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   /*
227bf215546Sopenharmony_ci    * Handle partial initialization for common resource destruction
228bf215546Sopenharmony_ci    * in the create path.
229bf215546Sopenharmony_ci    */
230bf215546Sopenharmony_ci   FREE(ppq->filters);
231bf215546Sopenharmony_ci   FREE(ppq->shaders);
232bf215546Sopenharmony_ci   FREE(ppq->pp_queue);
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   FREE(ppq);
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   pp_debug("Queue taken down.\n");
237bf215546Sopenharmony_ci}
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci/** Internal debug function. Should be available to final users. */
240bf215546Sopenharmony_civoid
241bf215546Sopenharmony_cipp_debug(const char *fmt, ...)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci   va_list ap;
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   if (!debug_get_bool_option("PP_DEBUG", FALSE))
246bf215546Sopenharmony_ci      return;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   va_start(ap, fmt);
249bf215546Sopenharmony_ci   _debug_vprintf(fmt, ap);
250bf215546Sopenharmony_ci   va_end(ap);
251bf215546Sopenharmony_ci}
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci/** Allocate the temp FBOs. Called on makecurrent and resize. */
254bf215546Sopenharmony_civoid
255bf215546Sopenharmony_cipp_init_fbos(struct pp_queue_t *ppq, unsigned int w,
256bf215546Sopenharmony_ci             unsigned int h)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   struct pp_program *p = ppq->p;  /* The lazy will inherit the earth */
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   unsigned int i;
262bf215546Sopenharmony_ci   struct pipe_resource tmp_res;
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   if (ppq->fbos_init)
265bf215546Sopenharmony_ci      return;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   pp_debug("Initializing FBOs, size %ux%u\n", w, h);
268bf215546Sopenharmony_ci   pp_debug("Requesting %u temps and %u inner temps\n", ppq->n_tmp,
269bf215546Sopenharmony_ci            ppq->n_inner_tmp);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   memset(&tmp_res, 0, sizeof(tmp_res));
272bf215546Sopenharmony_ci   tmp_res.target = PIPE_TEXTURE_2D;
273bf215546Sopenharmony_ci   tmp_res.format = p->surf.format = PIPE_FORMAT_B8G8R8A8_UNORM;
274bf215546Sopenharmony_ci   tmp_res.width0 = w;
275bf215546Sopenharmony_ci   tmp_res.height0 = h;
276bf215546Sopenharmony_ci   tmp_res.depth0 = 1;
277bf215546Sopenharmony_ci   tmp_res.array_size = 1;
278bf215546Sopenharmony_ci   tmp_res.last_level = 0;
279bf215546Sopenharmony_ci   tmp_res.bind = PIPE_BIND_RENDER_TARGET;
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   if (!p->screen->is_format_supported(p->screen, tmp_res.format,
282bf215546Sopenharmony_ci                                       tmp_res.target, 1, 1, tmp_res.bind))
283bf215546Sopenharmony_ci      pp_debug("Temp buffers' format fail\n");
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   for (i = 0; i < ppq->n_tmp; i++) {
286bf215546Sopenharmony_ci      ppq->tmp[i] = p->screen->resource_create(p->screen, &tmp_res);
287bf215546Sopenharmony_ci      ppq->tmps[i] = p->pipe->create_surface(p->pipe, ppq->tmp[i], &p->surf);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci      if (!ppq->tmp[i] || !ppq->tmps[i])
290bf215546Sopenharmony_ci         goto error;
291bf215546Sopenharmony_ci   }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   for (i = 0; i < ppq->n_inner_tmp; i++) {
294bf215546Sopenharmony_ci      ppq->inner_tmp[i] = p->screen->resource_create(p->screen, &tmp_res);
295bf215546Sopenharmony_ci      ppq->inner_tmps[i] = p->pipe->create_surface(p->pipe,
296bf215546Sopenharmony_ci                                                   ppq->inner_tmp[i],
297bf215546Sopenharmony_ci                                                   &p->surf);
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci      if (!ppq->inner_tmp[i] || !ppq->inner_tmps[i])
300bf215546Sopenharmony_ci         goto error;
301bf215546Sopenharmony_ci   }
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   tmp_res.bind = PIPE_BIND_DEPTH_STENCIL;
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   tmp_res.format = p->surf.format = PIPE_FORMAT_S8_UINT_Z24_UNORM;
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   if (!p->screen->is_format_supported(p->screen, tmp_res.format,
308bf215546Sopenharmony_ci                                       tmp_res.target, 1, 1, tmp_res.bind)) {
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci      tmp_res.format = p->surf.format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci      if (!p->screen->is_format_supported(p->screen, tmp_res.format,
313bf215546Sopenharmony_ci                                          tmp_res.target, 1, 1, tmp_res.bind))
314bf215546Sopenharmony_ci         pp_debug("Temp Sbuffer format fail\n");
315bf215546Sopenharmony_ci   }
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   ppq->stencil = p->screen->resource_create(p->screen, &tmp_res);
318bf215546Sopenharmony_ci   ppq->stencils = p->pipe->create_surface(p->pipe, ppq->stencil, &p->surf);
319bf215546Sopenharmony_ci   if (!ppq->stencil || !ppq->stencils)
320bf215546Sopenharmony_ci      goto error;
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   p->framebuffer.width = w;
323bf215546Sopenharmony_ci   p->framebuffer.height = h;
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   p->viewport.scale[0] = p->viewport.translate[0] = (float) w / 2.0f;
326bf215546Sopenharmony_ci   p->viewport.scale[1] = p->viewport.translate[1] = (float) h / 2.0f;
327bf215546Sopenharmony_ci   p->viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X;
328bf215546Sopenharmony_ci   p->viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y;
329bf215546Sopenharmony_ci   p->viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z;
330bf215546Sopenharmony_ci   p->viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W;
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   ppq->fbos_init = true;
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   return;
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci error:
337bf215546Sopenharmony_ci   pp_debug("Failed to allocate temp buffers!\n");
338bf215546Sopenharmony_ci}
339