• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen.
4  * Copyright 2011 Christian König.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include <assert.h>
30 
31 #include "pipe/p_state.h"
32 
33 #include "util/u_memory.h"
34 #include "util/u_debug.h"
35 #include "util/u_rect.h"
36 #include "vl/vl_defines.h"
37 
38 #include "vdpau_private.h"
39 
40 /**
41  * Create a VdpVideoSurface.
42  */
43 VdpStatus
vlVdpVideoSurfaceCreate(VdpDevice device,VdpChromaType chroma_type,uint32_t width,uint32_t height,VdpVideoSurface * surface)44 vlVdpVideoSurfaceCreate(VdpDevice device, VdpChromaType chroma_type,
45                         uint32_t width, uint32_t height,
46                         VdpVideoSurface *surface)
47 {
48    struct pipe_context *pipe;
49    vlVdpSurface *p_surf;
50    VdpStatus ret;
51 
52    if (!(width && height)) {
53       ret = VDP_STATUS_INVALID_SIZE;
54       goto inv_size;
55    }
56 
57    if (!vlCreateHTAB()) {
58       ret = VDP_STATUS_RESOURCES;
59       goto no_htab;
60    }
61 
62    p_surf = CALLOC(1, sizeof(vlVdpSurface));
63    if (!p_surf) {
64       ret = VDP_STATUS_RESOURCES;
65       goto no_res;
66    }
67 
68    vlVdpDevice *dev = vlGetDataHTAB(device);
69    if (!dev) {
70       ret = VDP_STATUS_INVALID_HANDLE;
71       goto inv_device;
72    }
73 
74    p_surf->device = dev;
75    pipe = dev->context;
76 
77    pipe_mutex_lock(dev->mutex);
78    memset(&p_surf->templat, 0, sizeof(p_surf->templat));
79    p_surf->templat.buffer_format = pipe->screen->get_video_param
80    (
81       pipe->screen,
82       PIPE_VIDEO_PROFILE_UNKNOWN,
83       PIPE_VIDEO_CAP_PREFERED_FORMAT
84    );
85    p_surf->templat.chroma_format = ChromaToPipe(chroma_type);
86    p_surf->templat.width = width;
87    p_surf->templat.height = height;
88    p_surf->templat.interlaced = pipe->screen->get_video_param
89    (
90       pipe->screen,
91       PIPE_VIDEO_PROFILE_UNKNOWN,
92       PIPE_VIDEO_CAP_PREFERS_INTERLACED
93    );
94    p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
95    vlVdpVideoSurfaceClear(p_surf);
96    pipe_mutex_unlock(dev->mutex);
97 
98    *surface = vlAddDataHTAB(p_surf);
99    if (*surface == 0) {
100       ret = VDP_STATUS_ERROR;
101       goto no_handle;
102    }
103 
104    return VDP_STATUS_OK;
105 
106 no_handle:
107    p_surf->video_buffer->destroy(p_surf->video_buffer);
108 
109 inv_device:
110    FREE(p_surf);
111 
112 no_res:
113 no_htab:
114 inv_size:
115    return ret;
116 }
117 
118 /**
119  * Destroy a VdpVideoSurface.
120  */
121 VdpStatus
vlVdpVideoSurfaceDestroy(VdpVideoSurface surface)122 vlVdpVideoSurfaceDestroy(VdpVideoSurface surface)
123 {
124    vlVdpSurface *p_surf;
125 
126    p_surf = (vlVdpSurface *)vlGetDataHTAB((vlHandle)surface);
127    if (!p_surf)
128       return VDP_STATUS_INVALID_HANDLE;
129 
130    pipe_mutex_lock(p_surf->device->mutex);
131    if (p_surf->video_buffer)
132       p_surf->video_buffer->destroy(p_surf->video_buffer);
133    pipe_mutex_unlock(p_surf->device->mutex);
134 
135    FREE(p_surf);
136    return VDP_STATUS_OK;
137 }
138 
139 /**
140  * Retrieve the parameters used to create a VdpVideoSurface.
141  */
142 VdpStatus
vlVdpVideoSurfaceGetParameters(VdpVideoSurface surface,VdpChromaType * chroma_type,uint32_t * width,uint32_t * height)143 vlVdpVideoSurfaceGetParameters(VdpVideoSurface surface,
144                                VdpChromaType *chroma_type,
145                                uint32_t *width, uint32_t *height)
146 {
147    if (!(width && height && chroma_type))
148       return VDP_STATUS_INVALID_POINTER;
149 
150    vlVdpSurface *p_surf = vlGetDataHTAB(surface);
151    if (!p_surf)
152       return VDP_STATUS_INVALID_HANDLE;
153 
154    if (p_surf->video_buffer) {
155       *width = p_surf->video_buffer->width;
156       *height = p_surf->video_buffer->height;
157       *chroma_type = PipeToChroma(p_surf->video_buffer->chroma_format);
158    } else {
159       *width = p_surf->templat.width;
160       *height = p_surf->templat.height;
161       *chroma_type = PipeToChroma(p_surf->templat.chroma_format);
162    }
163 
164    return VDP_STATUS_OK;
165 }
166 
167 static void
vlVdpVideoSurfaceSize(vlVdpSurface * p_surf,int component,unsigned * width,unsigned * height)168 vlVdpVideoSurfaceSize(vlVdpSurface *p_surf, int component,
169                       unsigned *width, unsigned *height)
170 {
171    *width = p_surf->templat.width;
172    *height = p_surf->templat.height;
173 
174    if (component > 0) {
175       if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
176          *width /= 2;
177          *height /= 2;
178       } else if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
179          *height /= 2;
180       }
181       if (p_surf->templat.interlaced)
182          *height /= 2;
183    }
184 }
185 
186 /**
187  * Copy image data from a VdpVideoSurface to application memory in a specified
188  * YCbCr format.
189  */
190 VdpStatus
vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface,VdpYCbCrFormat destination_ycbcr_format,void * const * destination_data,uint32_t const * destination_pitches)191 vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface,
192                               VdpYCbCrFormat destination_ycbcr_format,
193                               void *const *destination_data,
194                               uint32_t const *destination_pitches)
195 {
196    vlVdpSurface *vlsurface;
197    struct pipe_context *pipe;
198    enum pipe_format format;
199    struct pipe_sampler_view **sampler_views;
200    unsigned i, j;
201 
202    vlsurface = vlGetDataHTAB(surface);
203    if (!vlsurface)
204       return VDP_STATUS_INVALID_HANDLE;
205 
206    pipe = vlsurface->device->context;
207    if (!pipe)
208       return VDP_STATUS_INVALID_HANDLE;
209 
210    format = FormatYCBCRToPipe(destination_ycbcr_format);
211    if (format == PIPE_FORMAT_NONE)
212        return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
213 
214    if (vlsurface->video_buffer == NULL || format != vlsurface->video_buffer->buffer_format)
215       return VDP_STATUS_NO_IMPLEMENTATION; /* TODO We don't support conversion (yet) */
216 
217    pipe_mutex_lock(vlsurface->device->mutex);
218    sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer);
219    if (!sampler_views) {
220       pipe_mutex_unlock(vlsurface->device->mutex);
221       return VDP_STATUS_RESOURCES;
222    }
223 
224    for (i = 0; i < 3; ++i) {
225       unsigned width, height;
226       struct pipe_sampler_view *sv = sampler_views[i];
227       if (!sv) continue;
228 
229       vlVdpVideoSurfaceSize(vlsurface, i, &width, &height);
230 
231       for (j = 0; j < sv->texture->depth0; ++j) {
232          struct pipe_box box = {
233             0, 0, j,
234             width, height, 1
235          };
236          struct pipe_transfer *transfer;
237          uint8_t *map;
238 
239          transfer = pipe->get_transfer(pipe, sv->texture, 0, PIPE_TRANSFER_READ, &box);
240          if (transfer == NULL) {
241             pipe_mutex_unlock(vlsurface->device->mutex);
242             return VDP_STATUS_RESOURCES;
243          }
244 
245          map = pipe_transfer_map(pipe, transfer);
246          if (map == NULL) {
247             pipe_transfer_destroy(pipe, transfer);
248             pipe_mutex_unlock(vlsurface->device->mutex);
249             return VDP_STATUS_RESOURCES;
250          }
251 
252          util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format,
253                         destination_pitches[i] * sv->texture->depth0, 0, 0,
254                         box.width, box.height, map, transfer->stride, 0, 0);
255 
256          pipe_transfer_unmap(pipe, transfer);
257          pipe_transfer_destroy(pipe, transfer);
258       }
259    }
260    pipe_mutex_unlock(vlsurface->device->mutex);
261 
262    return VDP_STATUS_OK;
263 }
264 
265 /**
266  * Copy image data from application memory in a specific YCbCr format to
267  * a VdpVideoSurface.
268  */
269 VdpStatus
vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,VdpYCbCrFormat source_ycbcr_format,void const * const * source_data,uint32_t const * source_pitches)270 vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
271                               VdpYCbCrFormat source_ycbcr_format,
272                               void const *const *source_data,
273                               uint32_t const *source_pitches)
274 {
275    enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format);
276    struct pipe_context *pipe;
277    struct pipe_sampler_view **sampler_views;
278    unsigned i, j;
279 
280    if (!vlCreateHTAB())
281       return VDP_STATUS_RESOURCES;
282 
283    vlVdpSurface *p_surf = vlGetDataHTAB(surface);
284    if (!p_surf)
285       return VDP_STATUS_INVALID_HANDLE;
286 
287    pipe = p_surf->device->context;
288    if (!pipe)
289       return VDP_STATUS_INVALID_HANDLE;
290 
291    pipe_mutex_lock(p_surf->device->mutex);
292    if (p_surf->video_buffer == NULL || pformat != p_surf->video_buffer->buffer_format) {
293 
294       /* destroy the old one */
295       if (p_surf->video_buffer)
296          p_surf->video_buffer->destroy(p_surf->video_buffer);
297 
298       /* adjust the template parameters */
299       p_surf->templat.buffer_format = pformat;
300 
301       /* and try to create the video buffer with the new format */
302       p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
303 
304       /* stil no luck? ok forget it we don't support it */
305       if (!p_surf->video_buffer) {
306          pipe_mutex_unlock(p_surf->device->mutex);
307          return VDP_STATUS_NO_IMPLEMENTATION;
308       }
309       vlVdpVideoSurfaceClear(p_surf);
310    }
311 
312    sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer);
313    if (!sampler_views) {
314       pipe_mutex_unlock(p_surf->device->mutex);
315       return VDP_STATUS_RESOURCES;
316    }
317 
318    for (i = 0; i < 3; ++i) {
319       unsigned width, height;
320       struct pipe_sampler_view *sv = sampler_views[i];
321       if (!sv || !source_pitches[i]) continue;
322 
323       vlVdpVideoSurfaceSize(p_surf, i, &width, &height);
324 
325       for (j = 0; j < sv->texture->depth0; ++j) {
326          struct pipe_box dst_box = {
327             0, 0, j,
328             width, height, 1
329          };
330 
331          pipe->transfer_inline_write(pipe, sv->texture, 0,
332                                      PIPE_TRANSFER_WRITE, &dst_box,
333                                      source_data[i] + source_pitches[i] * j,
334                                      source_pitches[i] * sv->texture->depth0,
335                                      0);
336       }
337    }
338    pipe_mutex_unlock(p_surf->device->mutex);
339 
340    return VDP_STATUS_OK;
341 }
342 
343 /**
344  * Helper function to initially clear the VideoSurface after (re-)creation
345  */
346 void
vlVdpVideoSurfaceClear(vlVdpSurface * vlsurf)347 vlVdpVideoSurfaceClear(vlVdpSurface *vlsurf)
348 {
349    struct pipe_context *pipe = vlsurf->device->context;
350    struct pipe_surface **surfaces;
351    unsigned i;
352 
353    if (!vlsurf->video_buffer)
354       return;
355 
356    surfaces = vlsurf->video_buffer->get_surfaces(vlsurf->video_buffer);
357    for (i = 0; i < VL_MAX_SURFACES; ++i) {
358       union pipe_color_union c = {};
359 
360       if (!surfaces[i])
361          continue;
362 
363       if (i > !!vlsurf->templat.interlaced)
364          c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
365 
366       pipe->clear_render_target(pipe, surfaces[i], &c, 0, 0,
367                                 surfaces[i]->width, surfaces[i]->height);
368    }
369    pipe->flush(pipe, NULL);
370 }
371