st/va: add support for P010 and P016 formats v3
[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 drv->pipe->flush(drv->pipe, NULL, 0);
84 return VA_STATUS_SUCCESS;
85 }
86
87 static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
88 struct pipe_box *box, const VARectangle *region)
89 {
90 unsigned plane = buf->interlaced ? idx / 2: idx;
91 unsigned x, y, width, height;
92
93 x = abs(region->x);
94 y = abs(region->y);
95 width = region->width;
96 height = region->height;
97
98 vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format,
99 buf->interlaced);
100 vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format,
101 buf->interlaced);
102
103 box->x = region->x < 0 ? -x : x;
104 box->y = region->y < 0 ? -y : y;
105 box->width = width;
106 box->height = height;
107 }
108
109 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
110 const VARectangle *src_region,
111 const VARectangle *dst_region,
112 struct pipe_video_buffer *src,
113 struct pipe_video_buffer *dst,
114 enum vl_compositor_deinterlace deinterlace)
115 {
116 struct pipe_surface **src_surfaces;
117 struct pipe_surface **dst_surfaces;
118 unsigned i;
119
120 if (src->interlaced != dst->interlaced)
121 return VA_STATUS_ERROR_INVALID_SURFACE;
122
123 src_surfaces = src->get_surfaces(src);
124 if (!src_surfaces || !src_surfaces[0])
125 return VA_STATUS_ERROR_INVALID_SURFACE;
126
127 dst_surfaces = dst->get_surfaces(dst);
128 if (!dst_surfaces || !dst_surfaces[0])
129 return VA_STATUS_ERROR_INVALID_SURFACE;
130
131 for (i = 0; i < VL_MAX_SURFACES; ++i) {
132 struct pipe_surface *from = src_surfaces[i];
133 struct pipe_blit_info blit;
134
135 if (src->interlaced) {
136 /* Not 100% accurate, but close enough */
137 switch (deinterlace) {
138 case VL_COMPOSITOR_BOB_TOP:
139 from = src_surfaces[i & ~1];
140 break;
141 case VL_COMPOSITOR_BOB_BOTTOM:
142 from = src_surfaces[(i & ~1) + 1];
143 break;
144 default:
145 break;
146 }
147 }
148
149 if (!from || !dst_surfaces[i])
150 continue;
151
152 memset(&blit, 0, sizeof(blit));
153 blit.src.resource = from->texture;
154 blit.src.format = from->format;
155 blit.src.level = 0;
156 blit.src.box.z = from->u.tex.first_layer;
157 blit.src.box.depth = 1;
158 vlVaGetBox(src, i, &blit.src.box, src_region);
159
160 blit.dst.resource = dst_surfaces[i]->texture;
161 blit.dst.format = dst_surfaces[i]->format;
162 blit.dst.level = 0;
163 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
164 blit.dst.box.depth = 1;
165 vlVaGetBox(dst, i, &blit.dst.box, dst_region);
166
167 blit.mask = PIPE_MASK_RGBA;
168 blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
169
170 drv->pipe->blit(drv->pipe, &blit);
171 }
172
173 // TODO: figure out why this is necessary for DMA-buf sharing
174 drv->pipe->flush(drv->pipe, NULL, 0);
175
176 return VA_STATUS_SUCCESS;
177 }
178
179 static struct pipe_video_buffer *
180 vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,
181 VAProcPipelineParameterBuffer *param,
182 struct pipe_video_buffer *current,
183 unsigned field)
184 {
185 vlVaSurface *prevprev, *prev, *next;
186
187 if (param->num_forward_references < 2 ||
188 param->num_backward_references < 1)
189 return current;
190
191 prevprev = handle_table_get(drv->htab, param->forward_references[1]);
192 prev = handle_table_get(drv->htab, param->forward_references[0]);
193 next = handle_table_get(drv->htab, param->backward_references[0]);
194
195 if (!prevprev || !prev || !next)
196 return current;
197
198 if (context->deint && (context->deint->video_width != current->width ||
199 context->deint->video_height != current->height)) {
200 vl_deint_filter_cleanup(context->deint);
201 FREE(context->deint);
202 context->deint = NULL;
203 }
204
205 if (!context->deint) {
206 context->deint = MALLOC(sizeof(struct vl_deint_filter));
207 if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,
208 current->height, false, false)) {
209 FREE(context->deint);
210 context->deint = NULL;
211 return current;
212 }
213 }
214
215 if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,
216 prev->buffer, current, next->buffer))
217 return current;
218
219 vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,
220 current, next->buffer, field);
221 return context->deint->video_buffer;
222 }
223
224 VAStatus
225 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
226 {
227 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE;
228 VARectangle def_src_region, def_dst_region;
229 const VARectangle *src_region, *dst_region;
230 VAProcPipelineParameterBuffer *param;
231 struct pipe_video_buffer *src;
232 vlVaSurface *src_surface;
233 unsigned i;
234
235 if (!drv || !context)
236 return VA_STATUS_ERROR_INVALID_CONTEXT;
237
238 if (!buf || !buf->data)
239 return VA_STATUS_ERROR_INVALID_BUFFER;
240
241 if (!context->target)
242 return VA_STATUS_ERROR_INVALID_SURFACE;
243
244 param = buf->data;
245
246 src_surface = handle_table_get(drv->htab, param->surface);
247 if (!src_surface || !src_surface->buffer)
248 return VA_STATUS_ERROR_INVALID_SURFACE;
249
250 src = src_surface->buffer;
251
252 for (i = 0; i < param->num_filters; i++) {
253 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
254 VAProcFilterParameterBufferBase *filter;
255
256 if (!buf || buf->type != VAProcFilterParameterBufferType)
257 return VA_STATUS_ERROR_INVALID_BUFFER;
258
259 filter = buf->data;
260 switch (filter->type) {
261 case VAProcFilterDeinterlacing: {
262 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
263 switch (deint->algorithm) {
264 case VAProcDeinterlacingBob:
265 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
266 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
267 else
268 deinterlace = VL_COMPOSITOR_BOB_TOP;
269 break;
270
271 case VAProcDeinterlacingWeave:
272 deinterlace = VL_COMPOSITOR_WEAVE;
273 break;
274
275 case VAProcDeinterlacingMotionAdaptive:
276 src = vlVaApplyDeint(drv, context, param, src,
277 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));
278 break;
279
280 default:
281 return VA_STATUS_ERROR_UNIMPLEMENTED;
282 }
283
284 break;
285 }
286
287 default:
288 return VA_STATUS_ERROR_UNIMPLEMENTED;
289 }
290 }
291
292 src_region = vlVaRegionDefault(param->surface_region, src_surface->buffer, &def_src_region);
293 dst_region = vlVaRegionDefault(param->output_region, context->target, &def_dst_region);
294
295 if (context->target->buffer_format != PIPE_FORMAT_NV12 &&
296 context->target->buffer_format != PIPE_FORMAT_P016)
297 return vlVaPostProcCompositor(drv, context, src_region, dst_region,
298 src, context->target, deinterlace);
299 else
300 return vlVaPostProcBlit(drv, context, src_region, dst_region,
301 src, context->target, deinterlace);
302 }