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