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