diff options
-rw-r--r-- | src/spu_dec/spudvb_decoder.c | 1 | ||||
-rw-r--r-- | src/video_out/video_out_vdpau.c | 567 |
2 files changed, 292 insertions, 276 deletions
diff --git a/src/spu_dec/spudvb_decoder.c b/src/spu_dec/spudvb_decoder.c index eb14fc540..518903e01 100644 --- a/src/spu_dec/spudvb_decoder.c +++ b/src/spu_dec/spudvb_decoder.c @@ -901,7 +901,6 @@ static void draw_subtitles (dvb_spu_decoder_t * this) for ( r=0; r<MAX_REGIONS; r++ ) { lprintf("region=%d, visible=%d, osd=%d, empty=%d\n", r, this->dvbsub->page.regions[r].is_visible, this->dvbsub->regions[r].osd?1:0, this->dvbsub->regions[r].empty ); if ( this->dvbsub->page.regions[r].is_visible && this->dvbsub->regions[r].osd && !this->dvbsub->regions[r].empty ) { - this->stream->osd_renderer->set_extent(this->dvbsub->regions[r].osd, SPU_MAX_WIDTH, SPU_MAX_HEIGHT); this->stream->osd_renderer->set_position( this->dvbsub->regions[r].osd, this->dvbsub->page.regions[r].x, this->dvbsub->page.regions[r].y ); this->stream->osd_renderer->show( this->dvbsub->regions[r].osd, this->vpts ); lprintf("show region = %d\n",r); diff --git a/src/video_out/video_out_vdpau.c b/src/video_out/video_out_vdpau.c index 7d92302c2..57ee478b0 100644 --- a/src/video_out/video_out_vdpau.c +++ b/src/video_out/video_out_vdpau.c @@ -187,31 +187,30 @@ static VdpDecoderCreate *orig_vdp_decoder_create; static VdpDecoderDestroy *orig_vdp_decoder_destroy; static VdpDecoderRender *orig_vdp_decoder_render; +#ifdef LOCKDISPLAY +#define DO_LOCKDISPLAY XLockDisplay(guarded_display); +#define DO_UNLOCKDISPLAY XUnlockDisplay(guarded_display); static Display *guarded_display; +#else +#define DO_LOCKDISPLAY +#define DO_UNLOCKDISPLAY +#endif static VdpStatus guarded_vdp_video_surface_putbits_ycbcr(VdpVideoSurface surface, VdpYCbCrFormat source_ycbcr_format, void const *const *source_data, uint32_t const *source_pitches) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_video_surface_putbits_ycbcr(surface, source_ycbcr_format, source_data, source_pitches); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } static VdpStatus guarded_vdp_video_surface_create(VdpDevice device, VdpChromaType chroma_type, uint32_t width, uint32_t height,VdpVideoSurface *surface) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_video_surface_create(device, chroma_type, width, height, surface); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } @@ -227,76 +226,63 @@ static VdpStatus guarded_vdp_video_surface_destroy(VdpVideoSurface surface) static VdpStatus guarded_vdp_output_surface_create(VdpDevice device, VdpChromaType chroma_type, uint32_t width, uint32_t height,VdpVideoSurface *surface) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_output_surface_create(device, chroma_type, width, height, surface); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } static VdpStatus guarded_vdp_output_surface_destroy(VdpVideoSurface surface) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_output_surface_destroy(surface); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } static VdpStatus guarded_vdp_decoder_create(VdpDevice device, VdpDecoderProfile profile, uint32_t width, uint32_t height, uint32_t max_references, VdpDecoder *decoder) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_decoder_create(device, profile, width, height, max_references, decoder); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } static VdpStatus guarded_vdp_decoder_destroy(VdpDecoder decoder) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_decoder_destroy(decoder); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } static VdpStatus guarded_vdp_decoder_render(VdpDecoder decoder, VdpVideoSurface target, VdpPictureInfo const *picture_info, uint32_t bitstream_buffer_count, VdpBitstreamBuffer const *bitstream_buffers) { VdpStatus r; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY r = orig_vdp_decoder_render(decoder, target, picture_info, bitstream_buffer_count, bitstream_buffers); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return r; } typedef struct { + VdpOutputSurface surface; + uint32_t width; + uint32_t height; + uint32_t size; +} vdpau_output_surface_t; + + +typedef struct { xine_grab_video_frame_t grab_frame; vo_driver_t *vo_driver; - VdpOutputSurface render_surface; - int vdp_runtime_nr; + vdpau_output_surface_t render_surface; int width, height; uint32_t *rgba; } vdpau_grab_video_frame_t; @@ -331,13 +317,12 @@ typedef struct { int extent_width; int extent_height; - int unscaled; /* true if it should be blended unscaled */ + int unscaled; /* true if it should be blended unscaled */ + int use_dirty_rect; /* true if update of dirty rect only is possible */ vo_overlay_t *ovl; - VdpOutputSurface render_surface; - uint32_t render_width; - uint32_t render_height; + vdpau_output_surface_t render_surface; } vdpau_overlay_t; @@ -350,12 +335,14 @@ typedef struct { int screen; Drawable drawable; pthread_mutex_t drawable_lock; + uint32_t display_width; + uint32_t display_height; config_values_t *config; int ovl_changed; int num_ovls; - int created_ovls; + int old_num_ovls; vdpau_overlay_t overlays[XINE_VORAW_MAX_OVL]; uint32_t *ovl_pixmap; int ovl_pixmap_size; @@ -363,20 +350,18 @@ typedef struct { VdpRect ovl_src_rect; VdpRect ovl_dest_rect; VdpRect ovl_video_dest_rect; - VdpOutputSurface ovl_output_surface; - uint32_t ovl_output_width; - uint32_t ovl_output_height; - int ovl_use_dirty_rect; - int ovl_last_argb_x; - int ovl_last_argb_y; - int ovl_last_argb_width; - int ovl_last_argb_height; + vdpau_output_surface_t ovl_main_render_surface; VdpVideoSurface soft_surface; uint32_t soft_surface_width; uint32_t soft_surface_height; int soft_surface_format; +#define NOUTPUTSURFACEBUFFER 25 + vdpau_output_surface_t output_surface_buffer[NOUTPUTSURFACEBUFFER]; + int output_surface_buffer_size; + int num_big_output_surfaces_created; + #define NOUTPUTSURFACE 8 VdpOutputSurface output_surface[NOUTPUTSURFACE]; uint8_t current_output_surface; @@ -449,19 +434,116 @@ typedef struct { +static VdpStatus vdpau_get_output_surface (vdpau_driver_t *this, uint32_t width, uint32_t height, vdpau_output_surface_t *r) +{ + int i, full = 1; + vdpau_output_surface_t *smallest = NULL, *best = NULL; + vdpau_output_surface_t *l = &this->output_surface_buffer[0]; + VdpStatus st = VDP_STATUS_OK; + + for (i = this->output_surface_buffer_size; i; --i, ++l) { + if (l->surface == VDP_INVALID_HANDLE) + full = 0; + else if ((l->width >= width && l->height >= height) && (best == NULL || l->size < best->size)) + best = l; + else if (smallest == NULL || l->size < smallest->size) + smallest = l; + } + + if (best != NULL) { + *r = *best; + best->surface = VDP_INVALID_HANDLE; + } else if (full) { + *r = *smallest; + smallest->surface = VDP_INVALID_HANDLE; + } else + r->surface = VDP_INVALID_HANDLE; + + if (r->surface != VDP_INVALID_HANDLE && (r->width < width || r->height < height)) { + lprintf("destroy output surface %d\n", (int)r->surface); + st = vdp_output_surface_destroy(r->surface); + if (st != VDP_STATUS_OK) + fprintf(stderr, "vdpau_get_output_surface: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st)); + r->surface = VDP_INVALID_HANDLE; + } + + if (r->surface == VDP_INVALID_HANDLE) { + if (this->num_big_output_surfaces_created < this->output_surface_buffer_size) { + /* We create big output surfaces which should fit for many output buffer requests as long + * as the reuse buffer can hold them */ + if (width < this->video_mixer_width) + width = this->video_mixer_width; + if (height < this->video_mixer_height) + height = this->video_mixer_height; + + if (width < this->display_width) + width = this->display_width; + if (height < this->display_height) + height = this->display_height; + + ++this->num_big_output_surfaces_created; + } + + st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, width, height, &r->surface); + if (st != VDP_STATUS_OK) + fprintf(stderr, "vdpau_get_output_surface: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st)); + r->width = width; + r->height = height; + r->size = width * height; + lprintf("create output surface %dx%d -> %d\n", (int)r->width, (int)r->height, (int)r->surface); + } + + return st; +} + + + +static void vdpau_free_output_surface (vdpau_driver_t *this, vdpau_output_surface_t *os) +{ + if (os->surface == VDP_INVALID_HANDLE) + return; + + vdpau_output_surface_t *smallest = NULL; + vdpau_output_surface_t *l = &this->output_surface_buffer[0]; + int i; + for (i = this->output_surface_buffer_size; i; --i, ++l) { + if (l->surface == VDP_INVALID_HANDLE) { + *l = *os; + os->surface = VDP_INVALID_HANDLE; + return; + } else if (smallest == NULL || l->size < smallest->size) + smallest = l; + } + + VdpOutputSurface surface; + if (smallest && smallest->size < os->size) { + surface = smallest->surface; + *smallest = *os; + } else + surface = os->surface; + + lprintf("destroy output surface %d\n", (int)surface); + VdpStatus st = vdp_output_surface_destroy (surface); + if (st != VDP_STATUS_OK) + fprintf(stderr, "vdpau_free_output_surface: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st)); + + os->surface = VDP_INVALID_HANDLE; +} + + static void vdpau_overlay_begin (vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed) { vdpau_driver_t *this = (vdpau_driver_t *) this_gen; this->ovl_changed = changed; if ( changed ) { + this->old_num_ovls = this->num_ovls; this->num_ovls = 0; lprintf("overlay begin\n"); } } - static void vdpau_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *voovl) { vdpau_driver_t *this = (vdpau_driver_t *) this_gen; @@ -477,21 +559,34 @@ static void vdpau_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, v return; if (voovl->rle) - lprintf("overlay[%d] rle %s%s %dx%d@%d,%d extend %dx%d hili rect %d,%d-%d,%d\n", i, + lprintf("overlay[%d] rle %s%s %dx%d@%d,%d extend %dx%d hili %d,%d-%d,%d video %dx%d@%d,%d\n", i, voovl->unscaled ? " unscaled ": " scaled ", (voovl->rgb_clut > 0 || voovl->hili_rgb_clut > 0) ? " rgb ": " ycbcr ", voovl->width, voovl->height, voovl->x, voovl->y, voovl->extent_width, voovl->extent_height, voovl->hili_left, voovl->hili_top, - voovl->hili_right, voovl->hili_bottom); + voovl->hili_right, voovl->hili_bottom, + voovl->video_window_width,voovl->video_window_height, + voovl->video_window_x,voovl->video_window_y); if (voovl->argb_layer && voovl->argb_layer->buffer) - lprintf("overlay[%d] argb %s %dx%d@%d,%d dirty rect %d,%d-%d,%d\n", i, + lprintf("overlay[%d] argb %s %dx%d@%d,%d dirty %d,%d-%d,%d video %dx%d@%d,%d\n", i, voovl->unscaled ? " unscaled ": " scaled ", voovl->width, voovl->height, voovl->x, voovl->y, voovl->argb_layer->x1, voovl->argb_layer->y1, - voovl->argb_layer->x2, voovl->argb_layer->y2); + voovl->argb_layer->x2, voovl->argb_layer->y2, + voovl->video_window_width,voovl->video_window_height, + voovl->video_window_x,voovl->video_window_y); vdpau_overlay_t *ovl = &this->overlays[i]; + + if (i >= this->old_num_ovls || + !ovl->use_dirty_rect || + ovl->render_surface.surface == VDP_INVALID_HANDLE || + voovl->rle || + ovl->x != voovl->x || ovl->y != voovl->y || + ovl->width != voovl->width || ovl->height != voovl->height) + ovl->use_dirty_rect = 0; + ovl->ovl = voovl; ovl->x = voovl->x; ovl->y = voovl->y; @@ -516,46 +611,31 @@ static void vdpau_overlay_end (vo_driver_t *this_gen, vo_frame_t *frame_gen) if (!this->ovl_changed) return; - int novls = this->num_ovls; - if (!novls) - this->ovl_use_dirty_rect = 0; - - VdpStatus st; int i; - for (i = 0; i < novls; ++i) { + for (i = 0; i < this->old_num_ovls; ++i) { vdpau_overlay_t *ovl = &this->overlays[i]; - vo_overlay_t *voovl = ovl->ovl; - - if (ovl->render_surface != VDP_INVALID_HANDLE && (ovl->render_width < ovl->width || ovl->render_height < ovl->height) ) { - lprintf("overlay[%d] destroy render surface\n", i); - st = vdp_output_surface_destroy( ovl->render_surface ); - if ( st != VDP_STATUS_OK ) - fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); - ovl->render_surface = VDP_INVALID_HANDLE; + if (!ovl->use_dirty_rect) { + lprintf("overlay[%d] free render surface %d\n", i, (int)ovl->render_surface.surface); + vdpau_free_output_surface(this, &ovl->render_surface); } + } + if (this->ovl_main_render_surface.surface != VDP_INVALID_HANDLE) { + lprintf("overlay free main render surface %d\n", (int)this->ovl_main_render_surface.surface); + vdpau_free_output_surface(this, &this->ovl_main_render_surface); + } - if (ovl->render_surface == VDP_INVALID_HANDLE ) { - this->ovl_use_dirty_rect = 0; + for (i = 0; i < this->num_ovls; ++i) { + vdpau_overlay_t *ovl = &this->overlays[i]; + vo_overlay_t *voovl = ovl->ovl; - ovl->render_width = ovl->width; - ovl->render_height = ovl->height; - if (i == 0) { - if (ovl->render_width < this->video_mixer_width) - ovl->render_width = this->video_mixer_width; - if (ovl->render_height < this->video_mixer_height) - ovl->render_height = this->video_mixer_height; - } - lprintf("overlay[%d] create render surface %dx%d\n", i, ovl->render_width, ovl->render_height); - st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, ovl->render_width, ovl->render_height, &ovl->render_surface ); - if ( st != VDP_STATUS_OK ) - fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); + if (!ovl->use_dirty_rect) { + vdpau_get_output_surface(this, ovl->width, ovl->height, &ovl->render_surface); + lprintf("overlay[%d] get render surface %dx%d -> %d\n", i, ovl->width, ovl->height, (int)ovl->render_surface.surface); } uint32_t *pixmap; int is_argb = 1; if (voovl->rle) { - this->ovl_use_dirty_rect = 0; - if ((ovl->width * ovl->height) > this->ovl_pixmap_size) { this->ovl_pixmap_size = ovl->width * ovl->height; free(this->ovl_pixmap); @@ -611,7 +691,7 @@ static void vdpau_overlay_end (vo_driver_t *this_gen, vo_frame_t *frame_gen) } VdpRect put_rect; - if (this->ovl_use_dirty_rect && ovl->x == this->ovl_last_argb_x && ovl->y == this->ovl_last_argb_y && ovl->width == this->ovl_last_argb_width && ovl->height == this->ovl_last_argb_height) { + if (ovl->use_dirty_rect) { put_rect.x0 = voovl->argb_layer->x1; put_rect.y0 = voovl->argb_layer->y1; put_rect.x1 = voovl->argb_layer->x2; @@ -623,47 +703,27 @@ static void vdpau_overlay_end (vo_driver_t *this_gen, vo_frame_t *frame_gen) put_rect.y1 = ovl->height; } + VdpStatus st; uint32_t pitch = ovl->width * sizeof(uint32_t); if (is_argb) { - lprintf("overlay[%d] put argb %d,%d:%d,%d\n", i, put_rect.x0, put_rect.y0, put_rect.x1, put_rect.y1); - st = vdp_output_surface_put_bits(ovl->render_surface, &pixmap, &pitch, &put_rect); + lprintf("overlay[%d] put %s %d,%d:%d,%d\n", i, ovl->use_dirty_rect ? "dirty argb": "argb", put_rect.x0, put_rect.y0, put_rect.x1, put_rect.y1); + st = vdp_output_surface_put_bits(ovl->render_surface.surface, &pixmap, &pitch, &put_rect); if ( st != VDP_STATUS_OK ) fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_put_bits_native failed : %s\n", vdp_get_error_string(st)); } else { lprintf("overlay[%d] put ycbcr %d,%d:%d,%d\n", i, put_rect.x0, put_rect.y0, put_rect.x1, put_rect.y1); - st = vdp_output_surface_put_bits_ycbcr(ovl->render_surface, VDP_YCBCR_FORMAT_V8U8Y8A8, &pixmap, &pitch, &put_rect, NULL); + st = vdp_output_surface_put_bits_ycbcr(ovl->render_surface.surface, VDP_YCBCR_FORMAT_V8U8Y8A8, &pixmap, &pitch, &put_rect, NULL); if ( st != VDP_STATUS_OK ) fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_put_bits_ycbcr failed : %s\n", vdp_get_error_string(st)); } - if (!voovl->rle) { + if (voovl->rle) + ovl->use_dirty_rect = 0; + else { pthread_mutex_unlock(&voovl->argb_layer->mutex); - if (novls == 1) { - this->ovl_last_argb_x = ovl->x; - this->ovl_last_argb_y = ovl->y; - this->ovl_last_argb_width = ovl->width; - this->ovl_last_argb_height = ovl->height; - this->ovl_use_dirty_rect = 1; - } - } - } - - if (novls > this->created_ovls) - this->created_ovls = novls; - - i = this->created_ovls; - while (i > 1 && i > novls) { - vdpau_overlay_t *ovl = &this->overlays[--i]; - - if (ovl->render_surface != VDP_INVALID_HANDLE) { - lprintf("overlay[%d] destroy render surface\n", i); - st = vdp_output_surface_destroy( ovl->render_surface ); - if ( st != VDP_STATUS_OK ) - fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); - ovl->render_surface = VDP_INVALID_HANDLE; + ovl->use_dirty_rect = 1; } } - this->created_ovls = i; } @@ -754,11 +814,11 @@ static void vdpau_process_overlays (vdpau_driver_t *this, vo_frame_t *frame) if (novls == 1) { this->ovl_src_rect.x1 = this->overlays[0].width; this->ovl_src_rect.y1 = this->overlays[0].height; - this->ovl_layer_surface = this->overlays[0].render_surface; + this->ovl_layer_surface = this->overlays[0].render_surface.surface; } else { this->ovl_src_rect.x1 = this->ovl_dest_rect.x1 - this->ovl_dest_rect.x0; this->ovl_src_rect.y1 = this->ovl_dest_rect.y1 - this->ovl_dest_rect.y0; - this->ovl_layer_surface = this->ovl_output_surface; + this->ovl_layer_surface = this->ovl_main_render_surface.surface; } lprintf("overlay output %dx%d -> %d,%d:%d,%d video window %d,%d:%d,%d\n", @@ -773,37 +833,21 @@ static void vdpau_process_overlays (vdpau_driver_t *this, vo_frame_t *frame) return; } - VdpStatus st; - - uint32_t output_width = this->ovl_src_rect.x1; - uint32_t output_height = this->ovl_src_rect.y1; - if (this->ovl_output_surface != VDP_INVALID_HANDLE && (this->ovl_output_width < output_width || this->ovl_output_height < output_height) ) { - lprintf("overlay destroy output surface\n"); - st = vdp_output_surface_destroy( this->ovl_output_surface ); - if ( st != VDP_STATUS_OK ) - fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); - this->ovl_output_surface = VDP_INVALID_HANDLE; + if (this->ovl_main_render_surface.surface != VDP_INVALID_HANDLE) { + lprintf("overlay free main render surface %d\n", (int)this->ovl_main_render_surface.surface); + vdpau_free_output_surface(this, &this->ovl_main_render_surface); } - if (this->ovl_output_surface == VDP_INVALID_HANDLE ) { - if (output_width < this->video_mixer_width) - output_width = this->video_mixer_width; - if (output_height < this->video_mixer_height) - output_height = this->video_mixer_height; - lprintf("overlay create output surface %dx%d\n", output_width, output_height); - st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, output_width, output_height, &this->ovl_output_surface ); - if ( st != VDP_STATUS_OK ) - fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); + vdpau_get_output_surface(this, this->ovl_src_rect.x1, this->ovl_src_rect.y1, &this->ovl_main_render_surface); + lprintf("overlay get main render surface %dx%d -> %d\n", this->ovl_src_rect.x1, this->ovl_src_rect.y1, (int)this->ovl_main_render_surface.surface); - this->ovl_output_width = output_width; - this->ovl_output_height = output_height; - } + this->ovl_layer_surface = this->ovl_main_render_surface.surface; - this->ovl_layer_surface = this->ovl_output_surface; + VdpStatus st; if (novls > 1 && (this->ovl_dest_rect.x0 != ovl_rects[0].x0 || this->ovl_dest_rect.x1 != ovl_rects[0].x1 || this->ovl_dest_rect.y0 != ovl_rects[0].y0 || this->ovl_dest_rect.y1 != ovl_rects[0].y1)) { - if (output_width > this->ovl_pixmap_size) { - this->ovl_pixmap_size = output_width; + if (this->ovl_src_rect.x1 > this->ovl_pixmap_size) { + this->ovl_pixmap_size = this->ovl_src_rect.x1; free(this->ovl_pixmap); this->ovl_pixmap = calloc(this->ovl_pixmap_size, sizeof(uint32_t)); } else { @@ -833,7 +877,7 @@ static void vdpau_process_overlays (vdpau_driver_t *this, vo_frame_t *frame) lprintf("overlay[%d] render %dx%d -> %d,%d:%d,%d\n", i, src_rect.x1, src_rect.y1, render_rect.x0, render_rect.y0, render_rect.x1, render_rect.y1); VdpOutputSurfaceRenderBlendState *bs = (i > 0) ? &blend: NULL; - st = vdp_output_surface_render_output_surface(this->ovl_layer_surface, &render_rect, ovl->render_surface, &src_rect, 0, bs, 0 ); + st = vdp_output_surface_render_output_surface(this->ovl_layer_surface, &render_rect, ovl->render_surface.surface, &src_rect, 0, bs, 0 ); if ( st != VDP_STATUS_OK ) fprintf(stderr, "vdpau_process_overlays: vdp_output_surface_render_output_surface failed : %s\n", vdp_get_error_string(st)); } @@ -1583,8 +1627,13 @@ static void vdpau_check_output_size( vo_driver_t *this_gen ) this->output_surface_width[this->current_output_surface] = this->sc.gui_width; this->output_surface_height[this->current_output_surface] = this->sc.gui_height; - vdp_output_surface_destroy( this->output_surface[this->current_output_surface] ); - vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[this->current_output_surface], this->output_surface_height[this->current_output_surface], &this->output_surface[this->current_output_surface] ); + VdpStatus st = vdp_output_surface_destroy( this->output_surface[this->current_output_surface] ); + if (st != VDP_STATUS_OK) + fprintf(stderr, "vo_vdpau: Can't destroy output surface: %s\n", vdp_get_error_string (st)); + + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[this->current_output_surface], this->output_surface_height[this->current_output_surface], &this->output_surface[this->current_output_surface] ); + if (st != VDP_STATUS_OK) + fprintf(stderr, "vo_vdpau: Can't create output surface: %s\n", vdp_get_error_string (st)); } } @@ -1601,8 +1650,8 @@ static void vdpau_grab_current_output_surface (vdpau_driver_t *this, int64_t vpt frame->grab_frame.vpts = -1; VdpOutputSurface grab_surface = this->output_surface[this->current_output_surface]; - int width = this->output_surface_width[this->current_output_surface]; - int height = this->output_surface_height[this->current_output_surface]; + int width = this->sc.gui_width; + int height = this->sc.gui_height; /* take cropping parameters into account */ width = width - frame->grab_frame.crop_left - frame->grab_frame.crop_right; @@ -1618,26 +1667,12 @@ static void vdpau_grab_current_output_surface (vdpau_driver_t *this, int64_t vpt if (frame->grab_frame.height <= 0) frame->grab_frame.height = height; - if (frame->vdp_runtime_nr != this->vdp_runtime_nr) - frame->render_surface = VDP_INVALID_HANDLE; - if (frame->grab_frame.width != frame->width || frame->grab_frame.height != frame->height) { free(frame->rgba); free(frame->grab_frame.img); frame->rgba = NULL; frame->grab_frame.img = NULL; - if (frame->render_surface != VDP_INVALID_HANDLE) { - st = vdp_output_surface_destroy(frame->render_surface); - frame->render_surface = VDP_INVALID_HANDLE; - if (st != VDP_STATUS_OK) { - fprintf(stderr, "vo_vdpau: Can't destroy grab render output surface: %s\n", vdp_get_error_string (st)); - pthread_cond_broadcast(&this->grab_cond); - pthread_mutex_unlock(&this->grab_lock); - return; - } - } - frame->width = frame->grab_frame.width; frame->height = frame->grab_frame.height; } @@ -1650,6 +1685,7 @@ static void vdpau_grab_current_output_surface (vdpau_driver_t *this, int64_t vpt return; } } + if (frame->grab_frame.img == NULL) { frame->grab_frame.img = (uint8_t *) calloc(frame->width * frame->height, 3); if (frame->grab_frame.img == NULL) { @@ -1661,30 +1697,22 @@ static void vdpau_grab_current_output_surface (vdpau_driver_t *this, int64_t vpt uint32_t pitches = frame->width * sizeof(uint32_t); VdpRect src_rect = { frame->grab_frame.crop_left, frame->grab_frame.crop_top, width+frame->grab_frame.crop_left, height+frame->grab_frame.crop_top }; - if (frame->width != width || frame->height != height) { - st = VDP_STATUS_OK; - if (frame->render_surface == VDP_INVALID_HANDLE) { - frame->vdp_runtime_nr = this->vdp_runtime_nr; - st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, frame->width, frame->height, &frame->render_surface); - } + st = vdpau_get_output_surface(this, frame->width, frame->height, &frame->render_surface); if (st == VDP_STATUS_OK) { - st = vdp_output_surface_render_output_surface(frame->render_surface, NULL, grab_surface, &src_rect, NULL, NULL, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); + lprintf("grab got render output surface %dx%d -> %d\n", frame->width, frame->height, (int)frame->render_surface.surface); + + VdpRect dst_rect = { 0, 0, frame->width, frame->height }; + st = vdp_output_surface_render_output_surface(frame->render_surface.surface, &dst_rect, grab_surface, &src_rect, NULL, NULL, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); if (st == VDP_STATUS_OK) { - st = vdp_output_surface_get_bits(frame->render_surface, NULL, &frame->rgba, &pitches); - if (st == VDP_STATUS_OK) { - if (!(frame->grab_frame.flags & XINE_GRAB_VIDEO_FRAME_FLAGS_CONTINUOUS)) { - st = vdp_output_surface_destroy(frame->render_surface); - if (st != VDP_STATUS_OK) - fprintf(stderr, "vo_vdpau: Can't destroy grab render output surface: %s\n", vdp_get_error_string (st)); - frame->render_surface = VDP_INVALID_HANDLE; - } - } else + st = vdp_output_surface_get_bits(frame->render_surface.surface, &dst_rect, &frame->rgba, &pitches); + if (st != VDP_STATUS_OK) fprintf(stderr, "vo_vdpau: Can't get output surface bits for raw frame grabbing: %s\n", vdp_get_error_string (st)); } else fprintf(stderr, "vo_vdpau: Can't render output surface for raw frame grabbing: %s\n", vdp_get_error_string (st)); - } else - fprintf(stderr, "vo_vdpau: Can't create render output surface for raw frame grabbing: %s\n", vdp_get_error_string (st)); + + vdpau_free_output_surface(this, &frame->render_surface); + } } else { st = vdp_output_surface_get_bits(grab_surface, &src_rect, &frame->rgba, &pitches); if (st != VDP_STATUS_OK) @@ -1891,9 +1919,7 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) if ( this->init_queue>1 ) vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time ); -#ifdef LOCKDISPLAY - XLockDisplay( this->display ); -#endif + DO_LOCKDISPLAY vdpau_check_output_size( this_gen ); @@ -1914,7 +1940,7 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) vdpau_grab_current_output_surface( this, frame->vo_frame.vpts ); vdp_queue_get_time( vdp_queue, ¤t_time ); - vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, 0 ); /* display _now_ */ + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], this->sc.gui_width, this->sc.gui_height, 0 ); /* display _now_ */ vdpau_shift_queue( this_gen ); int dm; @@ -1925,13 +1951,9 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) if ( (dm != DEINT_HALF_TEMPORAL) && (dm != DEINT_HALF_TEMPORAL_SPATIAL) && frame->vo_frame.future_frame ) { /* process second field */ if ( this->init_queue >= this->queue_length ) { -#ifdef LOCKDISPLAY - XUnlockDisplay(this->display); -#endif + DO_UNLOCKDISPLAY vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time ); -#ifdef LOCKDISPLAY - XLockDisplay(this->display); -#endif + DO_LOCKDISPLAY } vdpau_check_output_size( this_gen ); @@ -1951,7 +1973,7 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) if ( stream_speed > 0 ) current_time += frame->vo_frame.duration * 1000000ull * XINE_FINE_SPEED_NORMAL / (180 * stream_speed); - vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, current_time ); + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], this->sc.gui_width, this->sc.gui_height, current_time ); vdpau_shift_queue( this_gen ); } } @@ -1964,13 +1986,11 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) fprintf(stderr, "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); vdpau_grab_current_output_surface( this, frame->vo_frame.vpts ); - vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, 0 ); + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], this->sc.gui_width, this->sc.gui_height, 0 ); vdpau_shift_queue( this_gen ); } -#ifdef LOCKDISPLAY - XUnlockDisplay( this->display ); -#endif + DO_UNLOCKDISPLAY if ( stream_speed ) vdpau_backup_frame( this_gen, frame_gen ); @@ -2099,19 +2119,13 @@ static void vdpau_get_property_min_max (vo_driver_t *this_gen, int property, int static void vdpau_dispose_grab_video_frame(xine_grab_video_frame_t *frame_gen) { vdpau_grab_video_frame_t *frame = (vdpau_grab_video_frame_t *) frame_gen; - vdpau_driver_t *this = (vdpau_driver_t *) frame->vo_driver; free(frame->grab_frame.img); free(frame->rgba); - if (frame->render_surface != VDP_INVALID_HANDLE && frame->vdp_runtime_nr == this->vdp_runtime_nr) { - VdpStatus st; - st = vdp_output_surface_destroy(frame->render_surface); - if (st != VDP_STATUS_OK) - fprintf(stderr, "vo_vdpau: Can't destroy grab render output surface: %s\n", vdp_get_error_string (st) ); - } free(frame); } + /* * grab next displayed output surface. * Note: This feature only supports grabbing of next displayed frame (implicit VO_GRAB_FRAME_FLAGS_WAIT_NEXT) @@ -2182,7 +2196,7 @@ static xine_grab_video_frame_t * vdpau_new_grab_video_frame(vo_driver_t *this) frame->grab_frame.vpts = -1; frame->grab_frame.timeout = XINE_GRAB_VIDEO_FRAME_DEFAULT_TIMEOUT; frame->vo_driver = this; - frame->render_surface = VDP_INVALID_HANDLE; + frame->render_surface.surface = VDP_INVALID_HANDLE; } return (xine_grab_video_frame_t *) frame; @@ -2202,18 +2216,14 @@ static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void * case XINE_GUI_SEND_EXPOSE_EVENT: { if ( this->init_queue ) { pthread_mutex_lock(&this->drawable_lock); /* wait for other thread which is currently displaying */ -#ifdef LOCKDISPLAY - XLockDisplay( this->display ); -#endif + DO_LOCKDISPLAY int previous; if ( this->current_output_surface ) previous = this->current_output_surface - 1; else previous = this->queue_length - 1; vdp_queue_display( vdp_queue, this->output_surface[previous], 0, 0, 0 ); -#ifdef LOCKDISPLAY - XUnlockDisplay( this->display ); -#endif + DO_UNLOCKDISPLAY pthread_mutex_unlock(&this->drawable_lock); } break; @@ -2222,34 +2232,26 @@ static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void * case XINE_GUI_SEND_DRAWABLE_CHANGED: { VdpStatus st; pthread_mutex_lock(&this->drawable_lock); /* wait for other thread which is currently displaying */ -#ifdef LOCKDISPLAY - XLockDisplay( this->display ); -#endif + DO_LOCKDISPLAY this->drawable = (Drawable) data; vdp_queue_destroy( vdp_queue ); vdp_queue_target_destroy( vdp_queue_target ); st = vdp_queue_target_create_x11( vdp_device, this->drawable, &vdp_queue_target ); if ( st != VDP_STATUS_OK ) { fprintf(stderr, "vo_vdpau: FATAL !! Can't recreate presentation queue target after drawable change !!\n" ); -#ifdef LOCKDISPLAY - XUnlockDisplay( this->display ); -#endif + DO_UNLOCKDISPLAY pthread_mutex_unlock(&this->drawable_lock); break; } st = vdp_queue_create( vdp_device, vdp_queue_target, &vdp_queue ); if ( st != VDP_STATUS_OK ) { fprintf(stderr, "vo_vdpau: FATAL !! Can't recreate presentation queue after drawable change !!\n" ); -#ifdef LOCKDISPLAY - XUnlockDisplay( this->display ); -#endif + DO_UNLOCKDISPLAY pthread_mutex_unlock(&this->drawable_lock); break; } vdp_queue_set_background_color( vdp_queue, &this->back_color ); -#ifdef LOCKDISPLAY - XUnlockDisplay( this->display ); -#endif + DO_UNLOCKDISPLAY pthread_mutex_unlock(&this->drawable_lock); this->sc.force_redraw = 1; break; @@ -2304,17 +2306,21 @@ static void vdpau_dispose (vo_driver_t *this_gen) vdp_video_surface_destroy( this->soft_surface ); if ( vdp_output_surface_destroy ) { - if (this->ovl_output_surface != VDP_INVALID_HANDLE) - vdp_output_surface_destroy( this->ovl_output_surface ); - for (i = 0; i < this->created_ovls; ++i) { + if (this->ovl_main_render_surface.surface != VDP_INVALID_HANDLE) + vdp_output_surface_destroy( this->ovl_main_render_surface.surface ); + for (i = 0; i < this->num_ovls; ++i) { vdpau_overlay_t *ovl = &this->overlays[i]; - if (ovl->render_surface != VDP_INVALID_HANDLE) - vdp_output_surface_destroy( ovl->render_surface ); + if (ovl->render_surface.surface != VDP_INVALID_HANDLE) + vdp_output_surface_destroy( ovl->render_surface.surface ); } for ( i=0; i<this->queue_length; ++i ) { - if ( this->output_surface[i]!=VDP_INVALID_HANDLE ) + if ( this->output_surface[i] != VDP_INVALID_HANDLE ) vdp_output_surface_destroy( this->output_surface[i] ); } + for ( i=0; i<this->output_surface_buffer_size; ++i ) { + if ( this->output_surface_buffer[i].surface != VDP_INVALID_HANDLE ) + vdp_output_surface_destroy( this->output_surface_buffer[i].surface ); + } } for ( i=0; i<NUM_FRAMES_BACK; i++ ) @@ -2333,6 +2339,18 @@ static void vdpau_dispose (vo_driver_t *this_gen) +static void vdpau_update_display_dimension (vdpau_driver_t *this) +{ + XLockDisplay (this->display); + + this->display_width = DisplayWidth(this->display, this->screen); + this->display_height = DisplayHeight(this->display, this->screen); + + XUnlockDisplay(this->display); +} + + + static int vdpau_reinit_error( VdpStatus st, const char *msg ) { if ( st != VDP_STATUS_OK ) { @@ -2349,9 +2367,7 @@ static void vdpau_reinit( vo_driver_t *this_gen ) fprintf(stderr,"vo_vdpau: VDPAU was pre-empted. Reinit.\n"); vdpau_driver_t *this = (vdpau_driver_t *)this_gen; -#ifdef LOCKDISPLAY - XLockDisplay(guarded_display); -#endif + DO_LOCKDISPLAY vdpau_release_back_frames(this_gen); VdpStatus st = vdp_device_create_x11( this->display, this->screen, &vdp_device, &vdp_get_proc_address ); @@ -2362,25 +2378,18 @@ static void vdpau_reinit( vo_driver_t *this_gen ) fprintf(stderr, "No vdpau implementation.\n" ); else fprintf(stderr, "unsupported GPU?\n" ); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return; } st = vdp_queue_target_create_x11( vdp_device, this->drawable, &vdp_queue_target ); if ( vdpau_reinit_error( st, "Can't create presentation queue target !!" ) ) { -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif - + DO_UNLOCKDISPLAY return; } st = vdp_queue_create( vdp_device, vdp_queue_target, &vdp_queue ); if ( vdpau_reinit_error( st, "Can't create presentation queue !!" ) ) { -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return; } vdp_queue_set_background_color( vdp_queue, &this->back_color ); @@ -2389,35 +2398,37 @@ static void vdpau_reinit( vo_driver_t *this_gen ) VdpChromaType chroma = VDP_CHROMA_TYPE_420; st = orig_vdp_video_surface_create( vdp_device, chroma, this->soft_surface_width, this->soft_surface_height, &this->soft_surface ); if ( vdpau_reinit_error( st, "Can't create video surface !!" ) ) { -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return; } + vdpau_update_display_dimension(this); this->current_output_surface = 0; this->init_queue = 0; int i; for ( i=0; i<this->queue_length; ++i ) { + this->output_surface_width[i] = this->display_width; + this->output_surface_height[i] = this->display_height; st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[i], this->output_surface_height[i], &this->output_surface[i] ); if ( vdpau_reinit_error( st, "Can't create output surface !!" ) ) { int j; for ( j=0; j<i; ++j ) vdp_output_surface_destroy( this->output_surface[j] ); vdp_video_surface_destroy( this->soft_surface ); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return; } } + this->num_big_output_surfaces_created = 0; + for (i = 0; i < this->output_surface_buffer_size; ++i) + this->output_surface_buffer[i].surface = VDP_INVALID_HANDLE; + this->ovl_layer_surface = VDP_INVALID_HANDLE; - this->ovl_output_surface = VDP_INVALID_HANDLE; - for (i = 0; i < this->created_ovls; ++i) - this->overlays[i].render_surface = VDP_INVALID_HANDLE; + this->ovl_main_render_surface.surface = VDP_INVALID_HANDLE; + for (i = 0; i < this->num_ovls; ++i) + this->overlays[i].render_surface.surface = VDP_INVALID_HANDLE; this->num_ovls = 0; - this->created_ovls = 0; this->ovl_changed = 1; VdpVideoMixerFeature features[15]; @@ -2456,9 +2467,7 @@ static void vdpau_reinit( vo_driver_t *this_gen ) orig_vdp_video_surface_destroy( this->soft_surface ); for ( i=0; i<this->queue_length; ++i ) vdp_output_surface_destroy( this->output_surface[i] ); -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY return; } this->video_mixer_chroma = chroma; @@ -2475,9 +2484,7 @@ static void vdpau_reinit( vo_driver_t *this_gen ) this->vdp_runtime_nr++; this->reinit_needed = 0; -#ifdef LOCKDISPLAY - XUnlockDisplay(guarded_display); -#endif + DO_UNLOCKDISPLAY fprintf(stderr,"vo_vdpau: Reinit done.\n"); } @@ -2520,7 +2527,10 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo if (!this) return NULL; +#ifdef LOCKDISPLAY guarded_display = visual->display; +#endif + this->display = visual->display; this->screen = visual->screen; this->drawable = visual->d; @@ -2576,20 +2586,14 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo this->ovl_changed = 0; this->num_ovls = 0; - this->created_ovls = 0; + this->old_num_ovls = 0; this->ovl_layer_surface = VDP_INVALID_HANDLE; - this->ovl_output_width = 0; - this->ovl_output_height = 0; - this->ovl_output_surface = VDP_INVALID_HANDLE; + this->ovl_main_render_surface.surface = VDP_INVALID_HANDLE; this->ovl_pixmap = NULL; this->ovl_pixmap_size = 0; - this->ovl_use_dirty_rect = 0; this->ovl_src_rect.x0 = 0; this->ovl_src_rect.y0 = 0; - for (i = 0; i < XINE_VORAW_MAX_OVL; ++i) - this->overlays[i].render_surface = VDP_INVALID_HANDLE; - VdpStatus st = vdp_device_create_x11( visual->display, visual->screen, &vdp_device, &vdp_get_proc_address ); if ( st != VDP_STATUS_OK ) { fprintf(stderr, "vo_vdpau: Can't create vdp device : " ); @@ -2832,6 +2836,22 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo if ( vdpau_init_error( st, "Can't create video surface !!", &this->vo_driver, 1 ) ) return NULL; + this->output_surface_buffer_size = config->register_num (config, "video.output.vdpau_output_surface_buffer_size", 10, /* default */ + _("maximum number of output surfaces buffered for reuse"), + _("The maximum number of video output surfaces buffered for reuse"), + 20, NULL, this); + if (this->output_surface_buffer_size < 2) + this->output_surface_buffer_size = 2; + if (this->output_surface_buffer_size > NOUTPUTSURFACEBUFFER) + this->output_surface_buffer_size = NOUTPUTSURFACEBUFFER; + fprintf(stderr, "vo_vdpau: hold a maximum of %d video output surfaces for reuse\n", this->output_surface_buffer_size); + + this->num_big_output_surfaces_created = 0; + for (i = 0; i < this->output_surface_buffer_size; ++i) + this->output_surface_buffer[i].surface = VDP_INVALID_HANDLE; + + vdpau_update_display_dimension(this); + this->queue_length = config->register_num (config, "video.output.vdpau_display_queue_length", 3, /* default */ _("default length of display queue"), _("The default number of video output surfaces to create for the display queue"), @@ -2840,16 +2860,13 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo this->queue_length = 2; if (this->queue_length > NOUTPUTSURFACE) this->queue_length = NOUTPUTSURFACE; - fprintf(stderr, "vo_vdpau: using %d output surfaces for display queue\n", this->queue_length); + fprintf(stderr, "vo_vdpau: using %d output surfaces of size %dx%d for display queue\n", this->queue_length, this->display_width, this->display_height); - for ( i=0; i<this->queue_length; ++i ) { - this->output_surface_width[i] = 320; - this->output_surface_height[i] = 240; - } this->current_output_surface = 0; this->init_queue = 0; - for ( i=0; i<this->queue_length; ++i ) { + this->output_surface_width[i] = this->display_width; + this->output_surface_height[i] = this->display_height; st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[i], this->output_surface_height[i], &this->output_surface[i] ); if ( vdpau_init_error( st, "Can't create output surface !!", &this->vo_driver, 1 ) ) { int j; |