1b8e80941Smrg/**************************************************************************
2b8e80941Smrg *
3b8e80941Smrg * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4b8e80941Smrg * Copyright 2014 Advanced Micro Devices, Inc.
5b8e80941Smrg * All Rights Reserved.
6b8e80941Smrg *
7b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8b8e80941Smrg * copy of this software and associated documentation files (the
9b8e80941Smrg * "Software"), to deal in the Software without restriction, including
10b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish,
11b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to
12b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to
13b8e80941Smrg * the following conditions:
14b8e80941Smrg *
15b8e80941Smrg * The above copyright notice and this permission notice (including the
16b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions
17b8e80941Smrg * of the Software.
18b8e80941Smrg *
19b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21b8e80941Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22b8e80941Smrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23b8e80941Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24b8e80941Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25b8e80941Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26b8e80941Smrg *
27b8e80941Smrg **************************************************************************/
28b8e80941Smrg
29b8e80941Smrg#include "pipe/p_screen.h"
30b8e80941Smrg
31b8e80941Smrg#include "util/u_memory.h"
32b8e80941Smrg#include "util/u_handle_table.h"
33b8e80941Smrg#include "util/u_surface.h"
34b8e80941Smrg#include "util/u_video.h"
35b8e80941Smrg
36b8e80941Smrg#include "vl/vl_winsys.h"
37b8e80941Smrg#include "vl/vl_video_buffer.h"
38b8e80941Smrg
39b8e80941Smrg#include "va_private.h"
40b8e80941Smrg
41b8e80941Smrgstatic const VAImageFormat formats[] =
42b8e80941Smrg{
43b8e80941Smrg   {VA_FOURCC('N','V','1','2')},
44b8e80941Smrg   {VA_FOURCC('P','0','1','0')},
45b8e80941Smrg   {VA_FOURCC('P','0','1','6')},
46b8e80941Smrg   {VA_FOURCC('I','4','2','0')},
47b8e80941Smrg   {VA_FOURCC('Y','V','1','2')},
48b8e80941Smrg   {VA_FOURCC('Y','U','Y','V')},
49b8e80941Smrg   {VA_FOURCC('U','Y','V','Y')},
50b8e80941Smrg   {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
51b8e80941Smrg    0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
52b8e80941Smrg   {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
53b8e80941Smrg    0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
54b8e80941Smrg   {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
55b8e80941Smrg    0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
56b8e80941Smrg   {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
57b8e80941Smrg    0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
58b8e80941Smrg};
59b8e80941Smrg
60b8e80941Smrgstatic void
61b8e80941SmrgvlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
62b8e80941Smrg                     unsigned *width, unsigned *height)
63b8e80941Smrg{
64b8e80941Smrg   *width = p_surf->templat.width;
65b8e80941Smrg   *height = p_surf->templat.height;
66b8e80941Smrg
67b8e80941Smrg   vl_video_buffer_adjust_size(width, height, component,
68b8e80941Smrg                               p_surf->templat.chroma_format,
69b8e80941Smrg                               p_surf->templat.interlaced);
70b8e80941Smrg}
71b8e80941Smrg
72b8e80941SmrgVAStatus
73b8e80941SmrgvlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
74b8e80941Smrg{
75b8e80941Smrg   struct pipe_screen *pscreen;
76b8e80941Smrg   enum pipe_format format;
77b8e80941Smrg   int i;
78b8e80941Smrg
79b8e80941Smrg   STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
80b8e80941Smrg
81b8e80941Smrg   if (!ctx)
82b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
83b8e80941Smrg
84b8e80941Smrg   if (!(format_list && num_formats))
85b8e80941Smrg      return VA_STATUS_ERROR_INVALID_PARAMETER;
86b8e80941Smrg
87b8e80941Smrg   *num_formats = 0;
88b8e80941Smrg   pscreen = VL_VA_PSCREEN(ctx);
89b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(formats); ++i) {
90b8e80941Smrg      format = VaFourccToPipeFormat(formats[i].fourcc);
91b8e80941Smrg      if (pscreen->is_video_format_supported(pscreen, format,
92b8e80941Smrg          PIPE_VIDEO_PROFILE_UNKNOWN,
93b8e80941Smrg          PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
94b8e80941Smrg         format_list[(*num_formats)++] = formats[i];
95b8e80941Smrg   }
96b8e80941Smrg
97b8e80941Smrg   return VA_STATUS_SUCCESS;
98b8e80941Smrg}
99b8e80941Smrg
100b8e80941SmrgVAStatus
101b8e80941SmrgvlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
102b8e80941Smrg{
103b8e80941Smrg   VAStatus status;
104b8e80941Smrg   vlVaDriver *drv;
105b8e80941Smrg   VAImage *img;
106b8e80941Smrg   int w, h;
107b8e80941Smrg
108b8e80941Smrg   if (!ctx)
109b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
110b8e80941Smrg
111b8e80941Smrg   if (!(format && image && width && height))
112b8e80941Smrg      return VA_STATUS_ERROR_INVALID_PARAMETER;
113b8e80941Smrg
114b8e80941Smrg   drv = VL_VA_DRIVER(ctx);
115b8e80941Smrg
116b8e80941Smrg   img = CALLOC(1, sizeof(VAImage));
117b8e80941Smrg   if (!img)
118b8e80941Smrg      return VA_STATUS_ERROR_ALLOCATION_FAILED;
119b8e80941Smrg   mtx_lock(&drv->mutex);
120b8e80941Smrg   img->image_id = handle_table_add(drv->htab, img);
121b8e80941Smrg   mtx_unlock(&drv->mutex);
122b8e80941Smrg
123b8e80941Smrg   img->format = *format;
124b8e80941Smrg   img->width = width;
125b8e80941Smrg   img->height = height;
126b8e80941Smrg   w = align(width, 2);
127b8e80941Smrg   h = align(height, 2);
128b8e80941Smrg
129b8e80941Smrg   switch (format->fourcc) {
130b8e80941Smrg   case VA_FOURCC('N','V','1','2'):
131b8e80941Smrg      img->num_planes = 2;
132b8e80941Smrg      img->pitches[0] = w;
133b8e80941Smrg      img->offsets[0] = 0;
134b8e80941Smrg      img->pitches[1] = w;
135b8e80941Smrg      img->offsets[1] = w * h;
136b8e80941Smrg      img->data_size  = w * h * 3 / 2;
137b8e80941Smrg      break;
138b8e80941Smrg
139b8e80941Smrg   case VA_FOURCC('P','0','1','0'):
140b8e80941Smrg   case VA_FOURCC('P','0','1','6'):
141b8e80941Smrg      img->num_planes = 2;
142b8e80941Smrg      img->pitches[0] = w * 2;
143b8e80941Smrg      img->offsets[0] = 0;
144b8e80941Smrg      img->pitches[1] = w * 2;
145b8e80941Smrg      img->offsets[1] = w * h * 2;
146b8e80941Smrg      img->data_size  = w * h * 3;
147b8e80941Smrg      break;
148b8e80941Smrg
149b8e80941Smrg   case VA_FOURCC('I','4','2','0'):
150b8e80941Smrg   case VA_FOURCC('Y','V','1','2'):
151b8e80941Smrg      img->num_planes = 3;
152b8e80941Smrg      img->pitches[0] = w;
153b8e80941Smrg      img->offsets[0] = 0;
154b8e80941Smrg      img->pitches[1] = w / 2;
155b8e80941Smrg      img->offsets[1] = w * h;
156b8e80941Smrg      img->pitches[2] = w / 2;
157b8e80941Smrg      img->offsets[2] = w * h * 5 / 4;
158b8e80941Smrg      img->data_size  = w * h * 3 / 2;
159b8e80941Smrg      break;
160b8e80941Smrg
161b8e80941Smrg   case VA_FOURCC('U','Y','V','Y'):
162b8e80941Smrg   case VA_FOURCC('Y','U','Y','V'):
163b8e80941Smrg      img->num_planes = 1;
164b8e80941Smrg      img->pitches[0] = w * 2;
165b8e80941Smrg      img->offsets[0] = 0;
166b8e80941Smrg      img->data_size  = w * h * 2;
167b8e80941Smrg      break;
168b8e80941Smrg
169b8e80941Smrg   case VA_FOURCC('B','G','R','A'):
170b8e80941Smrg   case VA_FOURCC('R','G','B','A'):
171b8e80941Smrg   case VA_FOURCC('B','G','R','X'):
172b8e80941Smrg   case VA_FOURCC('R','G','B','X'):
173b8e80941Smrg      img->num_planes = 1;
174b8e80941Smrg      img->pitches[0] = w * 4;
175b8e80941Smrg      img->offsets[0] = 0;
176b8e80941Smrg      img->data_size  = w * h * 4;
177b8e80941Smrg      break;
178b8e80941Smrg
179b8e80941Smrg   default:
180b8e80941Smrg      return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
181b8e80941Smrg   }
182b8e80941Smrg
183b8e80941Smrg   status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
184b8e80941Smrg                           align(img->data_size, 16),
185b8e80941Smrg                           1, NULL, &img->buf);
186b8e80941Smrg   if (status != VA_STATUS_SUCCESS)
187b8e80941Smrg      return status;
188b8e80941Smrg   *image = *img;
189b8e80941Smrg
190b8e80941Smrg   return status;
191b8e80941Smrg}
192b8e80941Smrg
193b8e80941SmrgVAStatus
194b8e80941SmrgvlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
195b8e80941Smrg{
196b8e80941Smrg   vlVaDriver *drv;
197b8e80941Smrg   vlVaSurface *surf;
198b8e80941Smrg   vlVaBuffer *img_buf;
199b8e80941Smrg   VAImage *img;
200b8e80941Smrg   struct pipe_screen *screen;
201b8e80941Smrg   struct pipe_surface **surfaces;
202b8e80941Smrg   int w;
203b8e80941Smrg   int h;
204b8e80941Smrg   int i;
205b8e80941Smrg   unsigned stride = 0;
206b8e80941Smrg   unsigned offset = 0;
207b8e80941Smrg
208b8e80941Smrg   if (!ctx)
209b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
210b8e80941Smrg
211b8e80941Smrg   drv = VL_VA_DRIVER(ctx);
212b8e80941Smrg
213b8e80941Smrg   if (!drv)
214b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
215b8e80941Smrg
216b8e80941Smrg   screen = VL_VA_PSCREEN(ctx);
217b8e80941Smrg
218b8e80941Smrg   if (!screen)
219b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
220b8e80941Smrg
221b8e80941Smrg   surf = handle_table_get(drv->htab, surface);
222b8e80941Smrg
223b8e80941Smrg   if (!surf || !surf->buffer)
224b8e80941Smrg      return VA_STATUS_ERROR_INVALID_SURFACE;
225b8e80941Smrg
226b8e80941Smrg   if (surf->buffer->interlaced)
227b8e80941Smrg     return VA_STATUS_ERROR_OPERATION_FAILED;
228b8e80941Smrg
229b8e80941Smrg   surfaces = surf->buffer->get_surfaces(surf->buffer);
230b8e80941Smrg   if (!surfaces || !surfaces[0]->texture)
231b8e80941Smrg      return VA_STATUS_ERROR_ALLOCATION_FAILED;
232b8e80941Smrg
233b8e80941Smrg   img = CALLOC(1, sizeof(VAImage));
234b8e80941Smrg   if (!img)
235b8e80941Smrg      return VA_STATUS_ERROR_ALLOCATION_FAILED;
236b8e80941Smrg
237b8e80941Smrg   img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
238b8e80941Smrg   img->buf = VA_INVALID_ID;
239b8e80941Smrg   img->width = surf->buffer->width;
240b8e80941Smrg   img->height = surf->buffer->height;
241b8e80941Smrg   img->num_palette_entries = 0;
242b8e80941Smrg   img->entry_bytes = 0;
243b8e80941Smrg   w = align(surf->buffer->width, 2);
244b8e80941Smrg   h = align(surf->buffer->height, 2);
245b8e80941Smrg
246b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(formats); ++i) {
247b8e80941Smrg      if (img->format.fourcc == formats[i].fourcc) {
248b8e80941Smrg         img->format = formats[i];
249b8e80941Smrg         break;
250b8e80941Smrg      }
251b8e80941Smrg   }
252b8e80941Smrg
253b8e80941Smrg   mtx_lock(&drv->mutex);
254b8e80941Smrg   if (screen->resource_get_info) {
255b8e80941Smrg      screen->resource_get_info(screen, surfaces[0]->texture, &stride,
256b8e80941Smrg                                &offset);
257b8e80941Smrg      if (!stride)
258b8e80941Smrg         offset = 0;
259b8e80941Smrg   }
260b8e80941Smrg
261b8e80941Smrg   switch (img->format.fourcc) {
262b8e80941Smrg   case VA_FOURCC('U','Y','V','Y'):
263b8e80941Smrg   case VA_FOURCC('Y','U','Y','V'):
264b8e80941Smrg      img->pitches[0] = stride > 0 ? stride : w * 2;
265b8e80941Smrg      assert(img->pitches[0] >= (w * 2));
266b8e80941Smrg      break;
267b8e80941Smrg
268b8e80941Smrg   case VA_FOURCC('B','G','R','A'):
269b8e80941Smrg   case VA_FOURCC('R','G','B','A'):
270b8e80941Smrg   case VA_FOURCC('B','G','R','X'):
271b8e80941Smrg   case VA_FOURCC('R','G','B','X'):
272b8e80941Smrg      img->pitches[0] = stride > 0 ? stride : w * 4;
273b8e80941Smrg      assert(img->pitches[0] >= (w * 4));
274b8e80941Smrg      break;
275b8e80941Smrg
276b8e80941Smrg   default:
277b8e80941Smrg      /* VaDeriveImage only supports contiguous planes. But there is now a
278b8e80941Smrg         more generic api vlVaExportSurfaceHandle. */
279b8e80941Smrg      FREE(img);
280b8e80941Smrg      mtx_unlock(&drv->mutex);
281b8e80941Smrg      return VA_STATUS_ERROR_OPERATION_FAILED;
282b8e80941Smrg   }
283b8e80941Smrg
284b8e80941Smrg   img->num_planes = 1;
285b8e80941Smrg   img->offsets[0] = offset;
286b8e80941Smrg   img->data_size  = img->pitches[0] * h;
287b8e80941Smrg
288b8e80941Smrg   img_buf = CALLOC(1, sizeof(vlVaBuffer));
289b8e80941Smrg   if (!img_buf) {
290b8e80941Smrg      FREE(img);
291b8e80941Smrg      mtx_unlock(&drv->mutex);
292b8e80941Smrg      return VA_STATUS_ERROR_ALLOCATION_FAILED;
293b8e80941Smrg   }
294b8e80941Smrg
295b8e80941Smrg   img->image_id = handle_table_add(drv->htab, img);
296b8e80941Smrg
297b8e80941Smrg   img_buf->type = VAImageBufferType;
298b8e80941Smrg   img_buf->size = img->data_size;
299b8e80941Smrg   img_buf->num_elements = 1;
300b8e80941Smrg
301b8e80941Smrg   pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
302b8e80941Smrg
303b8e80941Smrg   img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
304b8e80941Smrg   mtx_unlock(&drv->mutex);
305b8e80941Smrg
306b8e80941Smrg   *image = *img;
307b8e80941Smrg
308b8e80941Smrg   return VA_STATUS_SUCCESS;
309b8e80941Smrg}
310b8e80941Smrg
311b8e80941SmrgVAStatus
312b8e80941SmrgvlVaDestroyImage(VADriverContextP ctx, VAImageID image)
313b8e80941Smrg{
314b8e80941Smrg   vlVaDriver *drv;
315b8e80941Smrg   VAImage  *vaimage;
316b8e80941Smrg   VAStatus status;
317b8e80941Smrg
318b8e80941Smrg   if (!ctx)
319b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
320b8e80941Smrg
321b8e80941Smrg   drv = VL_VA_DRIVER(ctx);
322b8e80941Smrg   mtx_lock(&drv->mutex);
323b8e80941Smrg   vaimage = handle_table_get(drv->htab, image);
324b8e80941Smrg   if (!vaimage) {
325b8e80941Smrg      mtx_unlock(&drv->mutex);
326b8e80941Smrg      return VA_STATUS_ERROR_INVALID_IMAGE;
327b8e80941Smrg   }
328b8e80941Smrg
329b8e80941Smrg   handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
330b8e80941Smrg   mtx_unlock(&drv->mutex);
331b8e80941Smrg   status = vlVaDestroyBuffer(ctx, vaimage->buf);
332b8e80941Smrg   FREE(vaimage);
333b8e80941Smrg   return status;
334b8e80941Smrg}
335b8e80941Smrg
336b8e80941SmrgVAStatus
337b8e80941SmrgvlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
338b8e80941Smrg{
339b8e80941Smrg   if (!ctx)
340b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
341b8e80941Smrg
342b8e80941Smrg   return VA_STATUS_ERROR_UNIMPLEMENTED;
343b8e80941Smrg}
344b8e80941Smrg
345b8e80941SmrgVAStatus
346b8e80941SmrgvlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
347b8e80941Smrg             unsigned int width, unsigned int height, VAImageID image)
348b8e80941Smrg{
349b8e80941Smrg   vlVaDriver *drv;
350b8e80941Smrg   vlVaSurface *surf;
351b8e80941Smrg   vlVaBuffer *img_buf;
352b8e80941Smrg   VAImage *vaimage;
353b8e80941Smrg   struct pipe_sampler_view **views;
354b8e80941Smrg   enum pipe_format format;
355b8e80941Smrg   bool convert = false;
356b8e80941Smrg   void *data[3];
357b8e80941Smrg   unsigned pitches[3], i, j;
358b8e80941Smrg
359b8e80941Smrg   if (!ctx)
360b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
361b8e80941Smrg
362b8e80941Smrg   drv = VL_VA_DRIVER(ctx);
363b8e80941Smrg
364b8e80941Smrg   mtx_lock(&drv->mutex);
365b8e80941Smrg   surf = handle_table_get(drv->htab, surface);
366b8e80941Smrg   if (!surf || !surf->buffer) {
367b8e80941Smrg      mtx_unlock(&drv->mutex);
368b8e80941Smrg      return VA_STATUS_ERROR_INVALID_SURFACE;
369b8e80941Smrg   }
370b8e80941Smrg
371b8e80941Smrg   vaimage = handle_table_get(drv->htab, image);
372b8e80941Smrg   if (!vaimage) {
373b8e80941Smrg      mtx_unlock(&drv->mutex);
374b8e80941Smrg      return VA_STATUS_ERROR_INVALID_IMAGE;
375b8e80941Smrg   }
376b8e80941Smrg
377b8e80941Smrg   if (x < 0 || y < 0) {
378b8e80941Smrg      mtx_unlock(&drv->mutex);
379b8e80941Smrg      return VA_STATUS_ERROR_INVALID_PARAMETER;
380b8e80941Smrg   }
381b8e80941Smrg
382b8e80941Smrg   if (x + width > surf->templat.width ||
383b8e80941Smrg       y + height > surf->templat.height) {
384b8e80941Smrg      mtx_unlock(&drv->mutex);
385b8e80941Smrg      return VA_STATUS_ERROR_INVALID_PARAMETER;
386b8e80941Smrg   }
387b8e80941Smrg
388b8e80941Smrg   if (width > vaimage->width ||
389b8e80941Smrg       height > vaimage->height) {
390b8e80941Smrg      mtx_unlock(&drv->mutex);
391b8e80941Smrg      return VA_STATUS_ERROR_INVALID_PARAMETER;
392b8e80941Smrg   }
393b8e80941Smrg
394b8e80941Smrg   img_buf = handle_table_get(drv->htab, vaimage->buf);
395b8e80941Smrg   if (!img_buf) {
396b8e80941Smrg      mtx_unlock(&drv->mutex);
397b8e80941Smrg      return VA_STATUS_ERROR_INVALID_BUFFER;
398b8e80941Smrg   }
399b8e80941Smrg
400b8e80941Smrg   format = VaFourccToPipeFormat(vaimage->format.fourcc);
401b8e80941Smrg   if (format == PIPE_FORMAT_NONE) {
402b8e80941Smrg      mtx_unlock(&drv->mutex);
403b8e80941Smrg      return VA_STATUS_ERROR_OPERATION_FAILED;
404b8e80941Smrg   }
405b8e80941Smrg
406b8e80941Smrg   if (format != surf->buffer->buffer_format) {
407b8e80941Smrg      /* support NV12 to YV12 and IYUV conversion now only */
408b8e80941Smrg      if ((format == PIPE_FORMAT_YV12 &&
409b8e80941Smrg          surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
410b8e80941Smrg          (format == PIPE_FORMAT_IYUV &&
411b8e80941Smrg          surf->buffer->buffer_format == PIPE_FORMAT_NV12))
412b8e80941Smrg         convert = true;
413b8e80941Smrg      else {
414b8e80941Smrg         mtx_unlock(&drv->mutex);
415b8e80941Smrg         return VA_STATUS_ERROR_OPERATION_FAILED;
416b8e80941Smrg      }
417b8e80941Smrg   }
418b8e80941Smrg
419b8e80941Smrg   views = surf->buffer->get_sampler_view_planes(surf->buffer);
420b8e80941Smrg   if (!views) {
421b8e80941Smrg      mtx_unlock(&drv->mutex);
422b8e80941Smrg      return VA_STATUS_ERROR_OPERATION_FAILED;
423b8e80941Smrg   }
424b8e80941Smrg
425b8e80941Smrg   for (i = 0; i < vaimage->num_planes; i++) {
426b8e80941Smrg      data[i] = img_buf->data + vaimage->offsets[i];
427b8e80941Smrg      pitches[i] = vaimage->pitches[i];
428b8e80941Smrg   }
429b8e80941Smrg   if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
430b8e80941Smrg      void *tmp_d;
431b8e80941Smrg      unsigned tmp_p;
432b8e80941Smrg      tmp_d  = data[1];
433b8e80941Smrg      data[1] = data[2];
434b8e80941Smrg      data[2] = tmp_d;
435b8e80941Smrg      tmp_p = pitches[1];
436b8e80941Smrg      pitches[1] = pitches[2];
437b8e80941Smrg      pitches[2] = tmp_p;
438b8e80941Smrg   }
439b8e80941Smrg
440b8e80941Smrg   for (i = 0; i < vaimage->num_planes; i++) {
441b8e80941Smrg      unsigned box_w = align(width, 2);
442b8e80941Smrg      unsigned box_h = align(height, 2);
443b8e80941Smrg      unsigned box_x = x & ~1;
444b8e80941Smrg      unsigned box_y = y & ~1;
445b8e80941Smrg      if (!views[i]) continue;
446b8e80941Smrg      vl_video_buffer_adjust_size(&box_w, &box_h, i,
447b8e80941Smrg                                  surf->templat.chroma_format,
448b8e80941Smrg                                  surf->templat.interlaced);
449b8e80941Smrg      vl_video_buffer_adjust_size(&box_x, &box_y, i,
450b8e80941Smrg                                  surf->templat.chroma_format,
451b8e80941Smrg                                  surf->templat.interlaced);
452b8e80941Smrg      for (j = 0; j < views[i]->texture->array_size; ++j) {
453b8e80941Smrg         struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
454b8e80941Smrg         struct pipe_transfer *transfer;
455b8e80941Smrg         uint8_t *map;
456b8e80941Smrg         map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
457b8e80941Smrg                  PIPE_TRANSFER_READ, &box, &transfer);
458b8e80941Smrg         if (!map) {
459b8e80941Smrg            mtx_unlock(&drv->mutex);
460b8e80941Smrg            return VA_STATUS_ERROR_OPERATION_FAILED;
461b8e80941Smrg         }
462b8e80941Smrg
463b8e80941Smrg         if (i == 1 && convert) {
464b8e80941Smrg            u_copy_nv12_to_yv12(data, pitches, i, j,
465b8e80941Smrg               transfer->stride, views[i]->texture->array_size,
466b8e80941Smrg               map, box.width, box.height);
467b8e80941Smrg         } else {
468b8e80941Smrg            util_copy_rect(data[i] + pitches[i] * j,
469b8e80941Smrg               views[i]->texture->format,
470b8e80941Smrg               pitches[i] * views[i]->texture->array_size, 0, 0,
471b8e80941Smrg               box.width, box.height, map, transfer->stride, 0, 0);
472b8e80941Smrg         }
473b8e80941Smrg         pipe_transfer_unmap(drv->pipe, transfer);
474b8e80941Smrg      }
475b8e80941Smrg   }
476b8e80941Smrg   mtx_unlock(&drv->mutex);
477b8e80941Smrg
478b8e80941Smrg   return VA_STATUS_SUCCESS;
479b8e80941Smrg}
480b8e80941Smrg
481b8e80941SmrgVAStatus
482b8e80941SmrgvlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
483b8e80941Smrg             int src_x, int src_y, unsigned int src_width, unsigned int src_height,
484b8e80941Smrg             int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
485b8e80941Smrg{
486b8e80941Smrg   vlVaDriver *drv;
487b8e80941Smrg   vlVaSurface *surf;
488b8e80941Smrg   vlVaBuffer *img_buf;
489b8e80941Smrg   VAImage *vaimage;
490b8e80941Smrg   struct pipe_sampler_view **views;
491b8e80941Smrg   enum pipe_format format;
492b8e80941Smrg   void *data[3];
493b8e80941Smrg   unsigned pitches[3], i, j;
494b8e80941Smrg
495b8e80941Smrg   if (!ctx)
496b8e80941Smrg      return VA_STATUS_ERROR_INVALID_CONTEXT;
497b8e80941Smrg
498b8e80941Smrg   drv = VL_VA_DRIVER(ctx);
499b8e80941Smrg   mtx_lock(&drv->mutex);
500b8e80941Smrg
501b8e80941Smrg   surf = handle_table_get(drv->htab, surface);
502b8e80941Smrg   if (!surf || !surf->buffer) {
503b8e80941Smrg      mtx_unlock(&drv->mutex);
504b8e80941Smrg      return VA_STATUS_ERROR_INVALID_SURFACE;
505b8e80941Smrg   }
506b8e80941Smrg
507b8e80941Smrg   vaimage = handle_table_get(drv->htab, image);
508b8e80941Smrg   if (!vaimage) {
509b8e80941Smrg      mtx_unlock(&drv->mutex);
510b8e80941Smrg      return VA_STATUS_ERROR_INVALID_IMAGE;
511b8e80941Smrg   }
512b8e80941Smrg
513b8e80941Smrg   img_buf = handle_table_get(drv->htab, vaimage->buf);
514b8e80941Smrg   if (!img_buf) {
515b8e80941Smrg      mtx_unlock(&drv->mutex);
516b8e80941Smrg      return VA_STATUS_ERROR_INVALID_BUFFER;
517b8e80941Smrg   }
518b8e80941Smrg
519b8e80941Smrg   if (img_buf->derived_surface.resource) {
520b8e80941Smrg      /* Attempting to transfer derived image to surface */
521b8e80941Smrg      mtx_unlock(&drv->mutex);
522b8e80941Smrg      return VA_STATUS_ERROR_UNIMPLEMENTED;
523b8e80941Smrg   }
524b8e80941Smrg
525b8e80941Smrg   format = VaFourccToPipeFormat(vaimage->format.fourcc);
526b8e80941Smrg
527b8e80941Smrg   if (format == PIPE_FORMAT_NONE) {
528b8e80941Smrg      mtx_unlock(&drv->mutex);
529b8e80941Smrg      return VA_STATUS_ERROR_OPERATION_FAILED;
530b8e80941Smrg   }
531b8e80941Smrg
532b8e80941Smrg   if ((format != surf->buffer->buffer_format) &&
533b8e80941Smrg         ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
534b8e80941Smrg         ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
535b8e80941Smrg      struct pipe_video_buffer *tmp_buf;
536b8e80941Smrg
537b8e80941Smrg      surf->templat.buffer_format = format;
538b8e80941Smrg      if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
539b8e80941Smrg          format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
540b8e80941Smrg          format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
541b8e80941Smrg         surf->templat.interlaced = false;
542b8e80941Smrg      tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
543b8e80941Smrg
544b8e80941Smrg      if (!tmp_buf) {
545b8e80941Smrg         mtx_unlock(&drv->mutex);
546b8e80941Smrg         return VA_STATUS_ERROR_ALLOCATION_FAILED;
547b8e80941Smrg      }
548b8e80941Smrg
549b8e80941Smrg      surf->buffer->destroy(surf->buffer);
550b8e80941Smrg      surf->buffer = tmp_buf;
551b8e80941Smrg   }
552b8e80941Smrg
553b8e80941Smrg   views = surf->buffer->get_sampler_view_planes(surf->buffer);
554b8e80941Smrg   if (!views) {
555b8e80941Smrg      mtx_unlock(&drv->mutex);
556b8e80941Smrg      return VA_STATUS_ERROR_OPERATION_FAILED;
557b8e80941Smrg   }
558b8e80941Smrg
559b8e80941Smrg   for (i = 0; i < vaimage->num_planes; i++) {
560b8e80941Smrg      data[i] = img_buf->data + vaimage->offsets[i];
561b8e80941Smrg      pitches[i] = vaimage->pitches[i];
562b8e80941Smrg   }
563b8e80941Smrg   if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
564b8e80941Smrg      void *tmp_d;
565b8e80941Smrg      unsigned tmp_p;
566b8e80941Smrg      tmp_d  = data[1];
567b8e80941Smrg      data[1] = data[2];
568b8e80941Smrg      data[2] = tmp_d;
569b8e80941Smrg      tmp_p = pitches[1];
570b8e80941Smrg      pitches[1] = pitches[2];
571b8e80941Smrg      pitches[2] = tmp_p;
572b8e80941Smrg   }
573b8e80941Smrg
574b8e80941Smrg   for (i = 0; i < vaimage->num_planes; ++i) {
575b8e80941Smrg      unsigned width, height;
576b8e80941Smrg      struct pipe_resource *tex;
577b8e80941Smrg
578b8e80941Smrg      if (!views[i]) continue;
579b8e80941Smrg      tex = views[i]->texture;
580b8e80941Smrg
581b8e80941Smrg      vlVaVideoSurfaceSize(surf, i, &width, &height);
582b8e80941Smrg      for (j = 0; j < tex->array_size; ++j) {
583b8e80941Smrg         struct pipe_box dst_box = {0, 0, j, width, height, 1};
584b8e80941Smrg
585b8e80941Smrg         if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
586b8e80941Smrg             && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
587b8e80941Smrg             && i == 1) {
588b8e80941Smrg            struct pipe_transfer *transfer = NULL;
589b8e80941Smrg            uint8_t *map = NULL;
590b8e80941Smrg
591b8e80941Smrg            map = drv->pipe->transfer_map(drv->pipe,
592b8e80941Smrg                                          tex,
593b8e80941Smrg                                          0,
594b8e80941Smrg                                          PIPE_TRANSFER_WRITE |
595b8e80941Smrg                                          PIPE_TRANSFER_DISCARD_RANGE,
596b8e80941Smrg                                          &dst_box, &transfer);
597b8e80941Smrg            if (map == NULL) {
598b8e80941Smrg               mtx_unlock(&drv->mutex);
599b8e80941Smrg               return VA_STATUS_ERROR_OPERATION_FAILED;
600b8e80941Smrg            }
601b8e80941Smrg
602b8e80941Smrg            u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
603b8e80941Smrg                                  transfer->stride, tex->array_size,
604b8e80941Smrg                                  map, dst_box.width, dst_box.height);
605b8e80941Smrg            pipe_transfer_unmap(drv->pipe, transfer);
606b8e80941Smrg         } else {
607b8e80941Smrg            drv->pipe->texture_subdata(drv->pipe, tex, 0,
608b8e80941Smrg                                       PIPE_TRANSFER_WRITE, &dst_box,
609b8e80941Smrg                                       data[i] + pitches[i] * j,
610b8e80941Smrg                                       pitches[i] * views[i]->texture->array_size, 0);
611b8e80941Smrg         }
612b8e80941Smrg      }
613b8e80941Smrg   }
614b8e80941Smrg   mtx_unlock(&drv->mutex);
615b8e80941Smrg
616b8e80941Smrg   return VA_STATUS_SUCCESS;
617b8e80941Smrg}
618