1 /** 2 * Copyright (C) 2010 Jorge Jimenez (jorge (at) iryoku.com) 3 * Copyright (C) 2010 Belen Masia (bmasia (at) unizar.es) 4 * Copyright (C) 2010 Jose I. Echevarria (joseignacioechevarria (at) gmail.com) 5 * Copyright (C) 2010 Fernando Navarro (fernandn (at) microsoft.com) 6 * Copyright (C) 2010 Diego Gutierrez (diegog (at) unizar.es) 7 * Copyright (C) 2011 Lauri Kasanen (cand (at) gmx.com) 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the following statement: 17 * 18 * "Uses Jimenez's MLAA. Copyright (C) 2010 by Jorge Jimenez, Belen Masia, 19 * Jose I. Echevarria, Fernando Navarro and Diego Gutierrez." 20 * 21 * Only for use in the Mesa project, this point 2 is filled by naming the 22 * technique Jimenez's MLAA in the Mesa config options. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 25 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 * 36 * The views and conclusions contained in the software and documentation are 37 * those of the authors and should not be interpreted as representing official 38 * policies, either expressed or implied, of the copyright holders. 39 */ 40 41 #include "pipe/p_compiler.h" 42 43 #include "postprocess/postprocess.h" 44 #include "postprocess/pp_mlaa.h" 45 #include "postprocess/pp_filters.h" 46 #include "postprocess/pp_private.h" 47 48 #include "util/u_box.h" 49 #include "util/u_sampler.h" 50 #include "util/u_inlines.h" 51 #include "util/u_memory.h" 52 #include "util/u_string.h" 53 #include "pipe/p_screen.h" 54 55 #define IMM_SPACE 80 56 57 static float constants[] = { 1, 1, 0, 0 }; 58 static unsigned int dimensions[2] = { 0, 0 }; 59 60 /** Upload the constants. */ 61 static void 62 up_consts(struct pp_queue_t *ppq) 63 { 64 struct pipe_context *pipe = ppq->p->pipe; 65 66 pipe->buffer_subdata(pipe, ppq->constbuf, PIPE_TRANSFER_WRITE, 67 0, sizeof(constants), constants); 68 } 69 70 /** Run function of the MLAA filter. */ 71 static void 72 pp_jimenezmlaa_run(struct pp_queue_t *ppq, struct pipe_resource *in, 73 struct pipe_resource *out, unsigned int n, bool iscolor) 74 { 75 76 struct pp_program *p = ppq->p; 77 78 struct pipe_depth_stencil_alpha_state mstencil; 79 struct pipe_sampler_view v_tmp, *arr[3]; 80 81 unsigned int w = 0; 82 unsigned int h = 0; 83 84 const struct pipe_stencil_ref ref = { {1} }; 85 86 /* Insufficient initialization checks. */ 87 assert(p); 88 assert(ppq); 89 assert(ppq->constbuf); 90 assert(ppq->areamaptex); 91 assert(ppq->inner_tmp); 92 assert(ppq->shaders[n]); 93 94 w = p->framebuffer.width; 95 h = p->framebuffer.height; 96 97 memset(&mstencil, 0, sizeof(mstencil)); 98 99 cso_set_stencil_ref(p->cso, &ref); 100 101 /* Init the pixel size constant */ 102 if (dimensions[0] != p->framebuffer.width || 103 dimensions[1] != p->framebuffer.height) { 104 constants[0] = 1.0f / p->framebuffer.width; 105 constants[1] = 1.0f / p->framebuffer.height; 106 107 up_consts(ppq); 108 dimensions[0] = p->framebuffer.width; 109 dimensions[1] = p->framebuffer.height; 110 } 111 112 cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_VERTEX, 113 0, ppq->constbuf); 114 cso_set_constant_buffer_resource(p->cso, PIPE_SHADER_FRAGMENT, 115 0, ppq->constbuf); 116 117 mstencil.stencil[0].enabled = 1; 118 mstencil.stencil[0].valuemask = mstencil.stencil[0].writemask = ~0; 119 mstencil.stencil[0].func = PIPE_FUNC_ALWAYS; 120 mstencil.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 121 mstencil.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 122 mstencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; 123 124 p->framebuffer.zsbuf = ppq->stencils; 125 126 /* First pass: depth edge detection */ 127 if (iscolor) 128 pp_filter_setup_in(p, in); 129 else 130 pp_filter_setup_in(p, ppq->depth); 131 132 pp_filter_setup_out(p, ppq->inner_tmp[0]); 133 134 pp_filter_set_fb(p); 135 pp_filter_misc_state(p); 136 cso_set_depth_stencil_alpha(p->cso, &mstencil); 137 p->pipe->clear(p->pipe, PIPE_CLEAR_STENCIL | PIPE_CLEAR_COLOR0, 138 &p->clear_color, 0, 0); 139 140 { 141 const struct pipe_sampler_state *samplers[] = {&p->sampler_point}; 142 cso_set_samplers(p->cso, PIPE_SHADER_FRAGMENT, 1, samplers); 143 } 144 cso_set_sampler_views(p->cso, PIPE_SHADER_FRAGMENT, 1, &p->view); 145 146 cso_set_vertex_shader_handle(p->cso, ppq->shaders[n][1]); /* offsetvs */ 147 cso_set_fragment_shader_handle(p->cso, ppq->shaders[n][2]); 148 149 pp_filter_draw(p); 150 pp_filter_end_pass(p); 151 152 153 /* Second pass: blend weights */ 154 /* Sampler order: areamap, edgesmap, edgesmapL (reversed, thx compiler) */ 155 mstencil.stencil[0].func = PIPE_FUNC_EQUAL; 156 mstencil.stencil[0].zpass_op = PIPE_STENCIL_OP_KEEP; 157 cso_set_depth_stencil_alpha(p->cso, &mstencil); 158 159 pp_filter_setup_in(p, ppq->areamaptex); 160 pp_filter_setup_out(p, ppq->inner_tmp[1]); 161 162 u_sampler_view_default_template(&v_tmp, ppq->inner_tmp[0], 163 ppq->inner_tmp[0]->format); 164 arr[1] = arr[2] = p->pipe->create_sampler_view(p->pipe, 165 ppq->inner_tmp[0], &v_tmp); 166 167 pp_filter_set_clear_fb(p); 168 169 { 170 const struct pipe_sampler_state *samplers[] = 171 {&p->sampler_point, &p->sampler_point, &p->sampler}; 172 cso_set_samplers(p->cso, PIPE_SHADER_FRAGMENT, 3, samplers); 173 } 174 175 arr[0] = p->view; 176 cso_set_sampler_views(p->cso, PIPE_SHADER_FRAGMENT, 3, arr); 177 178 cso_set_vertex_shader_handle(p->cso, ppq->shaders[n][0]); /* passvs */ 179 cso_set_fragment_shader_handle(p->cso, ppq->shaders[n][3]); 180 181 pp_filter_draw(p); 182 pp_filter_end_pass(p); 183 pipe_sampler_view_reference(&arr[1], NULL); 184 185 186 /* Third pass: smoothed edges */ 187 /* Sampler order: colormap, blendmap (wtf compiler) */ 188 pp_filter_setup_in(p, ppq->inner_tmp[1]); 189 pp_filter_setup_out(p, out); 190 191 pp_filter_set_fb(p); 192 193 /* Blit the input to the output */ 194 pp_blit(p->pipe, in, 0, 0, 195 w, h, 0, p->framebuffer.cbufs[0], 196 0, 0, w, h); 197 198 u_sampler_view_default_template(&v_tmp, in, in->format); 199 arr[0] = p->pipe->create_sampler_view(p->pipe, in, &v_tmp); 200 201 { 202 const struct pipe_sampler_state *samplers[] = 203 {&p->sampler_point, &p->sampler_point}; 204 cso_set_samplers(p->cso, PIPE_SHADER_FRAGMENT, 2, samplers); 205 } 206 207 arr[1] = p->view; 208 cso_set_sampler_views(p->cso, PIPE_SHADER_FRAGMENT, 2, arr); 209 210 cso_set_vertex_shader_handle(p->cso, ppq->shaders[n][1]); /* offsetvs */ 211 cso_set_fragment_shader_handle(p->cso, ppq->shaders[n][4]); 212 213 p->blend.rt[0].blend_enable = 1; 214 cso_set_blend(p->cso, &p->blend); 215 216 pp_filter_draw(p); 217 pp_filter_end_pass(p); 218 pipe_sampler_view_reference(&arr[0], NULL); 219 220 p->blend.rt[0].blend_enable = 0; 221 p->framebuffer.zsbuf = NULL; 222 } 223 224 /** The init function of the MLAA filter. */ 225 static bool 226 pp_jimenezmlaa_init_run(struct pp_queue_t *ppq, unsigned int n, 227 unsigned int val, bool iscolor) 228 { 229 230 struct pipe_box box; 231 struct pipe_resource res; 232 char *tmp_text = NULL; 233 234 tmp_text = CALLOC(sizeof(blend2fs_1) + sizeof(blend2fs_2) + 235 IMM_SPACE, sizeof(char)); 236 237 if (!tmp_text) { 238 pp_debug("Failed to allocate shader space\n"); 239 return FALSE; 240 } 241 242 ppq->constbuf = pipe_buffer_create(ppq->p->screen, 243 PIPE_BIND_CONSTANT_BUFFER, 244 PIPE_USAGE_DEFAULT, 245 sizeof(constants)); 246 if (ppq->constbuf == NULL) { 247 pp_debug("Failed to allocate constant buffer\n"); 248 goto fail; 249 } 250 251 pp_debug("mlaa: using %u max search steps\n", val); 252 253 util_sprintf(tmp_text, "%s" 254 "IMM FLT32 { %.8f, 0.0000, 0.0000, 0.0000}\n" 255 "%s\n", blend2fs_1, (float) val, blend2fs_2); 256 257 memset(&res, 0, sizeof(res)); 258 259 res.target = PIPE_TEXTURE_2D; 260 res.format = PIPE_FORMAT_R8G8_UNORM; 261 res.width0 = res.height0 = 165; 262 res.bind = PIPE_BIND_SAMPLER_VIEW; 263 res.usage = PIPE_USAGE_DEFAULT; 264 res.depth0 = res.array_size = res.nr_samples = 1; 265 266 if (!ppq->p->screen->is_format_supported(ppq->p->screen, res.format, 267 res.target, 1, res.bind)) 268 pp_debug("Areamap format not supported\n"); 269 270 ppq->areamaptex = ppq->p->screen->resource_create(ppq->p->screen, &res); 271 272 if (ppq->areamaptex == NULL) { 273 pp_debug("Failed to allocate area map texture\n"); 274 goto fail; 275 } 276 277 u_box_2d(0, 0, 165, 165, &box); 278 279 ppq->p->pipe->texture_subdata(ppq->p->pipe, ppq->areamaptex, 0, 280 PIPE_TRANSFER_WRITE, &box, 281 areamap, 165 * 2, sizeof(areamap)); 282 283 ppq->shaders[n][1] = pp_tgsi_to_state(ppq->p->pipe, offsetvs, true, 284 "offsetvs"); 285 if (iscolor) 286 ppq->shaders[n][2] = pp_tgsi_to_state(ppq->p->pipe, color1fs, 287 false, "color1fs"); 288 else 289 ppq->shaders[n][2] = pp_tgsi_to_state(ppq->p->pipe, depth1fs, 290 false, "depth1fs"); 291 ppq->shaders[n][3] = pp_tgsi_to_state(ppq->p->pipe, tmp_text, false, 292 "blend2fs"); 293 ppq->shaders[n][4] = pp_tgsi_to_state(ppq->p->pipe, neigh3fs, false, 294 "neigh3fs"); 295 296 FREE(tmp_text); 297 298 return TRUE; 299 300 fail: 301 302 FREE(tmp_text); 303 304 /* 305 * Call the common free function for destruction of partially initialized 306 * resources. 307 */ 308 pp_jimenezmlaa_free(ppq, n); 309 310 return FALSE; 311 } 312 313 /** Short wrapper to init the depth version. */ 314 bool 315 pp_jimenezmlaa_init(struct pp_queue_t *ppq, unsigned int n, unsigned int val) 316 { 317 return pp_jimenezmlaa_init_run(ppq, n, val, false); 318 } 319 320 /** Short wrapper to init the color version. */ 321 bool 322 pp_jimenezmlaa_init_color(struct pp_queue_t *ppq, unsigned int n, 323 unsigned int val) 324 { 325 return pp_jimenezmlaa_init_run(ppq, n, val, true); 326 } 327 328 /** Short wrapper to run the depth version. */ 329 void 330 pp_jimenezmlaa(struct pp_queue_t *ppq, struct pipe_resource *in, 331 struct pipe_resource *out, unsigned int n) 332 { 333 if (!ppq->depth) { 334 return; 335 } 336 pp_jimenezmlaa_run(ppq, in, out, n, false); 337 } 338 339 /** Short wrapper to run the color version. */ 340 void 341 pp_jimenezmlaa_color(struct pp_queue_t *ppq, struct pipe_resource *in, 342 struct pipe_resource *out, unsigned int n) 343 { 344 pp_jimenezmlaa_run(ppq, in, out, n, true); 345 } 346 347 348 /** 349 * Short wrapper to free the mlaa filter resources. Shaders are freed in 350 * the common code in pp_free. 351 */ 352 void 353 pp_jimenezmlaa_free(struct pp_queue_t *ppq, unsigned int n) 354 { 355 if (ppq->areamaptex) { 356 pipe_resource_reference(&ppq->areamaptex, NULL); 357 } 358 359 if (ppq->constbuf) { 360 pipe_resource_reference(&ppq->constbuf, NULL); 361 } 362 } 363 364