1 /**************************************************************************
3 * Copyright 2012 Christian König.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
26 **************************************************************************/
28 #include "pipe/p_context.h"
30 #include "tgsi/tgsi_ureg.h"
32 #include "util/u_draw.h"
33 #include "util/u_memory.h"
34 #include "util/u_math.h"
37 #include "vl_vertex_buffers.h"
38 #include "vl_median_filter.h"
47 create_vert_shader(struct vl_median_filter
*filter
)
49 struct ureg_program
*shader
;
50 struct ureg_src i_vpos
;
51 struct ureg_dst o_vpos
, o_vtex
;
53 shader
= ureg_create(TGSI_PROCESSOR_VERTEX
);
57 i_vpos
= ureg_DECL_vs_input(shader
, 0);
58 o_vpos
= ureg_DECL_output(shader
, TGSI_SEMANTIC_POSITION
, VS_O_VPOS
);
59 o_vtex
= ureg_DECL_output(shader
, TGSI_SEMANTIC_GENERIC
, VS_O_VTEX
);
61 ureg_MOV(shader
, o_vpos
, i_vpos
);
62 ureg_MOV(shader
, o_vtex
, i_vpos
);
66 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
70 is_vec_zero(struct vertex2f v
)
72 return v
.x
== 0.0f
&& v
.y
== 0.0f
;
76 create_frag_shader(struct vl_median_filter
*filter
,
77 struct vertex2f
*offsets
,
80 struct pipe_screen
*screen
= filter
->pipe
->screen
;
81 struct ureg_program
*shader
;
82 struct ureg_src i_vtex
;
83 struct ureg_src sampler
;
84 struct ureg_dst
*t_array
= MALLOC(sizeof(struct ureg_dst
) * num_offsets
);
85 const unsigned median
= num_offsets
>> 1;
88 assert(num_offsets
& 1); /* we need an odd number of offsets */
89 if (!(num_offsets
& 1)) { /* yeah, we REALLY need an odd number of offsets!!! */
94 if (num_offsets
> screen
->get_shader_param(
95 screen
, TGSI_PROCESSOR_FRAGMENT
, PIPE_SHADER_CAP_MAX_TEMPS
)) {
101 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
107 i_vtex
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, VS_O_VTEX
, TGSI_INTERPOLATE_LINEAR
);
108 sampler
= ureg_DECL_sampler(shader
, 0);
110 for (i
= 0; i
< num_offsets
; ++i
) {
112 t_array
[i
] = ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
114 t_array
[i
] = ureg_DECL_temporary(shader
);
118 * t_array[0..*] = vtex + offset[0..*]
119 * t_array[0..*] = tex(t_array[0..*], sampler)
120 * result = partial_bubblesort(t_array)[mid]
123 for (i
= 0; i
< num_offsets
; ++i
) {
124 if (!is_vec_zero(offsets
[i
])) {
125 ureg_ADD(shader
, ureg_writemask(t_array
[i
], TGSI_WRITEMASK_XY
),
126 i_vtex
, ureg_imm2f(shader
, offsets
[i
].x
, offsets
[i
].y
));
127 ureg_MOV(shader
, ureg_writemask(t_array
[i
], TGSI_WRITEMASK_ZW
),
128 ureg_imm1f(shader
, 0.0f
));
132 for (i
= 0; i
< num_offsets
; ++i
) {
133 struct ureg_src src
= is_vec_zero(offsets
[i
]) ? i_vtex
: ureg_src(t_array
[i
]);
134 ureg_TEX(shader
, t_array
[i
], TGSI_TEXTURE_2D
, src
, sampler
);
137 // TODO: Couldn't this be improved even more?
138 for (i
= 0; i
<= median
; ++i
) {
139 for (j
= 1; j
< (num_offsets
- i
- 1); ++j
) {
140 struct ureg_dst tmp
= ureg_DECL_temporary(shader
);
141 ureg_MOV(shader
, tmp
, ureg_src(t_array
[j
]));
142 ureg_MAX(shader
, t_array
[j
], ureg_src(t_array
[j
]), ureg_src(t_array
[j
- 1]));
143 ureg_MIN(shader
, t_array
[j
- 1], ureg_src(tmp
), ureg_src(t_array
[j
- 1]));
144 ureg_release_temporary(shader
, tmp
);
147 ureg_MAX(shader
, t_array
[j
], ureg_src(t_array
[j
]), ureg_src(t_array
[j
- 1]));
149 ureg_MIN(shader
, t_array
[j
- 1], ureg_src(t_array
[j
]), ureg_src(t_array
[j
- 1]));
155 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
159 generate_offsets(enum vl_median_filter_shape shape
, unsigned size
,
160 struct vertex2f
**offsets
, unsigned *num_offsets
)
162 int i
= 0, half_size
;
165 assert(offsets
&& num_offsets
);
167 /* size needs to be odd */
168 size
= align(size
+ 1, 2) - 1;
169 half_size
= size
>> 1;
172 case VL_MEDIAN_FILTER_BOX
:
173 *num_offsets
= size
*size
;
176 case VL_MEDIAN_FILTER_CROSS
:
177 case VL_MEDIAN_FILTER_X
:
178 *num_offsets
= size
+ size
- 1;
181 case VL_MEDIAN_FILTER_HORIZONTAL
:
182 case VL_MEDIAN_FILTER_VERTICAL
:
191 *offsets
= MALLOC(sizeof(struct vertex2f
) * *num_offsets
);
196 case VL_MEDIAN_FILTER_BOX
:
197 for (v
.x
= -half_size
; v
.x
<= half_size
; ++v
.x
)
198 for (v
.y
= -half_size
; v
.y
<= half_size
; ++v
.y
)
202 case VL_MEDIAN_FILTER_CROSS
:
204 for (v
.x
= -half_size
; v
.x
<= half_size
; ++v
.x
)
208 for (v
.y
= -half_size
; v
.y
<= half_size
; ++v
.y
)
213 case VL_MEDIAN_FILTER_X
:
214 for (v
.x
= v
.y
= -half_size
; v
.x
<= half_size
; ++v
.x
, ++v
.y
)
217 for (v
.x
= -half_size
, v
.y
= half_size
; v
.x
<= half_size
; ++v
.x
, --v
.y
)
222 case VL_MEDIAN_FILTER_HORIZONTAL
:
224 for (v
.x
= -half_size
; v
.x
<= half_size
; ++v
.x
)
228 case VL_MEDIAN_FILTER_VERTICAL
:
230 for (v
.y
= -half_size
; v
.y
<= half_size
; ++v
.y
)
235 assert(i
== *num_offsets
);
239 vl_median_filter_init(struct vl_median_filter
*filter
, struct pipe_context
*pipe
,
240 unsigned width
, unsigned height
, unsigned size
,
241 enum vl_median_filter_shape shape
)
243 struct pipe_rasterizer_state rs_state
;
244 struct pipe_blend_state blend
;
245 struct pipe_sampler_state sampler
;
246 struct vertex2f
*offsets
= NULL
;
247 struct pipe_vertex_element ve
;
248 unsigned i
, num_offsets
= 0;
250 assert(filter
&& pipe
);
251 assert(width
&& height
);
252 assert(size
> 1 && size
< 20);
254 memset(filter
, 0, sizeof(*filter
));
257 memset(&rs_state
, 0, sizeof(rs_state
));
258 rs_state
.gl_rasterization_rules
= true;
259 rs_state
.depth_clip
= 1;
260 filter
->rs_state
= pipe
->create_rasterizer_state(pipe
, &rs_state
);
261 if (!filter
->rs_state
)
264 memset(&blend
, 0, sizeof blend
);
265 blend
.rt
[0].rgb_func
= PIPE_BLEND_ADD
;
266 blend
.rt
[0].rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
267 blend
.rt
[0].rgb_dst_factor
= PIPE_BLENDFACTOR_ONE
;
268 blend
.rt
[0].alpha_func
= PIPE_BLEND_ADD
;
269 blend
.rt
[0].alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
270 blend
.rt
[0].alpha_dst_factor
= PIPE_BLENDFACTOR_ONE
;
271 blend
.logicop_func
= PIPE_LOGICOP_CLEAR
;
272 blend
.rt
[0].colormask
= PIPE_MASK_RGBA
;
273 filter
->blend
= pipe
->create_blend_state(pipe
, &blend
);
277 memset(&sampler
, 0, sizeof(sampler
));
278 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
279 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
280 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
281 sampler
.min_img_filter
= PIPE_TEX_FILTER_NEAREST
;
282 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
283 sampler
.mag_img_filter
= PIPE_TEX_FILTER_NEAREST
;
284 sampler
.compare_mode
= PIPE_TEX_COMPARE_NONE
;
285 sampler
.compare_func
= PIPE_FUNC_ALWAYS
;
286 sampler
.normalized_coords
= 1;
287 filter
->sampler
= pipe
->create_sampler_state(pipe
, &sampler
);
288 if (!filter
->sampler
)
291 filter
->quad
= vl_vb_upload_quads(pipe
);
292 if(!filter
->quad
.buffer
)
295 memset(&ve
, 0, sizeof(ve
));
297 ve
.instance_divisor
= 0;
298 ve
.vertex_buffer_index
= 0;
299 ve
.src_format
= PIPE_FORMAT_R32G32_FLOAT
;
300 filter
->ves
= pipe
->create_vertex_elements_state(pipe
, 1, &ve
);
304 generate_offsets(shape
, size
, &offsets
, &num_offsets
);
308 for (i
= 0; i
< num_offsets
; ++i
) {
309 offsets
[i
].x
/= width
;
310 offsets
[i
].y
/= height
;
313 filter
->vs
= create_vert_shader(filter
);
317 filter
->fs
= create_frag_shader(filter
, offsets
, num_offsets
);
325 pipe
->delete_vs_state(pipe
, filter
->vs
);
331 pipe
->delete_vertex_elements_state(pipe
, filter
->ves
);
334 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
337 pipe
->delete_sampler_state(pipe
, filter
->sampler
);
340 pipe
->delete_blend_state(pipe
, filter
->blend
);
343 pipe
->delete_rasterizer_state(pipe
, filter
->rs_state
);
350 vl_median_filter_cleanup(struct vl_median_filter
*filter
)
354 filter
->pipe
->delete_sampler_state(filter
->pipe
, filter
->sampler
);
355 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
);
356 filter
->pipe
->delete_rasterizer_state(filter
->pipe
, filter
->rs_state
);
357 filter
->pipe
->delete_vertex_elements_state(filter
->pipe
, filter
->ves
);
358 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
360 filter
->pipe
->delete_vs_state(filter
->pipe
, filter
->vs
);
361 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs
);
365 vl_median_filter_render(struct vl_median_filter
*filter
,
366 struct pipe_sampler_view
*src
,
367 struct pipe_surface
*dst
)
369 struct pipe_viewport_state viewport
;
370 struct pipe_framebuffer_state fb_state
;
372 assert(filter
&& src
&& dst
);
374 memset(&viewport
, 0, sizeof(viewport
));
375 viewport
.scale
[0] = dst
->width
;
376 viewport
.scale
[1] = dst
->height
;
377 viewport
.scale
[2] = 1;
378 viewport
.scale
[3] = 1;
380 memset(&fb_state
, 0, sizeof(fb_state
));
381 fb_state
.width
= dst
->width
;
382 fb_state
.height
= dst
->height
;
383 fb_state
.nr_cbufs
= 1;
384 fb_state
.cbufs
[0] = dst
;
386 filter
->pipe
->bind_rasterizer_state(filter
->pipe
, filter
->rs_state
);
387 filter
->pipe
->bind_blend_state(filter
->pipe
, filter
->blend
);
388 filter
->pipe
->bind_fragment_sampler_states(filter
->pipe
, 1, &filter
->sampler
);
389 filter
->pipe
->set_fragment_sampler_views(filter
->pipe
, 1, &src
);
390 filter
->pipe
->bind_vs_state(filter
->pipe
, filter
->vs
);
391 filter
->pipe
->bind_fs_state(filter
->pipe
, filter
->fs
);
392 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
393 filter
->pipe
->set_viewport_state(filter
->pipe
, &viewport
);
394 filter
->pipe
->set_vertex_buffers(filter
->pipe
, 1, &filter
->quad
);
395 filter
->pipe
->bind_vertex_elements_state(filter
->pipe
, filter
->ves
);
397 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);