llvmpipe/tests: update arith test to check for edge cases
[mesa.git] / src / gallium / auxiliary / postprocess / pp_run.c
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
30 #include "postprocess/pp_filters.h"
31 #include "util/u_blit.h"
32 #include "util/u_inlines.h"
33 #include "util/u_sampler.h"
34
35 #include "tgsi/tgsi_parse.h"
36
37 /**
38 * Main run function of the PP queue. Called on swapbuffers/flush.
39 *
40 * Runs all requested filters in order and handles shuffling the temp
41 * buffers in between.
42 */
43 void
44 pp_run(struct pp_queue_t *ppq, struct pipe_resource *in,
45 struct pipe_resource *out, struct pipe_resource *indepth)
46 {
47 struct pipe_resource *refin = NULL, *refout = NULL;
48 unsigned int i;
49 struct cso_context *cso = ppq->p->cso;
50
51 if (ppq->n_filters == 0)
52 return;
53
54 assert(ppq->pp_queue);
55 assert(ppq->tmp[0]);
56
57 if (in->width0 != ppq->p->framebuffer.width ||
58 in->height0 != ppq->p->framebuffer.height) {
59 pp_debug("Resizing the temp pp buffers\n");
60 pp_free_fbos(ppq);
61 pp_init_fbos(ppq, in->width0, in->height0);
62 }
63
64 if (in == out && ppq->n_filters == 1) {
65 /* Make a copy of in to tmp[0] in this case. */
66 unsigned int w = ppq->p->framebuffer.width;
67 unsigned int h = ppq->p->framebuffer.height;
68
69 util_blit_pixels(ppq->p->blitctx, in, 0, 0, 0,
70 w, h, 0, ppq->tmps[0],
71 0, 0, w, h, 0, PIPE_TEX_MIPFILTER_NEAREST,
72 TGSI_WRITEMASK_XYZW, 0);
73
74 in = ppq->tmp[0];
75 }
76
77 /* save state (restored below) */
78 cso_save_blend(cso);
79 cso_save_depth_stencil_alpha(cso);
80 cso_save_fragment_shader(cso);
81 cso_save_framebuffer(cso);
82 cso_save_geometry_shader(cso);
83 cso_save_rasterizer(cso);
84 cso_save_sample_mask(cso);
85 cso_save_samplers(cso, PIPE_SHADER_FRAGMENT);
86 cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT);
87 cso_save_stencil_ref(cso);
88 cso_save_stream_outputs(cso);
89 cso_save_vertex_elements(cso);
90 cso_save_vertex_shader(cso);
91 cso_save_viewport(cso);
92 cso_save_aux_vertex_buffer_slot(cso);
93 cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
94 cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
95 cso_save_render_condition(cso);
96
97 /* set default state */
98 cso_set_sample_mask(cso, ~0);
99 cso_set_stream_outputs(cso, 0, NULL, 0);
100 cso_set_geometry_shader_handle(cso, NULL);
101 cso_set_render_condition(cso, NULL, FALSE, 0);
102
103 // Kept only for this frame.
104 pipe_resource_reference(&ppq->depth, indepth);
105 pipe_resource_reference(&refin, in);
106 pipe_resource_reference(&refout, out);
107
108 switch (ppq->n_filters) {
109 case 0:
110 /* Failsafe, but never reached. */
111 break;
112 case 1: /* No temp buf */
113 ppq->pp_queue[0] (ppq, in, out, 0);
114 break;
115 case 2: /* One temp buf */
116
117 ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0);
118 ppq->pp_queue[1] (ppq, ppq->tmp[0], out, 1);
119
120 break;
121 default: /* Two temp bufs */
122 assert(ppq->tmp[1]);
123 ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0);
124
125 for (i = 1; i < (ppq->n_filters - 1); i++) {
126 if (i % 2 == 0)
127 ppq->pp_queue[i] (ppq, ppq->tmp[1], ppq->tmp[0], i);
128
129 else
130 ppq->pp_queue[i] (ppq, ppq->tmp[0], ppq->tmp[1], i);
131 }
132
133 if (i % 2 == 0)
134 ppq->pp_queue[i] (ppq, ppq->tmp[1], out, i);
135
136 else
137 ppq->pp_queue[i] (ppq, ppq->tmp[0], out, i);
138
139 break;
140 }
141
142 /* restore state we changed */
143 cso_restore_blend(cso);
144 cso_restore_depth_stencil_alpha(cso);
145 cso_restore_fragment_shader(cso);
146 cso_restore_framebuffer(cso);
147 cso_restore_geometry_shader(cso);
148 cso_restore_rasterizer(cso);
149 cso_restore_sample_mask(cso);
150 cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT);
151 cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT);
152 cso_restore_stencil_ref(cso);
153 cso_restore_stream_outputs(cso);
154 cso_restore_vertex_elements(cso);
155 cso_restore_vertex_shader(cso);
156 cso_restore_viewport(cso);
157 cso_restore_aux_vertex_buffer_slot(cso);
158 cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
159 cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
160 cso_restore_render_condition(cso);
161
162 pipe_resource_reference(&ppq->depth, NULL);
163 pipe_resource_reference(&refin, NULL);
164 pipe_resource_reference(&refout, NULL);
165 }
166
167
168 /* Utility functions for the filters. You're not forced to use these if */
169 /* your filter is more complicated. */
170
171 /** Setup this resource as the filter input. */
172 void
173 pp_filter_setup_in(struct program *p, struct pipe_resource *in)
174 {
175 struct pipe_sampler_view v_tmp;
176 u_sampler_view_default_template(&v_tmp, in, in->format);
177 p->view = p->pipe->create_sampler_view(p->pipe, in, &v_tmp);
178 }
179
180 /** Setup this resource as the filter output. */
181 void
182 pp_filter_setup_out(struct program *p, struct pipe_resource *out)
183 {
184 p->surf.format = out->format;
185
186 p->framebuffer.cbufs[0] = p->pipe->create_surface(p->pipe, out, &p->surf);
187 }
188
189 /** Clean up the input and output set with the above. */
190 void
191 pp_filter_end_pass(struct program *p)
192 {
193 pipe_surface_reference(&p->framebuffer.cbufs[0], NULL);
194 pipe_sampler_view_reference(&p->view, NULL);
195 }
196
197 /**
198 * Convert the TGSI assembly to a runnable shader.
199 *
200 * We need not care about geometry shaders. All we have is screen quads.
201 */
202 void *
203 pp_tgsi_to_state(struct pipe_context *pipe, const char *text, bool isvs,
204 const char *name)
205 {
206 struct pipe_shader_state state;
207 struct tgsi_token *tokens = NULL;
208 void *ret_state = NULL;
209
210 /*
211 * Allocate temporary token storage. State creation will duplicate
212 * tokens so we must free them on exit.
213 */
214 tokens = tgsi_alloc_tokens(PP_MAX_TOKENS);
215
216 if (tokens == NULL) {
217 pp_debug("Failed to allocate temporary token storage.\n");
218 return NULL;
219 }
220
221 if (tgsi_text_translate(text, tokens, Elements(tokens)) == FALSE) {
222 pp_debug("Failed to translate %s\n", name);
223 return NULL;
224 }
225
226 state.tokens = tokens;
227 memset(&state.stream_output, 0, sizeof(state.stream_output));
228
229 if (isvs) {
230 ret_state = pipe->create_vs_state(pipe, &state);
231 FREE(tokens);
232 } else {
233 ret_state = pipe->create_fs_state(pipe, &state);
234 FREE(tokens);
235 }
236
237 return ret_state;
238 }
239
240 /** Setup misc state for the filter. */
241 void
242 pp_filter_misc_state(struct program *p)
243 {
244 cso_set_blend(p->cso, &p->blend);
245 cso_set_depth_stencil_alpha(p->cso, &p->depthstencil);
246 cso_set_rasterizer(p->cso, &p->rasterizer);
247 cso_set_viewport(p->cso, &p->viewport);
248
249 cso_set_vertex_elements(p->cso, 2, p->velem);
250 }
251
252 /** Draw with the filter to the set output. */
253 void
254 pp_filter_draw(struct program *p)
255 {
256 util_draw_vertex_buffer(p->pipe, p->cso, p->vbuf, 0, 0,
257 PIPE_PRIM_QUADS, 4, 2);
258 }
259
260 /** Set the framebuffer as active. */
261 void
262 pp_filter_set_fb(struct program *p)
263 {
264 cso_set_framebuffer(p->cso, &p->framebuffer);
265 }
266
267 /** Set the framebuffer as active and clear it. */
268 void
269 pp_filter_set_clear_fb(struct program *p)
270 {
271 cso_set_framebuffer(p->cso, &p->framebuffer);
272 p->pipe->clear(p->pipe, PIPE_CLEAR_COLOR, &p->clear_color, 0, 0);
273 }