1 #include "xorg_tracker.h"
4 #include <X11/extensions/Xv.h>
8 #include "xorg_renderer.h"
9 #include "xorg_exa_tgsi.h"
11 #include "cso_cache/cso_context.h"
12 #include "util/u_sampler.h"
14 #include "pipe/p_screen.h"
16 /*XXX get these from pipe's texture limits */
17 #define IMAGE_MAX_WIDTH 2048
18 #define IMAGE_MAX_HEIGHT 2048
20 #define RES_720P_X 1280
21 #define RES_720P_Y 720
24 /* The ITU-R BT.601 conversion matrix for SDTV. */
25 /* original, matrix, but we transpose it to
26 * make the shader easier
27 static const float bt_601[] = {
29 1.0, -0.3455, -0.7169, 0,
32 static const float bt_601
[] = {
34 0.0, -0.3455, 1.7790, 0,
35 1.4075, -0.7169, 0., 0,
38 /* The ITU-R BT.709 conversion matrix for HDTV. */
39 /* original, but we transpose to make the conversion
40 * in the shader easier
41 static const float bt_709[] = {
43 1.0, -0.1881, -0.47, 0,
46 static const float bt_709
[] = {
48 0.0, -0.1881, 1.8629, 0,
52 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
54 static Atom xvBrightness
, xvContrast
;
56 #define NUM_TEXTURED_ATTRIBUTES 2
57 static XF86AttributeRec TexturedAttributes
[NUM_TEXTURED_ATTRIBUTES
] = {
58 {XvSettable
| XvGettable
, -128, 127, "XV_BRIGHTNESS"},
59 {XvSettable
| XvGettable
, 0, 255, "XV_CONTRAST"}
63 static XF86VideoFormatRec Formats
[NUM_FORMATS
] = {
64 {15, TrueColor
}, {16, TrueColor
}, {24, TrueColor
}
67 static XF86VideoEncodingRec DummyEncoding
[1] = {
71 IMAGE_MAX_WIDTH
, IMAGE_MAX_HEIGHT
,
77 static XF86ImageRec Images
[NUM_IMAGES
] = {
83 struct xorg_xv_port_priv
{
84 struct xorg_renderer
*r
;
92 /* juggle two sets of seperate Y, U and V
94 struct pipe_texture
*yuv
[2][3];
95 struct pipe_sampler_view
*yuv_views
[2][3];
100 stop_video(ScrnInfoPtr pScrn
, pointer data
, Bool shutdown
)
102 struct xorg_xv_port_priv
*priv
= (struct xorg_xv_port_priv
*)data
;
104 REGION_EMPTY(pScrn
->pScreen
, &priv
->clip
);
108 set_port_attribute(ScrnInfoPtr pScrn
,
109 Atom attribute
, INT32 value
, pointer data
)
111 struct xorg_xv_port_priv
*priv
= (struct xorg_xv_port_priv
*)data
;
113 if (attribute
== xvBrightness
) {
114 if ((value
< -128) || (value
> 127))
116 priv
->brightness
= value
;
117 } else if (attribute
== xvContrast
) {
118 if ((value
< 0) || (value
> 255))
120 priv
->contrast
= value
;
128 get_port_attribute(ScrnInfoPtr pScrn
,
129 Atom attribute
, INT32
* value
, pointer data
)
131 struct xorg_xv_port_priv
*priv
= (struct xorg_xv_port_priv
*)data
;
133 if (attribute
== xvBrightness
)
134 *value
= priv
->brightness
;
135 else if (attribute
== xvContrast
)
136 *value
= priv
->contrast
;
144 query_best_size(ScrnInfoPtr pScrn
,
146 short vid_w
, short vid_h
,
147 short drw_w
, short drw_h
,
148 unsigned int *p_w
, unsigned int *p_h
, pointer data
)
150 if (vid_w
> (drw_w
<< 1))
152 if (vid_h
> (drw_h
<< 1))
159 static INLINE
struct pipe_texture
*
160 create_component_texture(struct pipe_context
*pipe
,
161 int width
, int height
)
163 struct pipe_screen
*screen
= pipe
->screen
;
164 struct pipe_texture
*tex
= 0;
165 struct pipe_texture templ
;
167 memset(&templ
, 0, sizeof(templ
));
168 templ
.target
= PIPE_TEXTURE_2D
;
169 templ
.format
= PIPE_FORMAT_L8_UNORM
;
170 templ
.last_level
= 0;
171 templ
.width0
= width
;
172 templ
.height0
= height
;
174 templ
.tex_usage
= PIPE_TEXTURE_USAGE_SAMPLER
;
176 tex
= screen
->texture_create(screen
, &templ
);
182 check_yuv_textures(struct xorg_xv_port_priv
*priv
, int width
, int height
)
184 struct pipe_texture
**dst
= priv
->yuv
[priv
->current_set
];
185 struct pipe_sampler_view
**dst_view
= priv
->yuv_views
[priv
->current_set
];
186 struct pipe_sampler_view view_templ
;
187 struct pipe_context
*pipe
= priv
->r
->pipe
;
190 dst
[0]->width0
!= width
||
191 dst
[0]->height0
!= height
) {
192 pipe_texture_reference(&dst
[0], NULL
);
193 pipe_sampler_view_reference(&dst_view
[0], NULL
);
196 dst
[1]->width0
!= width
||
197 dst
[1]->height0
!= height
) {
198 pipe_texture_reference(&dst
[1], NULL
);
199 pipe_sampler_view_reference(&dst_view
[1], NULL
);
202 dst
[2]->width0
!= width
||
203 dst
[2]->height0
!= height
) {
204 pipe_texture_reference(&dst
[2], NULL
);
205 pipe_sampler_view_reference(&dst_view
[2], NULL
);
209 dst
[0] = create_component_texture(priv
->r
->pipe
, width
, height
);
211 u_sampler_view_default_template(&view_templ
,
214 dst_view
[0] = pipe
->create_sampler_view(pipe
, dst
[0], &view_templ
);
219 dst
[1] = create_component_texture(priv
->r
->pipe
, width
, height
);
221 u_sampler_view_default_template(&view_templ
,
224 dst_view
[1] = pipe
->create_sampler_view(pipe
, dst
[1], &view_templ
);
229 dst
[2] = create_component_texture(priv
->r
->pipe
, width
, height
);
231 u_sampler_view_default_template(&view_templ
,
234 dst_view
[2] = pipe
->create_sampler_view(pipe
, dst
[2], &view_templ
);
238 if (!dst
[0] || !dst
[1] || !dst
[2] || !dst_view
[0] || !dst_view
[1] || !dst_view
[2] )
245 query_image_attributes(ScrnInfoPtr pScrn
,
247 unsigned short *w
, unsigned short *h
,
248 int *pitches
, int *offsets
)
252 if (*w
> IMAGE_MAX_WIDTH
)
253 *w
= IMAGE_MAX_WIDTH
;
254 if (*h
> IMAGE_MAX_HEIGHT
)
255 *h
= IMAGE_MAX_HEIGHT
;
264 size
= (*w
+ 3) & ~3;
272 tmp
= ((*w
>> 1) + 3) & ~3;
274 pitches
[1] = pitches
[2] = tmp
;
297 copy_packed_data(ScrnInfoPtr pScrn
,
298 struct xorg_xv_port_priv
*port
,
303 unsigned short w
, unsigned short h
)
306 struct pipe_texture
**dst
= port
->yuv
[port
->current_set
];
307 struct pipe_transfer
*ytrans
, *utrans
, *vtrans
;
308 struct pipe_context
*pipe
= port
->r
->pipe
;
309 char *ymap
, *vmap
, *umap
;
310 unsigned char y1
, y2
, u
, v
;
311 int yidx
, uidx
, vidx
;
312 int y_array_size
= w
* h
;
314 ytrans
= pipe
->get_tex_transfer(pipe
, dst
[0],
318 utrans
= pipe
->get_tex_transfer(pipe
, dst
[1],
322 vtrans
= pipe
->get_tex_transfer(pipe
, dst
[2],
327 ymap
= (char*)pipe
->transfer_map(pipe
, ytrans
);
328 umap
= (char*)pipe
->transfer_map(pipe
, utrans
);
329 vmap
= (char*)pipe
->transfer_map(pipe
, vtrans
);
331 yidx
= uidx
= vidx
= 0;
335 int pitches
[3], offsets
[3];
336 unsigned char *y
, *u
, *v
;
337 query_image_attributes(pScrn
, FOURCC_YV12
,
338 &w
, &h
, pitches
, offsets
);
340 y
= buf
+ offsets
[0];
341 v
= buf
+ offsets
[1];
342 u
= buf
+ offsets
[2];
343 for (i
= 0; i
< h
; ++i
) {
344 for (j
= 0; j
< w
; ++j
) {
345 int yoffset
= (w
*i
+j
);
346 int ii
= (i
|1), jj
= (j
|1);
347 int vuoffset
= (w
/2)*(ii
/2) + (jj
/2);
348 ymap
[yidx
++] = y
[yoffset
];
349 umap
[uidx
++] = u
[vuoffset
];
350 vmap
[vidx
++] = v
[vuoffset
];
356 for (i
= 0; i
< y_array_size
; i
+=2 ) {
357 /* extracting two pixels */
373 for (i
= 0; i
< y_array_size
; i
+=2 ) {
374 /* extracting two pixels */
391 debug_assert(!"Unsupported yuv format!");
395 pipe
->transfer_unmap(pipe
, ytrans
);
396 pipe
->transfer_unmap(pipe
, utrans
);
397 pipe
->transfer_unmap(pipe
, vtrans
);
398 pipe
->tex_transfer_destroy(pipe
, ytrans
);
399 pipe
->tex_transfer_destroy(pipe
, utrans
);
400 pipe
->tex_transfer_destroy(pipe
, vtrans
);
405 setup_fs_video_constants(struct xorg_renderer
*r
, boolean hdtv
)
407 const int param_bytes
= 12 * sizeof(float);
408 const float *video_constants
= (hdtv
) ? bt_709
: bt_601
;
410 renderer_set_constants(r
, PIPE_SHADER_FRAGMENT
,
411 video_constants
, param_bytes
);
415 draw_yuv(struct xorg_xv_port_priv
*port
,
416 int src_x
, int src_y
, int src_w
, int src_h
,
417 int dst_x
, int dst_y
, int dst_w
, int dst_h
)
419 struct pipe_texture
**textures
= port
->yuv
[port
->current_set
];
421 /*debug_printf(" draw_yuv([%d, %d, %d ,%d], [%d, %d, %d, %d])\n",
422 src_x, src_y, src_w, src_h,
423 dst_x, dst_y, dst_w, dst_h);*/
424 renderer_draw_yuv(port
->r
,
425 src_x
, src_y
, src_w
, src_h
,
426 dst_x
, dst_y
, dst_w
, dst_h
,
431 bind_blend_state(struct xorg_xv_port_priv
*port
)
433 struct pipe_blend_state blend
;
435 memset(&blend
, 0, sizeof(struct pipe_blend_state
));
436 blend
.rt
[0].blend_enable
= 0;
437 blend
.rt
[0].colormask
= PIPE_MASK_RGBA
;
439 /* porter&duff src */
440 blend
.rt
[0].rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
441 blend
.rt
[0].alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
442 blend
.rt
[0].rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
443 blend
.rt
[0].alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
445 cso_set_blend(port
->r
->cso
, &blend
);
450 bind_shaders(struct xorg_xv_port_priv
*port
)
452 unsigned vs_traits
= 0, fs_traits
= 0;
453 struct xorg_shader shader
;
458 shader
= xorg_shaders_get(port
->r
->shaders
, vs_traits
, fs_traits
);
459 cso_set_vertex_shader_handle(port
->r
->cso
, shader
.vs
);
460 cso_set_fragment_shader_handle(port
->r
->cso
, shader
.fs
);
464 conditional_flush(struct pipe_context
*pipe
, struct pipe_texture
**tex
,
468 for (i
= 0; i
< num
; ++i
) {
469 if (tex
[i
] && pipe
->is_texture_referenced(pipe
, tex
[i
], 0, 0) &
470 PIPE_REFERENCED_FOR_WRITE
) {
471 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
478 bind_samplers(struct xorg_xv_port_priv
*port
)
480 struct pipe_sampler_state
*samplers
[PIPE_MAX_SAMPLERS
];
481 struct pipe_sampler_state sampler
;
482 struct pipe_texture
**dst
= port
->yuv
[port
->current_set
];
483 struct pipe_sampler_view
**dst_views
= port
->yuv_views
[port
->current_set
];
485 memset(&sampler
, 0, sizeof(struct pipe_sampler_state
));
487 conditional_flush(port
->r
->pipe
, dst
, 3);
489 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP
;
490 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP
;
491 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
492 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
493 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
494 sampler
.normalized_coords
= 1;
496 samplers
[0] = &sampler
;
497 samplers
[1] = &sampler
;
498 samplers
[2] = &sampler
;
501 cso_set_samplers(port
->r
->cso
, 3,
502 (const struct pipe_sampler_state
**)samplers
);
503 cso_set_fragment_sampler_views(port
->r
->cso
, 3, dst_views
);
507 display_video(ScrnInfoPtr pScrn
, struct xorg_xv_port_priv
*pPriv
, int id
,
509 int src_x
, int src_y
, int src_w
, int src_h
,
510 int dstX
, int dstY
, int dst_w
, int dst_h
,
513 modesettingPtr ms
= modesettingPTR(pScrn
);
519 struct exa_pixmap_priv
*dst
;
520 struct pipe_surface
*dst_surf
= NULL
;
522 exaMoveInPixmap(pPixmap
);
523 dst
= exaGetPixmapDriverPrivate(pPixmap
);
525 /*debug_printf("display_video([%d, %d, %d, %d], [%d, %d, %d, %d])\n",
526 src_x, src_y, src_w, src_h, dstX, dstY, dst_w, dst_h);*/
528 if (dst
&& !dst
->tex
) {
529 xorg_exa_set_shared_usage(pPixmap
);
530 pScrn
->pScreen
->ModifyPixmapHeader(pPixmap
, 0, 0, 0, 0, 0, NULL
);
533 if (!dst
|| !dst
->tex
)
534 XORG_FALLBACK("Xv destination %s", !dst
? "!dst" : "!dst->tex");
536 dst_surf
= xorg_gpu_surface(pPriv
->r
->pipe
->screen
, dst
);
537 hdtv
= ((src_w
>= RES_720P_X
) && (src_h
>= RES_720P_Y
));
539 REGION_TRANSLATE(pScrn
->pScreen
, dstRegion
, -pPixmap
->screen_x
,
542 dxo
= dstRegion
->extents
.x1
;
543 dyo
= dstRegion
->extents
.y1
;
545 pbox
= REGION_RECTS(dstRegion
);
546 nbox
= REGION_NUM_RECTS(dstRegion
);
548 renderer_bind_destination(pPriv
->r
, dst_surf
,
549 dst_surf
->width
, dst_surf
->height
);
551 bind_blend_state(pPriv
);
553 bind_samplers(pPriv
);
554 setup_fs_video_constants(pPriv
->r
, hdtv
);
556 DamageDamageRegion(&pPixmap
->drawable
, dstRegion
);
559 int box_x1
= pbox
->x1
;
560 int box_y1
= pbox
->y1
;
561 int box_x2
= pbox
->x2
;
562 int box_y2
= pbox
->y2
;
563 float diff_x
= (float)src_w
/ (float)dst_w
;
564 float diff_y
= (float)src_h
/ (float)dst_h
;
565 int offset_x
= box_x1
- dstX
+ pPixmap
->screen_x
;
566 int offset_y
= box_y1
- dstY
+ pPixmap
->screen_y
;
575 offset_w
= dst_w
- w
;
576 offset_h
= dst_h
- h
;
579 src_x
+ offset_x
*diff_x
, src_y
+ offset_y
*diff_y
,
580 src_w
- offset_w
*diff_x
, src_h
- offset_h
*diff_y
,
585 DamageRegionProcessPending(&pPixmap
->drawable
);
587 pipe_surface_reference(&dst_surf
, NULL
);
593 put_image(ScrnInfoPtr pScrn
,
594 short src_x
, short src_y
,
595 short drw_x
, short drw_y
,
596 short src_w
, short src_h
,
597 short drw_w
, short drw_h
,
598 int id
, unsigned char *buf
,
599 short width
, short height
,
600 Bool sync
, RegionPtr clipBoxes
, pointer data
,
603 struct xorg_xv_port_priv
*pPriv
= (struct xorg_xv_port_priv
*) data
;
604 ScreenPtr pScreen
= screenInfo
.screens
[pScrn
->scrnIndex
];
606 INT32 x1
, x2
, y1
, y2
;
617 dstBox
.x2
= drw_x
+ drw_w
;
619 dstBox
.y2
= drw_y
+ drw_h
;
621 if (!xf86XVClipVideoHelper(&dstBox
, &x1
, &x2
, &y1
, &y2
, clipBoxes
,
625 ret
= check_yuv_textures(pPriv
, width
, height
);
630 copy_packed_data(pScrn
, pPriv
, id
, buf
,
631 src_x
, src_y
, width
, height
);
633 if (pDraw
->type
== DRAWABLE_WINDOW
) {
634 pPixmap
= (*pScreen
->GetWindowPixmap
)((WindowPtr
)pDraw
);
636 pPixmap
= (PixmapPtr
)pDraw
;
639 display_video(pScrn
, pPriv
, id
, clipBoxes
,
640 src_x
, src_y
, src_w
, src_h
,
642 drw_w
, drw_h
, pPixmap
);
644 pPriv
->current_set
= (pPriv
->current_set
+ 1) & 1;
648 static struct xorg_xv_port_priv
*
649 port_priv_create(struct xorg_renderer
*r
)
651 struct xorg_xv_port_priv
*priv
= NULL
;
653 priv
= calloc(1, sizeof(struct xorg_xv_port_priv
));
660 REGION_NULL(pScreen
, &priv
->clip
);
662 debug_assert(priv
&& priv
->r
);
667 static XF86VideoAdaptorPtr
668 xorg_setup_textured_adapter(ScreenPtr pScreen
)
670 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
671 modesettingPtr ms
= modesettingPTR(pScrn
);
672 XF86VideoAdaptorPtr adapt
;
673 XF86AttributePtr attrs
;
674 DevUnion
*dev_unions
;
678 nattributes
= NUM_TEXTURED_ATTRIBUTES
;
680 debug_assert(ms
->exa
);
681 debug_assert(ms
->exa
->renderer
);
683 adapt
= calloc(1, sizeof(XF86VideoAdaptorRec
));
684 dev_unions
= calloc(nports
, sizeof(DevUnion
));
685 attrs
= calloc(nattributes
, sizeof(XF86AttributeRec
));
686 if (adapt
== NULL
|| dev_unions
== NULL
|| attrs
== NULL
) {
693 adapt
->type
= XvWindowMask
| XvInputMask
| XvImageMask
;
695 adapt
->name
= "Gallium3D Textured Video";
696 adapt
->nEncodings
= 1;
697 adapt
->pEncodings
= DummyEncoding
;
698 adapt
->nFormats
= NUM_FORMATS
;
699 adapt
->pFormats
= Formats
;
701 adapt
->pPortPrivates
= dev_unions
;
702 adapt
->nAttributes
= nattributes
;
703 adapt
->pAttributes
= attrs
;
704 memcpy(attrs
, TexturedAttributes
, nattributes
* sizeof(XF86AttributeRec
));
705 adapt
->nImages
= NUM_IMAGES
;
706 adapt
->pImages
= Images
;
707 adapt
->PutVideo
= NULL
;
708 adapt
->PutStill
= NULL
;
709 adapt
->GetVideo
= NULL
;
710 adapt
->GetStill
= NULL
;
711 adapt
->StopVideo
= stop_video
;
712 adapt
->SetPortAttribute
= set_port_attribute
;
713 adapt
->GetPortAttribute
= get_port_attribute
;
714 adapt
->QueryBestSize
= query_best_size
;
715 adapt
->PutImage
= put_image
;
716 adapt
->QueryImageAttributes
= query_image_attributes
;
718 for (i
= 0; i
< nports
; i
++) {
719 struct xorg_xv_port_priv
*priv
=
720 port_priv_create(ms
->exa
->renderer
);
722 adapt
->pPortPrivates
[i
].ptr
= (pointer
) (priv
);
730 xorg_xv_init(ScreenPtr pScreen
)
732 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
733 /*modesettingPtr ms = modesettingPTR(pScrn);*/
734 XF86VideoAdaptorPtr
*adaptors
, *new_adaptors
= NULL
;
735 XF86VideoAdaptorPtr textured_adapter
;
738 num_adaptors
= xf86XVListGenericAdaptors(pScrn
, &adaptors
);
739 new_adaptors
= malloc((num_adaptors
+ 1) * sizeof(XF86VideoAdaptorPtr
*));
740 if (new_adaptors
== NULL
)
743 memcpy(new_adaptors
, adaptors
, num_adaptors
* sizeof(XF86VideoAdaptorPtr
));
744 adaptors
= new_adaptors
;
746 /* Add the adaptors supported by our hardware. First, set up the atoms
747 * that will be used by both output adaptors.
749 xvBrightness
= MAKE_ATOM("XV_BRIGHTNESS");
750 xvContrast
= MAKE_ATOM("XV_CONTRAST");
752 textured_adapter
= xorg_setup_textured_adapter(pScreen
);
754 debug_assert(textured_adapter
);
756 if (textured_adapter
) {
757 adaptors
[num_adaptors
++] = textured_adapter
;
761 xf86XVScreenInit(pScreen
, adaptors
, num_adaptors
);
763 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
764 "Disabling Xv because no adaptors could be initialized.\n");