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