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