Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5563 serge 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 
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
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
   p_surf = CALLOC(1, sizeof(vlVdpSurface));
58
   if (!p_surf) {
59
      ret = VDP_STATUS_RESOURCES;
60
      goto no_res;
61
   }
62
 
63
   vlVdpDevice *dev = vlGetDataHTAB(device);
64
   if (!dev) {
65
      ret = VDP_STATUS_INVALID_HANDLE;
66
      goto inv_device;
67
   }
68
 
69
   p_surf->device = dev;
70
   pipe = dev->context;
71
 
72
   pipe_mutex_lock(dev->mutex);
73
   memset(&p_surf->templat, 0, sizeof(p_surf->templat));
74
   p_surf->templat.buffer_format = pipe->screen->get_video_param
75
   (
76
      pipe->screen,
77
      PIPE_VIDEO_PROFILE_UNKNOWN,
78
      PIPE_VIDEO_CAP_PREFERED_FORMAT
79
   );
80
   p_surf->templat.chroma_format = ChromaToPipe(chroma_type);
81
   p_surf->templat.width = width;
82
   p_surf->templat.height = height;
83
   p_surf->templat.interlaced = pipe->screen->get_video_param
84
   (
85
      pipe->screen,
86
      PIPE_VIDEO_PROFILE_UNKNOWN,
87
      PIPE_VIDEO_CAP_PREFERS_INTERLACED
88
   );
89
   p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
90
   vlVdpVideoSurfaceClear(p_surf);
91
   pipe_mutex_unlock(dev->mutex);
92
 
93
   *surface = vlAddDataHTAB(p_surf);
94
   if (*surface == 0) {
95
      ret = VDP_STATUS_ERROR;
96
      goto no_handle;
97
   }
98
 
99
   return VDP_STATUS_OK;
100
 
101
no_handle:
102
   p_surf->video_buffer->destroy(p_surf->video_buffer);
103
 
104
inv_device:
105
   FREE(p_surf);
106
 
107
no_res:
108
inv_size:
109
   return ret;
110
}
111
 
112
/**
113
 * Destroy a VdpVideoSurface.
114
 */
115
VdpStatus
116
vlVdpVideoSurfaceDestroy(VdpVideoSurface surface)
117
{
118
   vlVdpSurface *p_surf;
119
 
120
   p_surf = (vlVdpSurface *)vlGetDataHTAB((vlHandle)surface);
121
   if (!p_surf)
122
      return VDP_STATUS_INVALID_HANDLE;
123
 
124
   pipe_mutex_lock(p_surf->device->mutex);
125
   if (p_surf->video_buffer)
126
      p_surf->video_buffer->destroy(p_surf->video_buffer);
127
   pipe_mutex_unlock(p_surf->device->mutex);
128
 
129
   vlRemoveDataHTAB(surface);
130
   FREE(p_surf);
131
 
132
   return VDP_STATUS_OK;
133
}
134
 
135
/**
136
 * Retrieve the parameters used to create a VdpVideoSurface.
137
 */
138
VdpStatus
139
vlVdpVideoSurfaceGetParameters(VdpVideoSurface surface,
140
                               VdpChromaType *chroma_type,
141
                               uint32_t *width, uint32_t *height)
142
{
143
   if (!(width && height && chroma_type))
144
      return VDP_STATUS_INVALID_POINTER;
145
 
146
   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
147
   if (!p_surf)
148
      return VDP_STATUS_INVALID_HANDLE;
149
 
150
   if (p_surf->video_buffer) {
151
      *width = p_surf->video_buffer->width;
152
      *height = p_surf->video_buffer->height;
153
      *chroma_type = PipeToChroma(p_surf->video_buffer->chroma_format);
154
   } else {
155
      *width = p_surf->templat.width;
156
      *height = p_surf->templat.height;
157
      *chroma_type = PipeToChroma(p_surf->templat.chroma_format);
158
   }
159
 
160
   return VDP_STATUS_OK;
161
}
162
 
163
static void
164
vlVdpVideoSurfaceSize(vlVdpSurface *p_surf, int component,
165
                      unsigned *width, unsigned *height)
166
{
167
   *width = p_surf->templat.width;
168
   *height = p_surf->templat.height;
169
 
170
   if (component > 0) {
171
      if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
172
         *width /= 2;
173
         *height /= 2;
174
      } else if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
175
         *height /= 2;
176
      }
177
   }
178
   if (p_surf->templat.interlaced)
179
      *height /= 2;
180
}
181
 
182
/**
183
 * Copy image data from a VdpVideoSurface to application memory in a specified
184
 * YCbCr format.
185
 */
186
VdpStatus
187
vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface,
188
                              VdpYCbCrFormat destination_ycbcr_format,
189
                              void *const *destination_data,
190
                              uint32_t const *destination_pitches)
191
{
192
   vlVdpSurface *vlsurface;
193
   struct pipe_context *pipe;
194
   enum pipe_format format;
195
   struct pipe_sampler_view **sampler_views;
196
   unsigned i, j;
197
 
198
   vlsurface = vlGetDataHTAB(surface);
199
   if (!vlsurface)
200
      return VDP_STATUS_INVALID_HANDLE;
201
 
202
   pipe = vlsurface->device->context;
203
   if (!pipe)
204
      return VDP_STATUS_INVALID_HANDLE;
205
 
206
   format = FormatYCBCRToPipe(destination_ycbcr_format);
207
   if (format == PIPE_FORMAT_NONE)
208
       return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
209
 
210
   if (vlsurface->video_buffer == NULL || format != vlsurface->video_buffer->buffer_format)
211
      return VDP_STATUS_NO_IMPLEMENTATION; /* TODO We don't support conversion (yet) */
212
 
213
   pipe_mutex_lock(vlsurface->device->mutex);
214
   sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer);
215
   if (!sampler_views) {
216
      pipe_mutex_unlock(vlsurface->device->mutex);
217
      return VDP_STATUS_RESOURCES;
218
   }
219
 
220
   for (i = 0; i < 3; ++i) {
221
      unsigned width, height;
222
      struct pipe_sampler_view *sv = sampler_views[i];
223
      if (!sv) continue;
224
 
225
      vlVdpVideoSurfaceSize(vlsurface, i, &width, &height);
226
 
227
      for (j = 0; j < sv->texture->array_size; ++j) {
228
         struct pipe_box box = {
229
            0, 0, j,
230
            width, height, 1
231
         };
232
         struct pipe_transfer *transfer;
233
         uint8_t *map;
234
 
235
         map = pipe->transfer_map(pipe, sv->texture, 0,
236
                                       PIPE_TRANSFER_READ, &box, &transfer);
237
         if (!map) {
238
            pipe_mutex_unlock(vlsurface->device->mutex);
239
            return VDP_STATUS_RESOURCES;
240
         }
241
 
242
         util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format,
243
                        destination_pitches[i] * sv->texture->array_size, 0, 0,
244
                        box.width, box.height, map, transfer->stride, 0, 0);
245
 
246
         pipe_transfer_unmap(pipe, transfer);
247
      }
248
   }
249
   pipe_mutex_unlock(vlsurface->device->mutex);
250
 
251
   return VDP_STATUS_OK;
252
}
253
 
254
/**
255
 * Copy image data from application memory in a specific YCbCr format to
256
 * a VdpVideoSurface.
257
 */
258
VdpStatus
259
vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
260
                              VdpYCbCrFormat source_ycbcr_format,
261
                              void const *const *source_data,
262
                              uint32_t const *source_pitches)
263
{
264
   enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format);
265
   struct pipe_context *pipe;
266
   struct pipe_sampler_view **sampler_views;
267
   unsigned i, j;
268
 
269
   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
270
   if (!p_surf)
271
      return VDP_STATUS_INVALID_HANDLE;
272
 
273
   pipe = p_surf->device->context;
274
   if (!pipe)
275
      return VDP_STATUS_INVALID_HANDLE;
276
 
277
   pipe_mutex_lock(p_surf->device->mutex);
278
   if (p_surf->video_buffer == NULL || pformat != p_surf->video_buffer->buffer_format) {
279
 
280
      /* destroy the old one */
281
      if (p_surf->video_buffer)
282
         p_surf->video_buffer->destroy(p_surf->video_buffer);
283
 
284
      /* adjust the template parameters */
285
      p_surf->templat.buffer_format = pformat;
286
 
287
      /* and try to create the video buffer with the new format */
288
      p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
289
 
290
      /* stil no luck? ok forget it we don't support it */
291
      if (!p_surf->video_buffer) {
292
         pipe_mutex_unlock(p_surf->device->mutex);
293
         return VDP_STATUS_NO_IMPLEMENTATION;
294
      }
295
      vlVdpVideoSurfaceClear(p_surf);
296
   }
297
 
298
   sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer);
299
   if (!sampler_views) {
300
      pipe_mutex_unlock(p_surf->device->mutex);
301
      return VDP_STATUS_RESOURCES;
302
   }
303
 
304
   for (i = 0; i < 3; ++i) {
305
      unsigned width, height;
306
      struct pipe_sampler_view *sv = sampler_views[i];
307
      if (!sv || !source_pitches[i]) continue;
308
 
309
      vlVdpVideoSurfaceSize(p_surf, i, &width, &height);
310
 
311
      for (j = 0; j < sv->texture->array_size; ++j) {
312
         struct pipe_box dst_box = {
313
            0, 0, j,
314
            width, height, 1
315
         };
316
 
317
         pipe->transfer_inline_write(pipe, sv->texture, 0,
318
                                     PIPE_TRANSFER_WRITE, &dst_box,
319
                                     source_data[i] + source_pitches[i] * j,
320
                                     source_pitches[i] * sv->texture->array_size,
321
                                     0);
322
      }
323
   }
324
   pipe_mutex_unlock(p_surf->device->mutex);
325
 
326
   return VDP_STATUS_OK;
327
}
328
 
329
/**
330
 * Helper function to initially clear the VideoSurface after (re-)creation
331
 */
332
void
333
vlVdpVideoSurfaceClear(vlVdpSurface *vlsurf)
334
{
335
   struct pipe_context *pipe = vlsurf->device->context;
336
   struct pipe_surface **surfaces;
337
   unsigned i;
338
 
339
   if (!vlsurf->video_buffer)
340
      return;
341
 
342
   surfaces = vlsurf->video_buffer->get_surfaces(vlsurf->video_buffer);
343
   for (i = 0; i < VL_MAX_SURFACES; ++i) {
344
      union pipe_color_union c = {};
345
 
346
      if (!surfaces[i])
347
         continue;
348
 
349
      if (i > !!vlsurf->templat.interlaced)
350
         c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
351
 
352
      pipe->clear_render_target(pipe, surfaces[i], &c, 0, 0,
353
                                surfaces[i]->width, surfaces[i]->height);
354
   }
355
   pipe->flush(pipe, NULL, 0);
356
}