presentation.c revision 736dda82ca5477b8976e2c6b810a71efe2337267
1/************************************************************************** 2 * 3 * Copyright 2010 Thomas Balling Sørensen. 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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 <stdio.h> 29#include <time.h> 30#include <sys/timeb.h> 31 32#include <vdpau/vdpau.h> 33 34#include "util/u_debug.h" 35#include "util/u_memory.h" 36 37#include "vdpau_private.h" 38 39/** 40 * Create a VdpPresentationQueue. 41 */ 42VdpStatus 43vlVdpPresentationQueueCreate(VdpDevice device, 44 VdpPresentationQueueTarget presentation_queue_target, 45 VdpPresentationQueue *presentation_queue) 46{ 47 vlVdpPresentationQueue *pq = NULL; 48 VdpStatus ret; 49 50 if (!presentation_queue) 51 return VDP_STATUS_INVALID_POINTER; 52 53 vlVdpDevice *dev = vlGetDataHTAB(device); 54 if (!dev) 55 return VDP_STATUS_INVALID_HANDLE; 56 57 vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target); 58 if (!pqt) 59 return VDP_STATUS_INVALID_HANDLE; 60 61 if (dev != pqt->device) 62 return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 63 64 pq = CALLOC(1, sizeof(vlVdpPresentationQueue)); 65 if (!pq) 66 return VDP_STATUS_RESOURCES; 67 68 pq->device = dev; 69 pq->drawable = pqt->drawable; 70 71 if (!vl_compositor_init(&pq->compositor, dev->context->pipe)) { 72 ret = VDP_STATUS_ERROR; 73 goto no_compositor; 74 } 75 76 vl_compositor_reset_dirty_area(&pq->dirty_area); 77 78 *presentation_queue = vlAddDataHTAB(pq); 79 if (*presentation_queue == 0) { 80 ret = VDP_STATUS_ERROR; 81 goto no_handle; 82 } 83 84 return VDP_STATUS_OK; 85 86no_handle: 87no_compositor: 88 FREE(pq); 89 return ret; 90} 91 92/** 93 * Destroy a VdpPresentationQueue. 94 */ 95VdpStatus 96vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue) 97{ 98 vlVdpPresentationQueue *pq; 99 100 pq = vlGetDataHTAB(presentation_queue); 101 if (!pq) 102 return VDP_STATUS_INVALID_HANDLE; 103 104 vl_compositor_cleanup(&pq->compositor); 105 106 vlRemoveDataHTAB(presentation_queue); 107 FREE(pq); 108 109 return VDP_STATUS_OK; 110} 111 112/** 113 * Configure the background color setting. 114 */ 115VdpStatus 116vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue, 117 VdpColor *const background_color) 118{ 119 vlVdpPresentationQueue *pq; 120 union pipe_color_union color; 121 122 if (!background_color) 123 return VDP_STATUS_INVALID_POINTER; 124 125 pq = vlGetDataHTAB(presentation_queue); 126 if (!pq) 127 return VDP_STATUS_INVALID_HANDLE; 128 129 color.f[0] = background_color->red; 130 color.f[1] = background_color->green; 131 color.f[2] = background_color->blue; 132 color.f[3] = background_color->alpha; 133 134 vl_compositor_set_clear_color(&pq->compositor, &color); 135 136 return VDP_STATUS_OK; 137} 138 139/** 140 * Retrieve the current background color setting. 141 */ 142VdpStatus 143vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue, 144 VdpColor *const background_color) 145{ 146 vlVdpPresentationQueue *pq; 147 union pipe_color_union color; 148 149 if (!background_color) 150 return VDP_STATUS_INVALID_POINTER; 151 152 pq = vlGetDataHTAB(presentation_queue); 153 if (!pq) 154 return VDP_STATUS_INVALID_HANDLE; 155 156 vl_compositor_get_clear_color(&pq->compositor, &color); 157 158 background_color->red = color.f[0]; 159 background_color->green = color.f[1]; 160 background_color->blue = color.f[2]; 161 background_color->alpha = color.f[3]; 162 163 return VDP_STATUS_OK; 164} 165 166/** 167 * Retrieve the presentation queue's "current" time. 168 */ 169VdpStatus 170vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue, 171 VdpTime *current_time) 172{ 173 vlVdpPresentationQueue *pq; 174 struct timespec ts; 175 176 if (!current_time) 177 return VDP_STATUS_INVALID_POINTER; 178 179 pq = vlGetDataHTAB(presentation_queue); 180 if (!pq) 181 return VDP_STATUS_INVALID_HANDLE; 182 183 clock_gettime(CLOCK_REALTIME, &ts); 184 *current_time = (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec; 185 186 return VDP_STATUS_OK; 187} 188 189/** 190 * Enter a surface into the presentation queue. 191 */ 192VdpStatus 193vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, 194 VdpOutputSurface surface, 195 uint32_t clip_width, 196 uint32_t clip_height, 197 VdpTime earliest_presentation_time) 198{ 199 static int dump_window = -1; 200 201 vlVdpPresentationQueue *pq; 202 vlVdpOutputSurface *surf; 203 204 struct pipe_context *pipe; 205 struct pipe_surface *drawable_surface; 206 struct pipe_video_rect src_rect, dst_clip; 207 208 pq = vlGetDataHTAB(presentation_queue); 209 if (!pq) 210 return VDP_STATUS_INVALID_HANDLE; 211 212 drawable_surface = vl_drawable_surface_get(pq->device->context, pq->drawable); 213 if (!drawable_surface) 214 return VDP_STATUS_INVALID_HANDLE; 215 216 surf = vlGetDataHTAB(surface); 217 if (!surf) 218 return VDP_STATUS_INVALID_HANDLE; 219 220 surf->timestamp = (vlVdpTime)earliest_presentation_time; 221 222 src_rect.x = 0; 223 src_rect.y = 0; 224 src_rect.w = drawable_surface->width; 225 src_rect.h = drawable_surface->height; 226 227 dst_clip.x = 0; 228 dst_clip.y = 0; 229 dst_clip.w = clip_width ? clip_width : drawable_surface->width; 230 dst_clip.h = clip_height ? clip_height : drawable_surface->height; 231 232 vl_compositor_clear_layers(&pq->compositor); 233 vl_compositor_set_rgba_layer(&pq->compositor, 0, surf->sampler_view, &src_rect, NULL); 234 vl_compositor_render(&pq->compositor, drawable_surface, NULL, &dst_clip, &pq->dirty_area); 235 236 pipe = pq->device->context->pipe; 237 238 pipe->screen->flush_frontbuffer 239 ( 240 pipe->screen, 241 drawable_surface->texture, 242 0, 0, 243 vl_contextprivate_get(pq->device->context, drawable_surface) 244 ); 245 246 pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL); 247 pipe->flush(pipe, &surf->fence); 248 249 if (dump_window == -1) { 250 dump_window = debug_get_num_option("VDPAU_DUMP", 0); 251 } 252 253 if (dump_window) { 254 static unsigned int framenum = 0; 255 char cmd[256]; 256 257 sprintf(cmd, "xwd -id %d -out vdpau_frame_%08d.xwd", (int)pq->drawable, ++framenum); 258 if (system(cmd) != 0) 259 VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface); 260 } 261 262 pipe_surface_reference(&drawable_surface, NULL); 263 264 return VDP_STATUS_OK; 265} 266 267/** 268 * Wait for a surface to finish being displayed. 269 */ 270VdpStatus 271vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue, 272 VdpOutputSurface surface, 273 VdpTime *first_presentation_time) 274{ 275 vlVdpPresentationQueue *pq; 276 vlVdpOutputSurface *surf; 277 struct pipe_screen *screen; 278 279 if (!first_presentation_time) 280 return VDP_STATUS_INVALID_POINTER; 281 282 pq = vlGetDataHTAB(presentation_queue); 283 if (!pq) 284 return VDP_STATUS_INVALID_HANDLE; 285 286 surf = vlGetDataHTAB(surface); 287 if (!surf) 288 return VDP_STATUS_INVALID_HANDLE; 289 290 if (surf->fence) { 291 screen = pq->device->context->pipe->screen; 292 screen->fence_finish(screen, surf->fence, 0); 293 } 294 295 // We actually need to query the timestamp of the last VSYNC event from the hardware 296 vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); 297 298 return VDP_STATUS_OK; 299} 300 301/** 302 * Poll the current queue status of a surface. 303 */ 304VdpStatus 305vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue, 306 VdpOutputSurface surface, 307 VdpPresentationQueueStatus *status, 308 VdpTime *first_presentation_time) 309{ 310 vlVdpPresentationQueue *pq; 311 vlVdpOutputSurface *surf; 312 struct pipe_screen *screen; 313 314 if (!(status && first_presentation_time)) 315 return VDP_STATUS_INVALID_POINTER; 316 317 pq = vlGetDataHTAB(presentation_queue); 318 if (!pq) 319 return VDP_STATUS_INVALID_HANDLE; 320 321 surf = vlGetDataHTAB(surface); 322 if (!surf) 323 return VDP_STATUS_INVALID_HANDLE; 324 325 *first_presentation_time = 0; 326 327 if (!surf->fence) { 328 *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; 329 } else { 330 screen = pq->device->context->pipe->screen; 331 if (screen->fence_signalled(screen, surf->fence)) { 332 screen->fence_reference(screen, &surf->fence, NULL); 333 *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; 334 335 // We actually need to query the timestamp of the last VSYNC event from the hardware 336 vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); 337 *first_presentation_time += 1; 338 } else { 339 *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED; 340 } 341 } 342 343 return VDP_STATUS_OK; 344} 345