1 /************************************************************************** 2 * 3 * Copyright 2010 Thomas Balling Srensen. 4 * Copyright 2011 Christian Knig. 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 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 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 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 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 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 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 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