Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 == NULL) {
  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.