Merge remote-tracking branch 'mattst88/nir-lower-pack-unpack' into vulkan
[mesa.git] / src / gallium / state_trackers / va / postproc.c
1 /**************************************************************************
2 *
3 * Copyright 2015 Advanced Micro Devices, Inc.
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "util/u_handle_table.h"
29
30 #include "vl/vl_defines.h"
31 #include "vl/vl_video_buffer.h"
32 #include "vl/vl_deint_filter.h"
33
34 #include "va_private.h"
35
36 static const VARectangle *
37 vlVaRegionDefault(const VARectangle *region, struct pipe_video_buffer *buf,
38 VARectangle *def)
39 {
40 if (region)
41 return region;
42
43 def->x = 0;
44 def->y = 0;
45 def->width = buf->width;
46 def->height = buf->height;
47
48 return def;
49 }
50
51 static VAStatus
52 vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context,
53 const VARectangle *src_region,
54 const VARectangle *dst_region,
55 struct pipe_video_buffer *src,
56 struct pipe_video_buffer *dst,
57 enum vl_compositor_deinterlace deinterlace)
58 {
59 struct pipe_surface **surfaces;
60 struct u_rect src_rect;
61 struct u_rect dst_rect;
62
63 surfaces = dst->get_surfaces(dst);
64 if (!surfaces || !surfaces[0])
65 return VA_STATUS_ERROR_INVALID_SURFACE;
66
67 src_rect.x0 = src_region->x;
68 src_rect.y0 = src_region->y;
69 src_rect.x1 = src_region->x + src_region->width;
70 src_rect.y1 = src_region->y + src_region->height;
71
72 dst_rect.x0 = dst_region->x;
73 dst_rect.y0 = dst_region->y;
74 dst_rect.x1 = dst_region->x + dst_region->width;
75 dst_rect.y1 = dst_region->y + dst_region->height;
76
77 vl_compositor_clear_layers(&drv->cstate);
78 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src,
79 &src_rect, NULL, deinterlace);
80 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
81 vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false);
82
83 return VA_STATUS_SUCCESS;
84 }
85
86 static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
87 struct pipe_box *box, const VARectangle *region)
88 {
89 unsigned plane = buf->interlaced ? idx / 2: idx;
90 unsigned x, y, width, height;
91
92 x = abs(region->x);
93 y = abs(region->y);
94 width = region->width;
95 height = region->height;
96
97 vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format,
98 buf->interlaced);
99 vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format,
100 buf->interlaced);
101
102 box->x = region->x < 0 ? -x : x;
103 box->y = region->y < 0 ? -y : y;
104 box->width = width;
105 box->height = height;
106 }
107
108 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
109 const VARectangle *src_region,
110 const VARectangle *dst_region,
111 struct pipe_video_buffer *src,
112 struct pipe_video_buffer *dst,
113 enum vl_compositor_deinterlace deinterlace)
114 {
115 struct pipe_surface **src_surfaces;
116 struct pipe_surface **dst_surfaces;
117 unsigned i;
118
119 if (src->interlaced != dst->interlaced)
120 return VA_STATUS_ERROR_INVALID_SURFACE;
121
122 src_surfaces = src->get_surfaces(src);
123 if (!src_surfaces || !src_surfaces[0])
124 return VA_STATUS_ERROR_INVALID_SURFACE;
125
126 dst_surfaces = dst->get_surfaces(dst);
127 if (!dst_surfaces || !dst_surfaces[0])
128 return VA_STATUS_ERROR_INVALID_SURFACE;
129
130 for (i = 0; i < VL_MAX_SURFACES; ++i) {
131 struct pipe_surface *from = src_surfaces[i];
132 struct pipe_blit_info blit;
133
134 if (src->interlaced) {
135 /* Not 100% accurate, but close enough */
136 switch (deinterlace) {
137 case VL_COMPOSITOR_BOB_TOP:
138 from = src_surfaces[i & ~1];
139 break;
140 case VL_COMPOSITOR_BOB_BOTTOM:
141 from = src_surfaces[(i & ~1) + 1];
142 break;
143 default:
144 break;
145 }
146 }
147
148 if (!from || !dst_surfaces[i])
149 continue;
150
151 memset(&blit, 0, sizeof(blit));
152 blit.src.resource = from->texture;
153 blit.src.format = from->format;
154 blit.src.level = 0;
155 blit.src.box.z = from->u.tex.first_layer;
156 blit.src.box.depth = 1;
157 vlVaGetBox(src, i, &blit.src.box, src_region);
158
159 blit.dst.resource = dst_surfaces[i]->texture;
160 blit.dst.format = dst_surfaces[i]->format;
161 blit.dst.level = 0;
162 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
163 blit.dst.box.depth = 1;
164 vlVaGetBox(dst, i, &blit.dst.box, dst_region);
165
166 blit.mask = PIPE_MASK_RGBA;
167 blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
168
169 drv->pipe->blit(drv->pipe, &blit);
170 }
171
172 // TODO: figure out why this is necessary for DMA-buf sharing
173 drv->pipe->flush(drv->pipe, NULL, 0);
174
175 return VA_STATUS_SUCCESS;
176 }
177
178 static struct pipe_video_buffer *
179 vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,
180 VAProcPipelineParameterBuffer *param,
181 struct pipe_video_buffer *current,
182 unsigned field)
183 {
184 vlVaSurface *prevprev, *prev, *next;
185
186 if (param->num_forward_references < 1 ||
187 param->num_backward_references < 2)
188 return current;
189
190 prevprev = handle_table_get(drv->htab, param->backward_references[1]);
191 prev = handle_table_get(drv->htab, param->backward_references[0]);
192 next = handle_table_get(drv->htab, param->forward_references[0]);
193
194 if (!prevprev || !prev || !next)
195 return current;
196
197 if (context->deint && (context->deint->video_width != current->width ||
198 context->deint->video_height != current->height)) {
199 vl_deint_filter_cleanup(context->deint);
200 FREE(context->deint);
201 context->deint = NULL;
202 }
203
204 if (!context->deint) {
205 context->deint = MALLOC(sizeof(struct vl_deint_filter));
206 if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,
207 current->height, false, false)) {
208 FREE(context->deint);
209 context->deint = NULL;
210 return current;
211 }
212 }
213
214 if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,
215 prev->buffer, current, next->buffer))
216 return current;
217
218 vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,
219 current, next->buffer, field);
220 return context->deint->video_buffer;
221 }
222
223 VAStatus
224 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
225 {
226 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE;
227 VARectangle def_src_region, def_dst_region;
228 const VARectangle *src_region, *dst_region;
229 VAProcPipelineParameterBuffer *param;
230 struct pipe_video_buffer *src;
231 vlVaSurface *src_surface;
232 unsigned i;
233
234 if (!drv || !context)
235 return VA_STATUS_ERROR_INVALID_CONTEXT;
236
237 if (!buf || !buf->data)
238 return VA_STATUS_ERROR_INVALID_BUFFER;
239
240 if (!context->target)
241 return VA_STATUS_ERROR_INVALID_SURFACE;
242
243 param = buf->data;
244
245 src_surface = handle_table_get(drv->htab, param->surface);
246 if (!src_surface || !src_surface->buffer)
247 return VA_STATUS_ERROR_INVALID_SURFACE;
248
249 src = src_surface->buffer;
250
251 for (i = 0; i < param->num_filters; i++) {
252 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
253 VAProcFilterParameterBufferBase *filter;
254
255 if (!buf || buf->type != VAProcFilterParameterBufferType)
256 return VA_STATUS_ERROR_INVALID_BUFFER;
257
258 filter = buf->data;
259 switch (filter->type) {
260 case VAProcFilterDeinterlacing: {
261 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
262 switch (deint->algorithm) {
263 case VAProcDeinterlacingBob:
264 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
265 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
266 else
267 deinterlace = VL_COMPOSITOR_BOB_TOP;
268 break;
269
270 case VAProcDeinterlacingWeave:
271 deinterlace = VL_COMPOSITOR_WEAVE;
272 break;
273
274 case VAProcDeinterlacingMotionAdaptive:
275 src = vlVaApplyDeint(drv, context, param, src,
276 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));
277 break;
278
279 default:
280 return VA_STATUS_ERROR_UNIMPLEMENTED;
281 }
282
283 break;
284 }
285
286 default:
287 return VA_STATUS_ERROR_UNIMPLEMENTED;
288 }
289 }
290
291 src_region = vlVaRegionDefault(param->surface_region, src_surface->buffer, &def_src_region);
292 dst_region = vlVaRegionDefault(param->output_region, context->target, &def_dst_region);
293
294 if (context->target->buffer_format != PIPE_FORMAT_NV12)
295 return vlVaPostProcCompositor(drv, context, src_region, dst_region,
296 src, context->target, deinterlace);
297 else
298 return vlVaPostProcBlit(drv, context, src_region, dst_region,
299 src, context->target, deinterlace);
300 }