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 "postprocess.h" 29bf215546Sopenharmony_ci#include "postprocess/pp_filters.h" 30bf215546Sopenharmony_ci#include "postprocess/pp_private.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "frontend/api.h" 33bf215546Sopenharmony_ci#include "util/u_inlines.h" 34bf215546Sopenharmony_ci#include "util/u_sampler.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "tgsi/tgsi_parse.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_civoid 40bf215546Sopenharmony_cipp_blit(struct pipe_context *pipe, 41bf215546Sopenharmony_ci struct pipe_resource *src_tex, 42bf215546Sopenharmony_ci int srcX0, int srcY0, 43bf215546Sopenharmony_ci int srcX1, int srcY1, 44bf215546Sopenharmony_ci int srcZ0, 45bf215546Sopenharmony_ci struct pipe_surface *dst, 46bf215546Sopenharmony_ci int dstX0, int dstY0, 47bf215546Sopenharmony_ci int dstX1, int dstY1) 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_ci struct pipe_blit_info blit; 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci memset(&blit, 0, sizeof(blit)); 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci blit.src.resource = src_tex; 54bf215546Sopenharmony_ci blit.src.level = 0; 55bf215546Sopenharmony_ci blit.src.format = src_tex->format; 56bf215546Sopenharmony_ci blit.src.box.x = srcX0; 57bf215546Sopenharmony_ci blit.src.box.y = srcY0; 58bf215546Sopenharmony_ci blit.src.box.z = srcZ0; 59bf215546Sopenharmony_ci blit.src.box.width = srcX1 - srcX0; 60bf215546Sopenharmony_ci blit.src.box.height = srcY1 - srcY0; 61bf215546Sopenharmony_ci blit.src.box.depth = 1; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci blit.dst.resource = dst->texture; 64bf215546Sopenharmony_ci blit.dst.level = dst->u.tex.level; 65bf215546Sopenharmony_ci blit.dst.format = dst->format; 66bf215546Sopenharmony_ci blit.dst.box.x = dstX0; 67bf215546Sopenharmony_ci blit.dst.box.y = dstY0; 68bf215546Sopenharmony_ci blit.dst.box.z = 0; 69bf215546Sopenharmony_ci blit.dst.box.width = dstX1 - dstX0; 70bf215546Sopenharmony_ci blit.dst.box.height = dstY1 - dstY0; 71bf215546Sopenharmony_ci blit.dst.box.depth = 1; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci blit.mask = PIPE_MASK_RGBA; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci pipe->blit(pipe, &blit); 76bf215546Sopenharmony_ci} 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci/** 79bf215546Sopenharmony_ci* Main run function of the PP queue. Called on swapbuffers/flush. 80bf215546Sopenharmony_ci* 81bf215546Sopenharmony_ci* Runs all requested filters in order and handles shuffling the temp 82bf215546Sopenharmony_ci* buffers in between. 83bf215546Sopenharmony_ci*/ 84bf215546Sopenharmony_civoid 85bf215546Sopenharmony_cipp_run(struct pp_queue_t *ppq, struct pipe_resource *in, 86bf215546Sopenharmony_ci struct pipe_resource *out, struct pipe_resource *indepth) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci struct pipe_resource *refin = NULL, *refout = NULL; 89bf215546Sopenharmony_ci unsigned int i; 90bf215546Sopenharmony_ci struct cso_context *cso = ppq->p->cso; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci if (ppq->n_filters == 0) 93bf215546Sopenharmony_ci return; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci assert(ppq->pp_queue); 96bf215546Sopenharmony_ci assert(ppq->tmp[0]); 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (in->width0 != ppq->p->framebuffer.width || 99bf215546Sopenharmony_ci in->height0 != ppq->p->framebuffer.height) { 100bf215546Sopenharmony_ci pp_debug("Resizing the temp pp buffers\n"); 101bf215546Sopenharmony_ci pp_free_fbos(ppq); 102bf215546Sopenharmony_ci pp_init_fbos(ppq, in->width0, in->height0); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (in == out && ppq->n_filters == 1) { 106bf215546Sopenharmony_ci /* Make a copy of in to tmp[0] in this case. */ 107bf215546Sopenharmony_ci unsigned int w = ppq->p->framebuffer.width; 108bf215546Sopenharmony_ci unsigned int h = ppq->p->framebuffer.height; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci pp_blit(ppq->p->pipe, in, 0, 0, 112bf215546Sopenharmony_ci w, h, 0, ppq->tmps[0], 113bf215546Sopenharmony_ci 0, 0, w, h); 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci in = ppq->tmp[0]; 116bf215546Sopenharmony_ci } 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci /* save state (restored below) */ 119bf215546Sopenharmony_ci cso_save_state(cso, (CSO_BIT_BLEND | 120bf215546Sopenharmony_ci CSO_BIT_DEPTH_STENCIL_ALPHA | 121bf215546Sopenharmony_ci CSO_BIT_FRAGMENT_SHADER | 122bf215546Sopenharmony_ci CSO_BIT_FRAMEBUFFER | 123bf215546Sopenharmony_ci CSO_BIT_TESSCTRL_SHADER | 124bf215546Sopenharmony_ci CSO_BIT_TESSEVAL_SHADER | 125bf215546Sopenharmony_ci CSO_BIT_GEOMETRY_SHADER | 126bf215546Sopenharmony_ci CSO_BIT_RASTERIZER | 127bf215546Sopenharmony_ci CSO_BIT_SAMPLE_MASK | 128bf215546Sopenharmony_ci CSO_BIT_MIN_SAMPLES | 129bf215546Sopenharmony_ci CSO_BIT_FRAGMENT_SAMPLERS | 130bf215546Sopenharmony_ci CSO_BIT_STENCIL_REF | 131bf215546Sopenharmony_ci CSO_BIT_STREAM_OUTPUTS | 132bf215546Sopenharmony_ci CSO_BIT_VERTEX_ELEMENTS | 133bf215546Sopenharmony_ci CSO_BIT_VERTEX_SHADER | 134bf215546Sopenharmony_ci CSO_BIT_VIEWPORT | 135bf215546Sopenharmony_ci CSO_BIT_PAUSE_QUERIES | 136bf215546Sopenharmony_ci CSO_BIT_RENDER_CONDITION)); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci /* set default state */ 139bf215546Sopenharmony_ci cso_set_sample_mask(cso, ~0); 140bf215546Sopenharmony_ci cso_set_min_samples(cso, 1); 141bf215546Sopenharmony_ci cso_set_stream_outputs(cso, 0, NULL, NULL); 142bf215546Sopenharmony_ci cso_set_tessctrl_shader_handle(cso, NULL); 143bf215546Sopenharmony_ci cso_set_tesseval_shader_handle(cso, NULL); 144bf215546Sopenharmony_ci cso_set_geometry_shader_handle(cso, NULL); 145bf215546Sopenharmony_ci cso_set_render_condition(cso, NULL, FALSE, 0); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci // Kept only for this frame. 148bf215546Sopenharmony_ci pipe_resource_reference(&ppq->depth, indepth); 149bf215546Sopenharmony_ci pipe_resource_reference(&refin, in); 150bf215546Sopenharmony_ci pipe_resource_reference(&refout, out); 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci switch (ppq->n_filters) { 153bf215546Sopenharmony_ci case 0: 154bf215546Sopenharmony_ci /* Failsafe, but never reached. */ 155bf215546Sopenharmony_ci break; 156bf215546Sopenharmony_ci case 1: /* No temp buf */ 157bf215546Sopenharmony_ci ppq->pp_queue[0] (ppq, in, out, 0); 158bf215546Sopenharmony_ci break; 159bf215546Sopenharmony_ci case 2: /* One temp buf */ 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0); 162bf215546Sopenharmony_ci ppq->pp_queue[1] (ppq, ppq->tmp[0], out, 1); 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci break; 165bf215546Sopenharmony_ci default: /* Two temp bufs */ 166bf215546Sopenharmony_ci assert(ppq->tmp[1]); 167bf215546Sopenharmony_ci ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci for (i = 1; i < (ppq->n_filters - 1); i++) { 170bf215546Sopenharmony_ci if (i % 2 == 0) 171bf215546Sopenharmony_ci ppq->pp_queue[i] (ppq, ppq->tmp[1], ppq->tmp[0], i); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci else 174bf215546Sopenharmony_ci ppq->pp_queue[i] (ppq, ppq->tmp[0], ppq->tmp[1], i); 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci if (i % 2 == 0) 178bf215546Sopenharmony_ci ppq->pp_queue[i] (ppq, ppq->tmp[1], out, i); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci else 181bf215546Sopenharmony_ci ppq->pp_queue[i] (ppq, ppq->tmp[0], out, i); 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci break; 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci /* restore state we changed */ 187bf215546Sopenharmony_ci cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS | 188bf215546Sopenharmony_ci CSO_UNBIND_FS_IMAGE0 | 189bf215546Sopenharmony_ci CSO_UNBIND_VS_CONSTANTS | 190bf215546Sopenharmony_ci CSO_UNBIND_FS_CONSTANTS | 191bf215546Sopenharmony_ci CSO_UNBIND_VERTEX_BUFFER0); 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci /* restore states not restored by cso */ 194bf215546Sopenharmony_ci if (ppq->p->st) { 195bf215546Sopenharmony_ci ppq->p->st->invalidate_state(ppq->p->st, 196bf215546Sopenharmony_ci ST_INVALIDATE_FS_SAMPLER_VIEWS | 197bf215546Sopenharmony_ci ST_INVALIDATE_FS_CONSTBUF0 | 198bf215546Sopenharmony_ci ST_INVALIDATE_VS_CONSTBUF0 | 199bf215546Sopenharmony_ci ST_INVALIDATE_VERTEX_BUFFERS); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci pipe_resource_reference(&ppq->depth, NULL); 203bf215546Sopenharmony_ci pipe_resource_reference(&refin, NULL); 204bf215546Sopenharmony_ci pipe_resource_reference(&refout, NULL); 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci/* Utility functions for the filters. You're not forced to use these if */ 209bf215546Sopenharmony_ci/* your filter is more complicated. */ 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci/** Setup this resource as the filter input. */ 212bf215546Sopenharmony_civoid 213bf215546Sopenharmony_cipp_filter_setup_in(struct pp_program *p, struct pipe_resource *in) 214bf215546Sopenharmony_ci{ 215bf215546Sopenharmony_ci struct pipe_sampler_view v_tmp; 216bf215546Sopenharmony_ci u_sampler_view_default_template(&v_tmp, in, in->format); 217bf215546Sopenharmony_ci p->view = p->pipe->create_sampler_view(p->pipe, in, &v_tmp); 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci/** Setup this resource as the filter output. */ 221bf215546Sopenharmony_civoid 222bf215546Sopenharmony_cipp_filter_setup_out(struct pp_program *p, struct pipe_resource *out) 223bf215546Sopenharmony_ci{ 224bf215546Sopenharmony_ci p->surf.format = out->format; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci p->framebuffer.cbufs[0] = p->pipe->create_surface(p->pipe, out, &p->surf); 227bf215546Sopenharmony_ci} 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci/** Clean up the input and output set with the above. */ 230bf215546Sopenharmony_civoid 231bf215546Sopenharmony_cipp_filter_end_pass(struct pp_program *p) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci pipe_surface_reference(&p->framebuffer.cbufs[0], NULL); 234bf215546Sopenharmony_ci pipe_sampler_view_reference(&p->view, NULL); 235bf215546Sopenharmony_ci} 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci/** 238bf215546Sopenharmony_ci* Convert the TGSI assembly to a runnable shader. 239bf215546Sopenharmony_ci* 240bf215546Sopenharmony_ci* We need not care about geometry shaders. All we have is screen quads. 241bf215546Sopenharmony_ci*/ 242bf215546Sopenharmony_civoid * 243bf215546Sopenharmony_cipp_tgsi_to_state(struct pipe_context *pipe, const char *text, bool isvs, 244bf215546Sopenharmony_ci const char *name) 245bf215546Sopenharmony_ci{ 246bf215546Sopenharmony_ci struct pipe_shader_state state; 247bf215546Sopenharmony_ci struct tgsi_token *tokens = NULL; 248bf215546Sopenharmony_ci void *ret_state = NULL; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci /* 251bf215546Sopenharmony_ci * Allocate temporary token storage. State creation will duplicate 252bf215546Sopenharmony_ci * tokens so we must free them on exit. 253bf215546Sopenharmony_ci */ 254bf215546Sopenharmony_ci tokens = tgsi_alloc_tokens(PP_MAX_TOKENS); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci if (!tokens) { 257bf215546Sopenharmony_ci pp_debug("Failed to allocate temporary token storage.\n"); 258bf215546Sopenharmony_ci return NULL; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if (tgsi_text_translate(text, tokens, PP_MAX_TOKENS) == FALSE) { 262bf215546Sopenharmony_ci _debug_printf("pp: Failed to translate a shader for %s\n", name); 263bf215546Sopenharmony_ci return NULL; 264bf215546Sopenharmony_ci } 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci pipe_shader_state_from_tgsi(&state, tokens); 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci if (isvs) { 269bf215546Sopenharmony_ci ret_state = pipe->create_vs_state(pipe, &state); 270bf215546Sopenharmony_ci FREE(tokens); 271bf215546Sopenharmony_ci } else { 272bf215546Sopenharmony_ci ret_state = pipe->create_fs_state(pipe, &state); 273bf215546Sopenharmony_ci FREE(tokens); 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci return ret_state; 277bf215546Sopenharmony_ci} 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci/** Setup misc state for the filter. */ 280bf215546Sopenharmony_civoid 281bf215546Sopenharmony_cipp_filter_misc_state(struct pp_program *p) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci cso_set_blend(p->cso, &p->blend); 284bf215546Sopenharmony_ci cso_set_depth_stencil_alpha(p->cso, &p->depthstencil); 285bf215546Sopenharmony_ci cso_set_rasterizer(p->cso, &p->rasterizer); 286bf215546Sopenharmony_ci cso_set_viewport(p->cso, &p->viewport); 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci cso_set_vertex_elements(p->cso, &p->velem); 289bf215546Sopenharmony_ci} 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci/** Draw with the filter to the set output. */ 292bf215546Sopenharmony_civoid 293bf215546Sopenharmony_cipp_filter_draw(struct pp_program *p) 294bf215546Sopenharmony_ci{ 295bf215546Sopenharmony_ci util_draw_vertex_buffer(p->pipe, p->cso, p->vbuf, 0, 0, 296bf215546Sopenharmony_ci PIPE_PRIM_QUADS, 4, 2); 297bf215546Sopenharmony_ci} 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci/** Set the framebuffer as active. */ 300bf215546Sopenharmony_civoid 301bf215546Sopenharmony_cipp_filter_set_fb(struct pp_program *p) 302bf215546Sopenharmony_ci{ 303bf215546Sopenharmony_ci cso_set_framebuffer(p->cso, &p->framebuffer); 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci/** Set the framebuffer as active and clear it. */ 307bf215546Sopenharmony_civoid 308bf215546Sopenharmony_cipp_filter_set_clear_fb(struct pp_program *p) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci cso_set_framebuffer(p->cso, &p->framebuffer); 311bf215546Sopenharmony_ci p->pipe->clear(p->pipe, PIPE_CLEAR_COLOR0, NULL, &p->clear_color, 0, 0); 312bf215546Sopenharmony_ci} 313