va: use a compute shader for the blit
[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 #include "util/u_memory.h"
30 #include "util/u_compute.h"
31
32 #include "vl/vl_defines.h"
33 #include "vl/vl_video_buffer.h"
34 #include "vl/vl_deint_filter.h"
35
36 #include "va_private.h"
37
38 static const VARectangle *
39 vlVaRegionDefault(const VARectangle *region, vlVaSurface *surf,
40 VARectangle *def)
41 {
42 if (region)
43 return region;
44
45 def->x = 0;
46 def->y = 0;
47 def->width = surf->templat.width;
48 def->height = surf->templat.height;
49
50 return def;
51 }
52
53 static VAStatus
54 vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context,
55 const VARectangle *src_region,
56 const VARectangle *dst_region,
57 struct pipe_video_buffer *src,
58 struct pipe_video_buffer *dst,
59 enum vl_compositor_deinterlace deinterlace)
60 {
61 struct pipe_surface **surfaces;
62 struct u_rect src_rect;
63 struct u_rect dst_rect;
64
65 surfaces = dst->get_surfaces(dst);
66 if (!surfaces || !surfaces[0])
67 return VA_STATUS_ERROR_INVALID_SURFACE;
68
69 src_rect.x0 = src_region->x;
70 src_rect.y0 = src_region->y;
71 src_rect.x1 = src_region->x + src_region->width;
72 src_rect.y1 = src_region->y + src_region->height;
73
74 dst_rect.x0 = dst_region->x;
75 dst_rect.y0 = dst_region->y;
76 dst_rect.x1 = dst_region->x + dst_region->width;
77 dst_rect.y1 = dst_region->y + dst_region->height;
78
79 vl_compositor_clear_layers(&drv->cstate);
80 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src,
81 &src_rect, NULL, deinterlace);
82 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
83 vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false);
84
85 drv->pipe->flush(drv->pipe, NULL, 0);
86 return VA_STATUS_SUCCESS;
87 }
88
89 static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
90 struct pipe_box *box, const VARectangle *region)
91 {
92 unsigned plane = buf->interlaced ? idx / 2: idx;
93 unsigned x, y, width, height;
94
95 x = abs(region->x);
96 y = abs(region->y);
97 width = region->width;
98 height = region->height;
99
100 vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format,
101 buf->interlaced);
102 vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format,
103 buf->interlaced);
104
105 box->x = region->x < 0 ? -x : x;
106 box->y = region->y < 0 ? -y : y;
107 box->width = width;
108 box->height = height;
109 }
110
111 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
112 const VARectangle *src_region,
113 const VARectangle *dst_region,
114 struct pipe_video_buffer *src,
115 struct pipe_video_buffer *dst,
116 enum vl_compositor_deinterlace deinterlace)
117 {
118 struct pipe_surface **src_surfaces;
119 struct pipe_surface **dst_surfaces;
120 struct u_rect src_rect;
121 struct u_rect dst_rect;
122 bool scale = false;
123 bool grab = false;
124 unsigned i;
125
126 if ((src->buffer_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
127 src->buffer_format == PIPE_FORMAT_B8G8R8X8_UNORM) &&
128 !src->interlaced)
129 grab = true;
130
131 if (src->interlaced != dst->interlaced && dst->interlaced && !grab)
132 return VA_STATUS_ERROR_INVALID_SURFACE;
133
134 if ((src->width != dst->width || src->height != dst->height) &&
135 (src->interlaced && dst->interlaced))
136 scale = true;
137
138 src_surfaces = src->get_surfaces(src);
139 if (!src_surfaces || !src_surfaces[0])
140 return VA_STATUS_ERROR_INVALID_SURFACE;
141
142 if (scale || (grab && dst->interlaced)) {
143 vlVaSurface *surf;
144
145 surf = handle_table_get(drv->htab, context->target_id);
146 surf->templat.interlaced = false;
147 dst->destroy(dst);
148
149 if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat) != VA_STATUS_SUCCESS)
150 return VA_STATUS_ERROR_ALLOCATION_FAILED;
151
152 dst = context->target = surf->buffer;
153 }
154
155 dst_surfaces = dst->get_surfaces(dst);
156 if (!dst_surfaces || !dst_surfaces[0])
157 return VA_STATUS_ERROR_INVALID_SURFACE;
158
159 src_rect.x0 = src_region->x;
160 src_rect.y0 = src_region->y;
161 src_rect.x1 = src_region->x + src_region->width;
162 src_rect.y1 = src_region->y + src_region->height;
163
164 dst_rect.x0 = dst_region->x;
165 dst_rect.y0 = dst_region->y;
166 dst_rect.x1 = dst_region->x + dst_region->width;
167 dst_rect.y1 = dst_region->y + dst_region->height;
168
169 if (grab) {
170 vl_compositor_convert_rgb_to_yuv(&drv->cstate, &drv->compositor, 0,
171 ((struct vl_video_buffer *)src)->resources[0],
172 dst, &src_rect, &dst_rect);
173
174 return VA_STATUS_SUCCESS;
175 }
176
177 if (src->interlaced != dst->interlaced) {
178 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
179 src, dst, &src_rect, &dst_rect,
180 deinterlace);
181
182 return VA_STATUS_SUCCESS;
183 }
184
185 for (i = 0; i < VL_MAX_SURFACES; ++i) {
186 struct pipe_surface *from = src_surfaces[i];
187 struct pipe_blit_info blit;
188
189 if (src->interlaced) {
190 /* Not 100% accurate, but close enough */
191 switch (deinterlace) {
192 case VL_COMPOSITOR_BOB_TOP:
193 from = src_surfaces[i & ~1];
194 break;
195 case VL_COMPOSITOR_BOB_BOTTOM:
196 from = src_surfaces[(i & ~1) + 1];
197 break;
198 default:
199 break;
200 }
201 }
202
203 if (!from || !dst_surfaces[i])
204 continue;
205
206 memset(&blit, 0, sizeof(blit));
207 blit.src.resource = from->texture;
208 blit.src.format = from->format;
209 blit.src.level = 0;
210 blit.src.box.z = from->u.tex.first_layer;
211 blit.src.box.depth = 1;
212 vlVaGetBox(src, i, &blit.src.box, src_region);
213
214 blit.dst.resource = dst_surfaces[i]->texture;
215 blit.dst.format = dst_surfaces[i]->format;
216 blit.dst.level = 0;
217 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
218 blit.dst.box.depth = 1;
219 vlVaGetBox(dst, i, &blit.dst.box, dst_region);
220
221 blit.mask = PIPE_MASK_RGBA;
222 blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
223
224 if (drv->pipe->screen->get_param(drv->pipe->screen,
225 PIPE_CAP_PREFER_COMPUTE_BLIT_FOR_MULTIMEDIA))
226 util_compute_blit(drv->pipe, &blit, &context->blit_cs);
227 else
228 drv->pipe->blit(drv->pipe, &blit);
229 }
230
231 // TODO: figure out why this is necessary for DMA-buf sharing
232 drv->pipe->flush(drv->pipe, NULL, 0);
233
234 return VA_STATUS_SUCCESS;
235 }
236
237 static struct pipe_video_buffer *
238 vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,
239 VAProcPipelineParameterBuffer *param,
240 struct pipe_video_buffer *current,
241 unsigned field)
242 {
243 vlVaSurface *prevprev, *prev, *next;
244
245 if (param->num_forward_references < 2 ||
246 param->num_backward_references < 1)
247 return current;
248
249 prevprev = handle_table_get(drv->htab, param->forward_references[1]);
250 prev = handle_table_get(drv->htab, param->forward_references[0]);
251 next = handle_table_get(drv->htab, param->backward_references[0]);
252
253 if (!prevprev || !prev || !next)
254 return current;
255
256 if (context->deint && (context->deint->video_width != current->width ||
257 context->deint->video_height != current->height)) {
258 vl_deint_filter_cleanup(context->deint);
259 FREE(context->deint);
260 context->deint = NULL;
261 }
262
263 if (!context->deint) {
264 context->deint = MALLOC(sizeof(struct vl_deint_filter));
265 if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,
266 current->height, false, false)) {
267 FREE(context->deint);
268 context->deint = NULL;
269 return current;
270 }
271 }
272
273 if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,
274 prev->buffer, current, next->buffer))
275 return current;
276
277 vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,
278 current, next->buffer, field);
279 return context->deint->video_buffer;
280 }
281
282 VAStatus
283 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
284 {
285 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE;
286 VARectangle def_src_region, def_dst_region;
287 const VARectangle *src_region, *dst_region;
288 VAProcPipelineParameterBuffer *param;
289 struct pipe_video_buffer *src;
290 vlVaSurface *src_surface, *dst_surface;
291 unsigned i;
292
293 if (!drv || !context)
294 return VA_STATUS_ERROR_INVALID_CONTEXT;
295
296 if (!buf || !buf->data)
297 return VA_STATUS_ERROR_INVALID_BUFFER;
298
299 if (!context->target)
300 return VA_STATUS_ERROR_INVALID_SURFACE;
301
302 param = buf->data;
303
304 src_surface = handle_table_get(drv->htab, param->surface);
305 dst_surface = handle_table_get(drv->htab, context->target_id);
306
307 if (!src_surface || !src_surface->buffer)
308 return VA_STATUS_ERROR_INVALID_SURFACE;
309
310 src = src_surface->buffer;
311
312 for (i = 0; i < param->num_filters; i++) {
313 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
314 VAProcFilterParameterBufferBase *filter;
315
316 if (!buf || buf->type != VAProcFilterParameterBufferType)
317 return VA_STATUS_ERROR_INVALID_BUFFER;
318
319 filter = buf->data;
320 switch (filter->type) {
321 case VAProcFilterDeinterlacing: {
322 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
323 switch (deint->algorithm) {
324 case VAProcDeinterlacingBob:
325 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
326 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
327 else
328 deinterlace = VL_COMPOSITOR_BOB_TOP;
329 break;
330
331 case VAProcDeinterlacingWeave:
332 deinterlace = VL_COMPOSITOR_WEAVE;
333 break;
334
335 case VAProcDeinterlacingMotionAdaptive:
336 src = vlVaApplyDeint(drv, context, param, src,
337 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));
338 break;
339
340 default:
341 return VA_STATUS_ERROR_UNIMPLEMENTED;
342 }
343
344 break;
345 }
346
347 default:
348 return VA_STATUS_ERROR_UNIMPLEMENTED;
349 }
350 }
351
352 src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region);
353 dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region);
354
355 if (context->target->buffer_format != PIPE_FORMAT_NV12 &&
356 context->target->buffer_format != PIPE_FORMAT_P016)
357 return vlVaPostProcCompositor(drv, context, src_region, dst_region,
358 src, context->target, deinterlace);
359 else
360 return vlVaPostProcBlit(drv, context, src_region, dst_region,
361 src, context->target, deinterlace);
362 }