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