#include "postprocess/postprocess.h"
-typedef void (*pp_init_func) (struct pp_queue_t *, unsigned int,
+typedef bool (*pp_init_func) (struct pp_queue_t *, unsigned int,
unsigned int);
+typedef void (*pp_free_func) (struct pp_queue_t *, unsigned int);
struct pp_filter_t
{
unsigned int verts; /* How many are vertex shaders */
pp_init_func init; /* Init function */
pp_func main; /* Run function */
+ pp_free_func free; /* Free function */
};
/* Order matters. Put new filters in a suitable place. */
static const struct pp_filter_t pp_filters[PP_FILTERS] = {
-/* name inner shaders verts init run */
- { "pp_noblue", 0, 2, 1, pp_noblue_init, pp_nocolor },
- { "pp_nogreen", 0, 2, 1, pp_nogreen_init, pp_nocolor },
- { "pp_nored", 0, 2, 1, pp_nored_init, pp_nocolor },
- { "pp_celshade", 0, 2, 1, pp_celshade_init, pp_nocolor },
- { "pp_jimenezmlaa", 2, 5, 2, pp_jimenezmlaa_init, pp_jimenezmlaa },
- { "pp_jimenezmlaa_color", 2, 5, 2, pp_jimenezmlaa_init_color, pp_jimenezmlaa_color },
+/* name inner shaders verts init run free */
+ { "pp_noblue", 0, 2, 1, pp_noblue_init, pp_nocolor, pp_nocolor_free },
+ { "pp_nogreen", 0, 2, 1, pp_nogreen_init, pp_nocolor, pp_nocolor_free },
+ { "pp_nored", 0, 2, 1, pp_nored_init, pp_nocolor, pp_nocolor_free },
+ { "pp_celshade", 0, 2, 1, pp_celshade_init, pp_nocolor, pp_celshade_free },
+ { "pp_jimenezmlaa", 2, 5, 2, pp_jimenezmlaa_init, pp_jimenezmlaa, pp_jimenezmlaa_free },
+ { "pp_jimenezmlaa_color", 2, 5, 2, pp_jimenezmlaa_init_color, pp_jimenezmlaa_color, pp_jimenezmlaa_free },
};
#endif
struct pipe_resource *depth; /* depth of original input */
struct pipe_resource *stencil; /* stencil shared by inner_tmps */
+ struct pipe_resource *constbuf; /* MLAA constant buffer */
+ struct pipe_resource *areamaptex; /* MLAA area map texture */
struct pipe_surface *tmps[2], *inner_tmps[3], *stencils;
void ***shaders; /* Shaders in TGSI form */
- unsigned int *verts;
+ unsigned int *filters; /* Active filter to filters.h mapping. */
struct program *p;
bool fbos_init;
/* The filter init functions */
-void pp_celshade_init(struct pp_queue_t *, unsigned int, unsigned int);
+bool pp_celshade_init(struct pp_queue_t *, unsigned int, unsigned int);
-void pp_nored_init(struct pp_queue_t *, unsigned int, unsigned int);
-void pp_nogreen_init(struct pp_queue_t *, unsigned int, unsigned int);
-void pp_noblue_init(struct pp_queue_t *, unsigned int, unsigned int);
+bool pp_nored_init(struct pp_queue_t *, unsigned int, unsigned int);
+bool pp_nogreen_init(struct pp_queue_t *, unsigned int, unsigned int);
+bool pp_noblue_init(struct pp_queue_t *, unsigned int, unsigned int);
-void pp_jimenezmlaa_init(struct pp_queue_t *, unsigned int, unsigned int);
-void pp_jimenezmlaa_init_color(struct pp_queue_t *, unsigned int,
+bool pp_jimenezmlaa_init(struct pp_queue_t *, unsigned int, unsigned int);
+bool pp_jimenezmlaa_init_color(struct pp_queue_t *, unsigned int,
unsigned int);
+/* The filter free functions */
+
+void pp_celshade_free(struct pp_queue_t *, unsigned int);
+void pp_nocolor_free(struct pp_queue_t *, unsigned int);
+void pp_jimenezmlaa_free(struct pp_queue_t *, unsigned int);
+
#endif
#include "postprocess/pp_filters.h"
/** Init function */
-void
+bool
pp_celshade_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val)
{
ppq->shaders[n][1] =
pp_tgsi_to_state(ppq->p->pipe, celshade, false, "celshade");
+
+ return (ppq->shaders[n][1] != NULL) ? TRUE : FALSE;
+}
+
+/** Free function */
+void
+pp_celshade_free(struct pp_queue_t *ppq, unsigned int n)
+{
}
/* Init functions */
-void
+bool
pp_nored_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val)
{
- ppq->shaders[n][1] = pp_tgsi_to_state(ppq->p->pipe, nored, false, "nored");
+ ppq->shaders[n][1] =
+ pp_tgsi_to_state(ppq->p->pipe, nored, false, "nored");
+
+ return (ppq->shaders[n][1] != NULL) ? TRUE : FALSE;
}
-void
+bool
pp_nogreen_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val)
{
ppq->shaders[n][1] =
pp_tgsi_to_state(ppq->p->pipe, nogreen, false, "nogreen");
+
+ return (ppq->shaders[n][1] != NULL) ? TRUE : FALSE;
}
-void
+bool
pp_noblue_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val)
{
ppq->shaders[n][1] =
pp_tgsi_to_state(ppq->p->pipe, noblue, false, "noblue");
+
+ return (ppq->shaders[n][1] != NULL) ? TRUE : FALSE;
+}
+
+/* Free functions */
+void
+pp_nocolor_free(struct pp_queue_t *ppq, unsigned int n)
+{
}
pp_init(struct pipe_context *pipe, const unsigned int *enabled,
struct cso_context *cso)
{
-
+ unsigned int num_filters = 0;
unsigned int curpos = 0, i, tmp_req = 0;
struct pp_queue_t *ppq;
- pp_func *tmp_q;
pp_debug("Initializing the post-processing queue.\n");
/* How many filters were requested? */
for (i = 0; i < PP_FILTERS; i++) {
if (enabled[i])
- curpos++;
+ num_filters++;
}
- if (!curpos)
+ if (num_filters == 0)
return NULL;
ppq = CALLOC(1, sizeof(struct pp_queue_t));
- tmp_q = CALLOC(curpos, sizeof(pp_func));
- ppq->shaders = CALLOC(curpos, sizeof(void *));
- ppq->verts = CALLOC(curpos, sizeof(unsigned int));
- if (!tmp_q || !ppq || !ppq->shaders || !ppq->verts)
+ if (ppq == NULL) {
+ pp_debug("Unable to allocate memory for ppq.\n");
goto error;
+ }
+
+ ppq->pp_queue = CALLOC(num_filters, sizeof(pp_func));
+ if (ppq->pp_queue == NULL) {
+ pp_debug("Unable to allocate memory for pp_queue.\n");
+ goto error;
+ }
+
+ ppq->shaders = CALLOC(num_filters, sizeof(void *));
+ ppq->filters = CALLOC(num_filters, sizeof(unsigned int));
+
+ if ((ppq->shaders == NULL) ||
+ (ppq->filters == NULL)) {
+ pp_debug("Unable to allocate memory for shaders and filter arrays.\n");
+ goto error;
+ }
ppq->p = pp_init_prog(ppq, pipe, cso);
- if (!ppq->p)
+ if (ppq->p == NULL) {
+ pp_debug("pp_init_prog returned NULL.\n");
goto error;
+ }
/* Add the enabled filters to the queue, in order */
curpos = 0;
- ppq->pp_queue = tmp_q;
for (i = 0; i < PP_FILTERS; i++) {
if (enabled[i]) {
ppq->pp_queue[curpos] = pp_filters[i].main;
tmp_req = MAX2(tmp_req, pp_filters[i].inner_tmps);
+ ppq->filters[curpos] = i;
if (pp_filters[i].shaders) {
ppq->shaders[curpos] =
CALLOC(pp_filters[i].shaders + 1, sizeof(void *));
- ppq->verts[curpos] = pp_filters[i].verts;
- if (!ppq->shaders[curpos])
+ if (!ppq->shaders[curpos]) {
+ pp_debug("Unable to allocate memory for shader list.\n");
goto error;
+ }
}
- pp_filters[i].init(ppq, curpos, enabled[i]);
+
+ /* Call the initialization function for the filter. */
+ if (!pp_filters[i].init(ppq, curpos, enabled[i])) {
+ pp_debug("Initialization for filter %u failed.\n", i);
+ goto error;
+ }
curpos++;
}
}
ppq->p->blitctx = util_create_blit(ppq->p->pipe, cso);
- if (!ppq->p->blitctx)
+
+ if (ppq->p->blitctx == NULL) {
+ pp_debug("Unable to create a blit context.\n");
goto error;
+ }
ppq->n_filters = curpos;
ppq->n_tmp = (curpos > 2 ? 2 : 1);
ppq->shaders[i][0] = ppq->p->passvs;
pp_debug("Queue successfully allocated. %u filter(s).\n", curpos);
-
+
return ppq;
error:
- pp_debug("Error setting up pp\n");
- if (ppq)
- FREE(ppq->p);
- FREE(ppq);
- FREE(tmp_q);
+ if (ppq) {
+ /* Assign curpos, since we only need to destroy initialized filters. */
+ ppq->n_filters = curpos;
+
+ /* Call the common free function which must handle partial initialization. */
+ pp_free(ppq);
+ }
return NULL;
}
ppq->fbos_init = false;
}
-/** Free the pp queue. Called on context termination. */
+/**
+ * Free the pp queue. Called on context termination and failure in
+ * pp_init.
+ */
void
pp_free(struct pp_queue_t *ppq)
{
-
unsigned int i, j;
pp_free_fbos(ppq);
- util_destroy_blit(ppq->p->blitctx);
+ if (ppq && ppq->p) {
+ /* Only destroy created contexts. */
+ if (ppq->p->blitctx) {
+ util_destroy_blit(ppq->p->blitctx);
+ }
- for (i = 0; i < ppq->n_filters; i++) {
- for (j = 0; j < PP_MAX_PASSES && ppq->shaders[i][j]; j++) {
- if (j >= ppq->verts[i]) {
- ppq->p->pipe->delete_fs_state(ppq->p->pipe, ppq->shaders[i][j]);
- ppq->shaders[i][j] = NULL;
- }
- else if (ppq->shaders[i][j] != ppq->p->passvs) {
- ppq->p->pipe->delete_vs_state(ppq->p->pipe, ppq->shaders[i][j]);
- ppq->shaders[i][j] = NULL;
+ if (ppq->p->pipe && ppq->filters && ppq->shaders) {
+ for (i = 0; i < ppq->n_filters; i++) {
+ unsigned int filter = ppq->filters[i];
+
+ if (ppq->shaders[i] == NULL) {
+ continue;
+ }
+
+ /*
+ * Common shader destruction code for all postprocessing
+ * filters.
+ */
+ for (j = 0; j < pp_filters[filter].shaders; j++) {
+ if (ppq->shaders[i][j] == NULL) {
+ /* We reached the end of initialized shaders. */
+ break;
+ }
+
+ if (ppq->shaders[i][j] == ppq->p->passvs) {
+ continue;
+ }
+
+ assert(ppq);
+ assert(ppq->p);
+ assert(ppq->p->pipe);
+
+ if (j >= pp_filters[filter].verts) {
+ assert(ppq->p->pipe->delete_fs_state);
+ ppq->p->pipe->delete_fs_state(ppq->p->pipe,
+ ppq->shaders[i][j]);
+ ppq->shaders[i][j] = NULL;
+ } else {
+ assert(ppq->p->pipe->delete_vs_state);
+ ppq->p->pipe->delete_vs_state(ppq->p->pipe,
+ ppq->shaders[i][j]);
+ ppq->shaders[i][j] = NULL;
+ }
+ }
+
+ /* Finally call each filter type's free functionality. */
+ pp_filters[filter].free(ppq, i);
}
}
+
+ FREE(ppq->p);
}
- FREE(ppq->p);
- FREE(ppq->pp_queue);
- FREE(ppq);
+ if (ppq) {
+ /*
+ * Handle partial initialization for common resource destruction
+ * in the create path.
+ */
+ FREE(ppq->filters);
+ FREE(ppq->shaders);
+ FREE(ppq->pp_queue);
+
+ FREE(ppq);
+ }
pp_debug("Queue taken down.\n");
}
if (!ppq->stencil || !ppq->stencils)
goto error;
-
p->framebuffer.width = w;
p->framebuffer.height = h;
static float constants[] = { 1, 1, 0, 0 };
static unsigned int dimensions[2] = { 0, 0 };
-static struct pipe_resource *constbuf, *areamaptex;
-
/** Upload the constants. */
static void
-up_consts(struct pipe_context *pipe)
+up_consts(struct pp_queue_t *ppq)
{
+ struct pipe_context *pipe = ppq->p->pipe;
struct pipe_box box;
u_box_2d(0, 0, sizeof(constants), 1, &box);
- pipe->transfer_inline_write(pipe, constbuf, 0, PIPE_TRANSFER_WRITE,
+
+ pipe->transfer_inline_write(pipe, ppq->constbuf, 0, PIPE_TRANSFER_WRITE,
&box, constants, sizeof(constants),
sizeof(constants));
}
struct pipe_depth_stencil_alpha_state mstencil;
struct pipe_sampler_view v_tmp, *arr[3];
- unsigned int w = p->framebuffer.width;
- unsigned int h = p->framebuffer.height;
+ unsigned int w = 0;
+ unsigned int h = 0;
const struct pipe_stencil_ref ref = { {1} };
+
+ /* Insufficient initialization checks. */
+ assert(p);
+ assert(ppq);
+ assert(ppq->constbuf);
+ assert(ppq->areamaptex);
+ assert(ppq->inner_tmp);
+ assert(ppq->shaders[n]);
+
+ w = p->framebuffer.width;
+ h = p->framebuffer.height;
+
memset(&mstencil, 0, sizeof(mstencil));
+
cso_set_stencil_ref(p->cso, &ref);
/* Init the pixel size constant */
constants[0] = 1.0f / p->framebuffer.width;
constants[1] = 1.0f / p->framebuffer.height;
- up_consts(p->pipe);
+ up_consts(ppq);
dimensions[0] = p->framebuffer.width;
dimensions[1] = p->framebuffer.height;
}
- cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_VERTEX, 0, constbuf);
- cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_FRAGMENT, 0, constbuf);
+ cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_VERTEX,
+ 0, ppq->constbuf);
+ cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_FRAGMENT,
+ 0, ppq->constbuf);
mstencil.stencil[0].enabled = 1;
mstencil.stencil[0].valuemask = mstencil.stencil[0].writemask = ~0;
mstencil.stencil[0].zpass_op = PIPE_STENCIL_OP_KEEP;
cso_set_depth_stencil_alpha(p->cso, &mstencil);
- pp_filter_setup_in(p, areamaptex);
+ pp_filter_setup_in(p, ppq->areamaptex);
pp_filter_setup_out(p, ppq->inner_tmp[1]);
u_sampler_view_default_template(&v_tmp, ppq->inner_tmp[0],
}
/** The init function of the MLAA filter. */
-static void
+static bool
pp_jimenezmlaa_init_run(struct pp_queue_t *ppq, unsigned int n,
unsigned int val, bool iscolor)
{
struct pipe_box box;
struct pipe_resource res;
- char *tmp_text;
-
- constbuf = pipe_buffer_create(ppq->p->screen, PIPE_BIND_CONSTANT_BUFFER,
- PIPE_USAGE_STATIC, sizeof(constants));
- if (!constbuf) {
- pp_debug("Failed to allocate constant buffer\n");
- return;
- }
-
-
- pp_debug("mlaa: using %u max search steps\n", val);
+ char *tmp_text = NULL;
tmp_text = CALLOC(sizeof(blend2fs_1) + sizeof(blend2fs_2) +
IMM_SPACE, sizeof(char));
- if (!tmp_text) {
+ if (tmp_text == NULL) {
pp_debug("Failed to allocate shader space\n");
- return;
+ return FALSE;
+ }
+
+ ppq->constbuf = pipe_buffer_create(ppq->p->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ PIPE_USAGE_STATIC,
+ sizeof(constants));
+ if (ppq->constbuf == NULL) {
+ pp_debug("Failed to allocate constant buffer\n");
+ goto fail;
}
+
+ pp_debug("mlaa: using %u max search steps\n", val);
+
util_sprintf(tmp_text, "%s"
"IMM FLT32 { %.8f, 0.0000, 0.0000, 0.0000}\n"
"%s\n", blend2fs_1, (float) val, blend2fs_2);
res.target, 1, res.bind))
pp_debug("Areamap format not supported\n");
- areamaptex = ppq->p->screen->resource_create(ppq->p->screen, &res);
+ ppq->areamaptex = ppq->p->screen->resource_create(ppq->p->screen, &res);
+
+ if (ppq->areamaptex == NULL) {
+ pp_debug("Failed to allocate area map texture\n");
+ goto fail;
+ }
+
u_box_2d(0, 0, 165, 165, &box);
- ppq->p->pipe->transfer_inline_write(ppq->p->pipe, areamaptex, 0,
+ ppq->p->pipe->transfer_inline_write(ppq->p->pipe, ppq->areamaptex, 0,
PIPE_TRANSFER_WRITE, &box,
areamap, 165 * 2, sizeof(areamap));
-
-
ppq->shaders[n][1] = pp_tgsi_to_state(ppq->p->pipe, offsetvs, true,
"offsetvs");
if (iscolor)
"neigh3fs");
FREE(tmp_text);
+
+ return TRUE;
+
+ fail:
+
+ FREE(tmp_text);
+
+ /*
+ * Call the common free function for destruction of partially initialized
+ * resources.
+ */
+ pp_jimenezmlaa_free(ppq, n);
+
+ return FALSE;
}
/** Short wrapper to init the depth version. */
-void
+bool
pp_jimenezmlaa_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val)
{
-
- pp_jimenezmlaa_init_run(ppq, n, val, false);
+ return pp_jimenezmlaa_init_run(ppq, n, val, false);
}
/** Short wrapper to init the color version. */
-void
+bool
pp_jimenezmlaa_init_color(struct pp_queue_t *ppq, unsigned int n,
unsigned int val)
{
-
- pp_jimenezmlaa_init_run(ppq, n, val, true);
+ return pp_jimenezmlaa_init_run(ppq, n, val, true);
}
/** Short wrapper to run the depth version. */
{
pp_jimenezmlaa_run(ppq, in, out, n, true);
}
+
+
+/**
+ * Short wrapper to free the mlaa filter resources. Shaders are freed in
+ * the common code in pp_free.
+ */
+void
+pp_jimenezmlaa_free(struct pp_queue_t *ppq, unsigned int n)
+{
+ if (ppq->areamaptex) {
+ ppq->p->screen->resource_destroy(ppq->p->screen, ppq->areamaptex);
+ ppq->areamaptex = NULL;
+ }
+
+ if (ppq->constbuf) {
+ ppq->p->screen->resource_destroy(ppq->p->screen, ppq->constbuf);
+ ppq->constbuf = NULL;
+ }
+}
+
#include "util/u_inlines.h"
#include "util/u_sampler.h"
+#include "tgsi/tgsi_parse.h"
+
/**
* Main run function of the PP queue. Called on swapbuffers/flush.
*
unsigned int i;
struct cso_context *cso = ppq->p->cso;
+ if (ppq->n_filters == 0)
+ return;
+
+ assert(ppq->pp_queue);
+ assert(ppq->tmp[0]);
+ assert(ppq->tmp[1]);
+
if (in->width0 != ppq->p->framebuffer.width ||
in->height0 != ppq->p->framebuffer.height) {
pp_debug("Resizing the temp pp buffers\n");
pipe_resource_reference(&refout, out);
switch (ppq->n_filters) {
+ case 0:
+ /* Failsafe, but never reached. */
+ break;
case 1: /* No temp buf */
ppq->pp_queue[0] (ppq, in, out, 0);
break;
const char *name)
{
struct pipe_shader_state state;
- struct tgsi_token tokens[PP_MAX_TOKENS];
+ struct tgsi_token *tokens = NULL;
+ void *ret_state = NULL;
+
+ /*
+ * Allocate temporary token storage. State creation will duplicate
+ * tokens so we must free them on exit.
+ */
+ tokens = tgsi_alloc_tokens(PP_MAX_TOKENS);
+
+ if (tokens == NULL) {
+ pp_debug("Failed to allocate temporary token storage.\n");
+ return NULL;
+ }
if (tgsi_text_translate(text, tokens, Elements(tokens)) == FALSE) {
pp_debug("Failed to translate %s\n", name);
state.tokens = tokens;
memset(&state.stream_output, 0, sizeof(state.stream_output));
- if (isvs)
- return pipe->create_vs_state(pipe, &state);
- else
- return pipe->create_fs_state(pipe, &state);
+ if (isvs) {
+ ret_state = pipe->create_vs_state(pipe, &state);
+ FREE(tokens);
+ } else {
+ ret_state = pipe->create_fs_state(pipe, &state);
+ FREE(tokens);
+ }
+
+ return ret_state;
}
/** Setup misc state for the filter. */