st/va: add BOB deinterlacing v2
[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
33 #include "va_private.h"
34
35 static const VARectangle *
36 vlVaRegionDefault(const VARectangle *region, struct pipe_video_buffer *buf,
37 VARectangle *def)
38 {
39 if (region)
40 return region;
41
42 def->x = 0;
43 def->y = 0;
44 def->width = buf->width;
45 def->height = buf->height;
46
47 return def;
48 }
49
50 static VAStatus
51 vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context,
52 const VARectangle *src_region,
53 const VARectangle *dst_region,
54 struct pipe_video_buffer *src,
55 struct pipe_video_buffer *dst,
56 enum vl_compositor_deinterlace deinterlace)
57 {
58 struct pipe_surface **surfaces;
59 struct u_rect src_rect;
60 struct u_rect dst_rect;
61
62 surfaces = dst->get_surfaces(dst);
63 if (!surfaces || !surfaces[0])
64 return VA_STATUS_ERROR_INVALID_SURFACE;
65
66 src_rect.x0 = src_region->x;
67 src_rect.y0 = src_region->y;
68 src_rect.x1 = src_region->x + src_region->width;
69 src_rect.y1 = src_region->y + src_region->height;
70
71 dst_rect.x0 = dst_region->x;
72 dst_rect.y0 = dst_region->y;
73 dst_rect.x1 = dst_region->x + dst_region->width;
74 dst_rect.y1 = dst_region->y + dst_region->height;
75
76 vl_compositor_clear_layers(&drv->cstate);
77 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src,
78 &src_rect, NULL, deinterlace);
79 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
80 vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false);
81
82 return VA_STATUS_SUCCESS;
83 }
84
85 static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
86 struct pipe_box *box, const VARectangle *region)
87 {
88 unsigned plane = buf->interlaced ? idx / 2: idx;
89 unsigned x, y, width, height;
90
91 x = abs(region->x);
92 y = abs(region->y);
93 width = region->width;
94 height = region->height;
95
96 vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format,
97 buf->interlaced);
98 vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format,
99 buf->interlaced);
100
101 box->x = region->x < 0 ? -x : x;
102 box->y = region->y < 0 ? -y : y;
103 box->width = width;
104 box->height = height;
105 }
106
107 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
108 const VARectangle *src_region,
109 const VARectangle *dst_region,
110 struct pipe_video_buffer *src,
111 struct pipe_video_buffer *dst,
112 enum vl_compositor_deinterlace deinterlace)
113 {
114 struct pipe_surface **src_surfaces;
115 struct pipe_surface **dst_surfaces;
116 unsigned i;
117
118 if (src->interlaced != dst->interlaced)
119 return VA_STATUS_ERROR_INVALID_SURFACE;
120
121 src_surfaces = src->get_surfaces(src);
122 if (!src_surfaces || !src_surfaces[0])
123 return VA_STATUS_ERROR_INVALID_SURFACE;
124
125 dst_surfaces = dst->get_surfaces(dst);
126 if (!dst_surfaces || !dst_surfaces[0])
127 return VA_STATUS_ERROR_INVALID_SURFACE;
128
129 for (i = 0; i < VL_MAX_SURFACES; ++i) {
130 struct pipe_surface *from = src_surfaces[i];
131 struct pipe_blit_info blit;
132
133 if (src->interlaced) {
134 /* Not 100% accurate, but close enough */
135 switch (deinterlace) {
136 case VL_COMPOSITOR_BOB_TOP:
137 from = src_surfaces[i & ~1];
138 break;
139 case VL_COMPOSITOR_BOB_BOTTOM:
140 from = src_surfaces[(i & ~1) + 1];
141 break;
142 default:
143 break;
144 }
145 }
146
147 if (!from || !dst_surfaces[i])
148 continue;
149
150 memset(&blit, 0, sizeof(blit));
151 blit.src.resource = from->texture;
152 blit.src.format = from->format;
153 blit.src.level = 0;
154 blit.src.box.z = from->u.tex.first_layer;
155 blit.src.box.depth = 1;
156 vlVaGetBox(src, i, &blit.src.box, src_region);
157
158 blit.dst.resource = dst_surfaces[i]->texture;
159 blit.dst.format = dst_surfaces[i]->format;
160 blit.dst.level = 0;
161 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
162 blit.dst.box.depth = 1;
163 vlVaGetBox(dst, i, &blit.dst.box, dst_region);
164
165 blit.mask = PIPE_MASK_RGBA;
166 blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
167
168 drv->pipe->blit(drv->pipe, &blit);
169 }
170
171 // TODO: figure out why this is necessary for DMA-buf sharing
172 drv->pipe->flush(drv->pipe, NULL, 0);
173
174 return VA_STATUS_SUCCESS;
175 }
176
177 VAStatus
178 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
179 {
180 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE;
181 VARectangle def_src_region, def_dst_region;
182 const VARectangle *src_region, *dst_region;
183 VAProcPipelineParameterBuffer *param;
184 vlVaSurface *src_surface;
185 unsigned i;
186
187 if (!drv || !context)
188 return VA_STATUS_ERROR_INVALID_CONTEXT;
189
190 if (!buf || !buf->data)
191 return VA_STATUS_ERROR_INVALID_BUFFER;
192
193 if (!context->target)
194 return VA_STATUS_ERROR_INVALID_SURFACE;
195
196 param = buf->data;
197
198 src_surface = handle_table_get(drv->htab, param->surface);
199 if (!src_surface || !src_surface->buffer)
200 return VA_STATUS_ERROR_INVALID_SURFACE;
201
202 for (i = 0; i < param->num_filters; i++) {
203 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
204 VAProcFilterParameterBufferBase *filter;
205
206 if (!buf || buf->type != VAProcFilterParameterBufferType)
207 return VA_STATUS_ERROR_INVALID_BUFFER;
208
209 filter = buf->data;
210 switch (filter->type) {
211 case VAProcFilterDeinterlacing: {
212 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
213 switch (deint->algorithm) {
214 case VAProcDeinterlacingBob:
215 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
216 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
217 else
218 deinterlace = VL_COMPOSITOR_BOB_TOP;
219 break;
220
221 case VAProcDeinterlacingWeave:
222 deinterlace = VL_COMPOSITOR_WEAVE;
223 break;
224
225 default:
226 return VA_STATUS_ERROR_UNIMPLEMENTED;
227 }
228
229 break;
230 }
231
232 default:
233 return VA_STATUS_ERROR_UNIMPLEMENTED;
234 }
235 }
236
237 src_region = vlVaRegionDefault(param->surface_region, src_surface->buffer, &def_src_region);
238 dst_region = vlVaRegionDefault(param->output_region, context->target, &def_dst_region);
239
240 if (context->target->buffer_format != PIPE_FORMAT_NV12)
241 return vlVaPostProcCompositor(drv, context, src_region, dst_region,
242 src_surface->buffer, context->target,
243 deinterlace);
244 else
245 return vlVaPostProcBlit(drv, context, src_region, dst_region,
246 src_surface->buffer, context->target,
247 deinterlace);
248 }