1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2011 Lauri Kasanen
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg#include "postprocess.h"
29848b8605Smrg#include "postprocess/pp_filters.h"
30848b8605Smrg#include "postprocess/pp_private.h"
31848b8605Smrg
32848b8605Smrg#include "util/u_inlines.h"
33848b8605Smrg#include "util/u_sampler.h"
34848b8605Smrg
35848b8605Smrg#include "tgsi/tgsi_parse.h"
36848b8605Smrg
37848b8605Smrg
38848b8605Smrgvoid
39848b8605Smrgpp_blit(struct pipe_context *pipe,
40848b8605Smrg        struct pipe_resource *src_tex,
41848b8605Smrg        int srcX0, int srcY0,
42848b8605Smrg        int srcX1, int srcY1,
43848b8605Smrg        int srcZ0,
44848b8605Smrg        struct pipe_surface *dst,
45848b8605Smrg        int dstX0, int dstY0,
46848b8605Smrg        int dstX1, int dstY1)
47848b8605Smrg{
48848b8605Smrg   struct pipe_blit_info blit;
49848b8605Smrg
50848b8605Smrg   memset(&blit, 0, sizeof(blit));
51848b8605Smrg
52848b8605Smrg   blit.src.resource = src_tex;
53848b8605Smrg   blit.src.level = 0;
54848b8605Smrg   blit.src.format = src_tex->format;
55848b8605Smrg   blit.src.box.x = srcX0;
56848b8605Smrg   blit.src.box.y = srcY0;
57848b8605Smrg   blit.src.box.z = srcZ0;
58848b8605Smrg   blit.src.box.width = srcX1 - srcX0;
59848b8605Smrg   blit.src.box.height = srcY1 - srcY0;
60848b8605Smrg   blit.src.box.depth = 1;
61848b8605Smrg
62848b8605Smrg   blit.dst.resource = dst->texture;
63848b8605Smrg   blit.dst.level = dst->u.tex.level;
64848b8605Smrg   blit.dst.format = dst->format;
65848b8605Smrg   blit.dst.box.x = dstX0;
66848b8605Smrg   blit.dst.box.y = dstY0;
67848b8605Smrg   blit.dst.box.z = 0;
68848b8605Smrg   blit.dst.box.width = dstX1 - dstX0;
69848b8605Smrg   blit.dst.box.height = dstY1 - dstY0;
70848b8605Smrg   blit.dst.box.depth = 1;
71848b8605Smrg
72848b8605Smrg   blit.mask = PIPE_MASK_RGBA;
73848b8605Smrg
74848b8605Smrg   pipe->blit(pipe, &blit);
75848b8605Smrg}
76848b8605Smrg
77848b8605Smrg/**
78848b8605Smrg*	Main run function of the PP queue. Called on swapbuffers/flush.
79848b8605Smrg*
80848b8605Smrg*	Runs all requested filters in order and handles shuffling the temp
81848b8605Smrg*	buffers in between.
82848b8605Smrg*/
83848b8605Smrgvoid
84848b8605Smrgpp_run(struct pp_queue_t *ppq, struct pipe_resource *in,
85848b8605Smrg       struct pipe_resource *out, struct pipe_resource *indepth)
86848b8605Smrg{
87848b8605Smrg   struct pipe_resource *refin = NULL, *refout = NULL;
88848b8605Smrg   unsigned int i;
89848b8605Smrg   struct cso_context *cso = ppq->p->cso;
90848b8605Smrg
91848b8605Smrg   if (ppq->n_filters == 0)
92848b8605Smrg      return;
93848b8605Smrg
94848b8605Smrg   assert(ppq->pp_queue);
95848b8605Smrg   assert(ppq->tmp[0]);
96848b8605Smrg
97848b8605Smrg   if (in->width0 != ppq->p->framebuffer.width ||
98848b8605Smrg       in->height0 != ppq->p->framebuffer.height) {
99848b8605Smrg      pp_debug("Resizing the temp pp buffers\n");
100848b8605Smrg      pp_free_fbos(ppq);
101848b8605Smrg      pp_init_fbos(ppq, in->width0, in->height0);
102848b8605Smrg   }
103848b8605Smrg
104848b8605Smrg   if (in == out && ppq->n_filters == 1) {
105848b8605Smrg      /* Make a copy of in to tmp[0] in this case. */
106848b8605Smrg      unsigned int w = ppq->p->framebuffer.width;
107848b8605Smrg      unsigned int h = ppq->p->framebuffer.height;
108848b8605Smrg
109848b8605Smrg
110848b8605Smrg      pp_blit(ppq->p->pipe, in, 0, 0,
111848b8605Smrg              w, h, 0, ppq->tmps[0],
112848b8605Smrg              0, 0, w, h);
113848b8605Smrg
114848b8605Smrg      in = ppq->tmp[0];
115848b8605Smrg   }
116848b8605Smrg
117848b8605Smrg   /* save state (restored below) */
118b8e80941Smrg   cso_save_state(cso, (CSO_BIT_BLEND |
119b8e80941Smrg                        CSO_BIT_DEPTH_STENCIL_ALPHA |
120b8e80941Smrg                        CSO_BIT_FRAGMENT_SHADER |
121b8e80941Smrg                        CSO_BIT_FRAMEBUFFER |
122b8e80941Smrg                        CSO_BIT_TESSCTRL_SHADER |
123b8e80941Smrg                        CSO_BIT_TESSEVAL_SHADER |
124b8e80941Smrg                        CSO_BIT_GEOMETRY_SHADER |
125b8e80941Smrg                        CSO_BIT_RASTERIZER |
126b8e80941Smrg                        CSO_BIT_SAMPLE_MASK |
127b8e80941Smrg                        CSO_BIT_MIN_SAMPLES |
128b8e80941Smrg                        CSO_BIT_FRAGMENT_SAMPLERS |
129b8e80941Smrg                        CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
130b8e80941Smrg                        CSO_BIT_STENCIL_REF |
131b8e80941Smrg                        CSO_BIT_STREAM_OUTPUTS |
132b8e80941Smrg                        CSO_BIT_VERTEX_ELEMENTS |
133b8e80941Smrg                        CSO_BIT_VERTEX_SHADER |
134b8e80941Smrg                        CSO_BIT_VIEWPORT |
135b8e80941Smrg                        CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
136b8e80941Smrg                        CSO_BIT_PAUSE_QUERIES |
137b8e80941Smrg                        CSO_BIT_RENDER_CONDITION));
138848b8605Smrg   cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
139848b8605Smrg   cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
140848b8605Smrg
141848b8605Smrg   /* set default state */
142848b8605Smrg   cso_set_sample_mask(cso, ~0);
143848b8605Smrg   cso_set_min_samples(cso, 1);
144848b8605Smrg   cso_set_stream_outputs(cso, 0, NULL, NULL);
145b8e80941Smrg   cso_set_tessctrl_shader_handle(cso, NULL);
146b8e80941Smrg   cso_set_tesseval_shader_handle(cso, NULL);
147848b8605Smrg   cso_set_geometry_shader_handle(cso, NULL);
148848b8605Smrg   cso_set_render_condition(cso, NULL, FALSE, 0);
149848b8605Smrg
150848b8605Smrg   // Kept only for this frame.
151848b8605Smrg   pipe_resource_reference(&ppq->depth, indepth);
152848b8605Smrg   pipe_resource_reference(&refin, in);
153848b8605Smrg   pipe_resource_reference(&refout, out);
154848b8605Smrg
155848b8605Smrg   switch (ppq->n_filters) {
156848b8605Smrg   case 0:
157848b8605Smrg      /* Failsafe, but never reached. */
158848b8605Smrg      break;
159848b8605Smrg   case 1:                     /* No temp buf */
160848b8605Smrg      ppq->pp_queue[0] (ppq, in, out, 0);
161848b8605Smrg      break;
162848b8605Smrg   case 2:                     /* One temp buf */
163848b8605Smrg
164848b8605Smrg      ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0);
165848b8605Smrg      ppq->pp_queue[1] (ppq, ppq->tmp[0], out, 1);
166848b8605Smrg
167848b8605Smrg      break;
168848b8605Smrg   default:                    /* Two temp bufs */
169848b8605Smrg      assert(ppq->tmp[1]);
170848b8605Smrg      ppq->pp_queue[0] (ppq, in, ppq->tmp[0], 0);
171848b8605Smrg
172848b8605Smrg      for (i = 1; i < (ppq->n_filters - 1); i++) {
173848b8605Smrg         if (i % 2 == 0)
174848b8605Smrg            ppq->pp_queue[i] (ppq, ppq->tmp[1], ppq->tmp[0], i);
175848b8605Smrg
176848b8605Smrg         else
177848b8605Smrg            ppq->pp_queue[i] (ppq, ppq->tmp[0], ppq->tmp[1], i);
178848b8605Smrg      }
179848b8605Smrg
180848b8605Smrg      if (i % 2 == 0)
181848b8605Smrg         ppq->pp_queue[i] (ppq, ppq->tmp[1], out, i);
182848b8605Smrg
183848b8605Smrg      else
184848b8605Smrg         ppq->pp_queue[i] (ppq, ppq->tmp[0], out, i);
185848b8605Smrg
186848b8605Smrg      break;
187848b8605Smrg   }
188848b8605Smrg
189848b8605Smrg   /* restore state we changed */
190b8e80941Smrg   cso_restore_state(cso);
191848b8605Smrg   cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX);
192848b8605Smrg   cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
193848b8605Smrg
194848b8605Smrg   pipe_resource_reference(&ppq->depth, NULL);
195848b8605Smrg   pipe_resource_reference(&refin, NULL);
196848b8605Smrg   pipe_resource_reference(&refout, NULL);
197848b8605Smrg}
198848b8605Smrg
199848b8605Smrg
200848b8605Smrg/* Utility functions for the filters. You're not forced to use these if */
201848b8605Smrg/* your filter is more complicated. */
202848b8605Smrg
203848b8605Smrg/** Setup this resource as the filter input. */
204848b8605Smrgvoid
205848b8605Smrgpp_filter_setup_in(struct pp_program *p, struct pipe_resource *in)
206848b8605Smrg{
207848b8605Smrg   struct pipe_sampler_view v_tmp;
208848b8605Smrg   u_sampler_view_default_template(&v_tmp, in, in->format);
209848b8605Smrg   p->view = p->pipe->create_sampler_view(p->pipe, in, &v_tmp);
210848b8605Smrg}
211848b8605Smrg
212848b8605Smrg/** Setup this resource as the filter output. */
213848b8605Smrgvoid
214848b8605Smrgpp_filter_setup_out(struct pp_program *p, struct pipe_resource *out)
215848b8605Smrg{
216848b8605Smrg   p->surf.format = out->format;
217848b8605Smrg
218848b8605Smrg   p->framebuffer.cbufs[0] = p->pipe->create_surface(p->pipe, out, &p->surf);
219848b8605Smrg}
220848b8605Smrg
221848b8605Smrg/** Clean up the input and output set with the above. */
222848b8605Smrgvoid
223848b8605Smrgpp_filter_end_pass(struct pp_program *p)
224848b8605Smrg{
225848b8605Smrg   pipe_surface_reference(&p->framebuffer.cbufs[0], NULL);
226848b8605Smrg   pipe_sampler_view_reference(&p->view, NULL);
227848b8605Smrg}
228848b8605Smrg
229848b8605Smrg/**
230848b8605Smrg*	Convert the TGSI assembly to a runnable shader.
231848b8605Smrg*
232848b8605Smrg* We need not care about geometry shaders. All we have is screen quads.
233848b8605Smrg*/
234848b8605Smrgvoid *
235848b8605Smrgpp_tgsi_to_state(struct pipe_context *pipe, const char *text, bool isvs,
236848b8605Smrg                 const char *name)
237848b8605Smrg{
238848b8605Smrg   struct pipe_shader_state state;
239848b8605Smrg   struct tgsi_token *tokens = NULL;
240848b8605Smrg   void *ret_state = NULL;
241848b8605Smrg
242848b8605Smrg   /*
243848b8605Smrg    * Allocate temporary token storage. State creation will duplicate
244848b8605Smrg    * tokens so we must free them on exit.
245848b8605Smrg    */
246848b8605Smrg   tokens = tgsi_alloc_tokens(PP_MAX_TOKENS);
247848b8605Smrg
248b8e80941Smrg   if (!tokens) {
249848b8605Smrg      pp_debug("Failed to allocate temporary token storage.\n");
250848b8605Smrg      return NULL;
251848b8605Smrg   }
252848b8605Smrg
253848b8605Smrg   if (tgsi_text_translate(text, tokens, PP_MAX_TOKENS) == FALSE) {
254848b8605Smrg      _debug_printf("pp: Failed to translate a shader for %s\n", name);
255848b8605Smrg      return NULL;
256848b8605Smrg   }
257848b8605Smrg
258b8e80941Smrg   pipe_shader_state_from_tgsi(&state, tokens);
259848b8605Smrg
260848b8605Smrg   if (isvs) {
261848b8605Smrg      ret_state = pipe->create_vs_state(pipe, &state);
262848b8605Smrg      FREE(tokens);
263848b8605Smrg   } else {
264848b8605Smrg      ret_state = pipe->create_fs_state(pipe, &state);
265848b8605Smrg      FREE(tokens);
266848b8605Smrg   }
267848b8605Smrg
268848b8605Smrg   return ret_state;
269848b8605Smrg}
270848b8605Smrg
271848b8605Smrg/** Setup misc state for the filter. */
272848b8605Smrgvoid
273848b8605Smrgpp_filter_misc_state(struct pp_program *p)
274848b8605Smrg{
275848b8605Smrg   cso_set_blend(p->cso, &p->blend);
276848b8605Smrg   cso_set_depth_stencil_alpha(p->cso, &p->depthstencil);
277848b8605Smrg   cso_set_rasterizer(p->cso, &p->rasterizer);
278848b8605Smrg   cso_set_viewport(p->cso, &p->viewport);
279848b8605Smrg
280848b8605Smrg   cso_set_vertex_elements(p->cso, 2, p->velem);
281848b8605Smrg}
282848b8605Smrg
283848b8605Smrg/** Draw with the filter to the set output. */
284848b8605Smrgvoid
285848b8605Smrgpp_filter_draw(struct pp_program *p)
286848b8605Smrg{
287848b8605Smrg   util_draw_vertex_buffer(p->pipe, p->cso, p->vbuf, 0, 0,
288848b8605Smrg                           PIPE_PRIM_QUADS, 4, 2);
289848b8605Smrg}
290848b8605Smrg
291848b8605Smrg/** Set the framebuffer as active. */
292848b8605Smrgvoid
293848b8605Smrgpp_filter_set_fb(struct pp_program *p)
294848b8605Smrg{
295848b8605Smrg   cso_set_framebuffer(p->cso, &p->framebuffer);
296848b8605Smrg}
297848b8605Smrg
298848b8605Smrg/** Set the framebuffer as active and clear it. */
299848b8605Smrgvoid
300848b8605Smrgpp_filter_set_clear_fb(struct pp_program *p)
301848b8605Smrg{
302848b8605Smrg   cso_set_framebuffer(p->cso, &p->framebuffer);
303848b8605Smrg   p->pipe->clear(p->pipe, PIPE_CLEAR_COLOR0, &p->clear_color, 0, 0);
304848b8605Smrg}
305