diff options
Diffstat (limited to 'src/gallium/state_trackers/xorg/xorg_xv.c')
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_xv.c | 522 |
1 files changed, 511 insertions, 11 deletions
diff --git a/src/gallium/state_trackers/xorg/xorg_xv.c b/src/gallium/state_trackers/xorg/xorg_xv.c index 88955d47fd..c3d9454245 100644 --- a/src/gallium/state_trackers/xorg/xorg_xv.c +++ b/src/gallium/state_trackers/xorg/xorg_xv.c @@ -4,10 +4,51 @@ #include <X11/extensions/Xv.h> #include <fourcc.h> +#include "xorg_exa.h" +#include "xorg_renderer.h" +#include "xorg_exa_tgsi.h" + +#include "cso_cache/cso_context.h" + +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" + /*XXX get these from pipe's texture limits */ #define IMAGE_MAX_WIDTH 2048 #define IMAGE_MAX_HEIGHT 2048 +#define RES_720P_X 1280 +#define RES_720P_Y 720 + + +/* The ITU-R BT.601 conversion matrix for SDTV. */ +/* original, matrix, but we transpose it to + * make the shader easier +static const float bt_601[] = { + 1.0, 0.0, 1.4075, , + 1.0, -0.3455, -0.7169, 0, + 1.0, 1.7790, 0., 0, +};*/ +static const float bt_601[] = { + 1.0, 1.0, 1.0, 0.5, + 0.0, -0.3455, 1.7790, 0, + 1.4075, -0.7169, 0., 0, +}; + +/* The ITU-R BT.709 conversion matrix for HDTV. */ +/* original, but we transpose to make the conversion + * in the shader easier +static const float bt_709[] = { + 1.0, 0.0, 1.581, 0, + 1.0, -0.1881, -0.47, 0, + 1.0, 1.8629, 0., 0, +};*/ +static const float bt_709[] = { + 1.0, 1.0, 1.0, 0.5, + 0.0, -0.1881, 1.8629, 0, + 1.581,-0.47 , 0.0, 0, +}; + #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) static Atom xvBrightness, xvContrast; @@ -39,27 +80,62 @@ static XF86ImageRec Images[NUM_IMAGES] = { }; struct xorg_xv_port_priv { + struct xorg_renderer *r; + RegionRec clip; + + int brightness; + int contrast; + + int current_set; + /* juggle two sets of seperate Y, U and V + * textures */ + struct pipe_texture *yuv[2][3]; }; static void stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) { + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + REGION_EMPTY(pScrn->pScreen, &priv->clip); } static int set_port_attribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data) { - return 0; + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) { + if ((value < -128) || (value > 127)) + return BadValue; + priv->brightness = value; + } else if (attribute == xvContrast) { + if ((value < 0) || (value > 255)) + return BadValue; + priv->contrast = value; + } else + return BadMatch; + + return Success; } static int get_port_attribute(ScrnInfoPtr pScrn, Atom attribute, INT32 * value, pointer data) { - return 0; + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) + *value = priv->brightness; + else if (attribute == xvContrast) + *value = priv->contrast; + else + return BadMatch; + + return Success; } static void @@ -69,6 +145,352 @@ query_best_size(ScrnInfoPtr pScrn, short drw_w, short drw_h, unsigned int *p_w, unsigned int *p_h, pointer data) { + if (vid_w > (drw_w << 1)) + drw_w = vid_w >> 1; + if (vid_h > (drw_h << 1)) + drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + +static INLINE struct pipe_texture * +create_component_texture(struct pipe_context *pipe, + int width, int height) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_texture *tex = 0; + struct pipe_texture templ; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = PIPE_FORMAT_L8_UNORM; + templ.last_level = 0; + templ.width[0] = width; + templ.height[0] = height; + templ.depth[0] = 1; + pf_get_block(PIPE_FORMAT_L8_UNORM, &templ.block); + templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; + + tex = screen->texture_create(screen, &templ); + + return tex; +} + +static int +check_yuv_textures(struct xorg_xv_port_priv *priv, int width, int height) +{ + struct pipe_texture **dst = priv->yuv[priv->current_set]; + if (!dst[0] || + dst[0]->width[0] != width || + dst[0]->height[0] != height) { + pipe_texture_reference(&dst[0], NULL); + } + if (!dst[1] || + dst[1]->width[0] != width || + dst[1]->height[0] != height) { + pipe_texture_reference(&dst[1], NULL); + } + if (!dst[2] || + dst[2]->width[0] != width || + dst[2]->height[0] != height) { + pipe_texture_reference(&dst[2], NULL); + } + + if (!dst[0]) + dst[0] = create_component_texture(priv->r->pipe, width, height); + + if (!dst[1]) + dst[1] = create_component_texture(priv->r->pipe, width, height); + + if (!dst[2]) + dst[2] = create_component_texture(priv->r->pipe, width, height); + + if (!dst[0] || !dst[1] || !dst[2]) + return BadAlloc; + + return Success; +} + +static void +copy_packed_data(ScrnInfoPtr pScrn, + struct xorg_xv_port_priv *port, + int id, + unsigned char *buf, + int srcPitch, + int left, + int top, + int w, int h) +{ + unsigned char *src; + int i, j; + struct pipe_texture **dst = port->yuv[port->current_set]; + struct pipe_transfer *ytrans, *utrans, *vtrans; + struct pipe_screen *screen = port->r->pipe->screen; + char *ymap, *vmap, *umap; + unsigned char y1, y2, u, v; + int yidx, uidx, vidx; + int y_array_size = w * h; + + src = buf + (top * srcPitch) + (left << 1); + + ytrans = screen->get_tex_transfer(screen, dst[0], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + utrans = screen->get_tex_transfer(screen, dst[1], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + vtrans = screen->get_tex_transfer(screen, dst[2], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + + ymap = (char*)screen->transfer_map(screen, ytrans); + umap = (char*)screen->transfer_map(screen, utrans); + vmap = (char*)screen->transfer_map(screen, vtrans); + + yidx = uidx = vidx = 0; + + switch (id) { + case FOURCC_YV12: { + for (i = 0; i < w; ++i) { + for (j = 0; i < h; ++j) { + /*XXX use src? */ + y1 = buf[j*w + i]; + u = buf[(j/2) * (w/2) + i/2 + y_array_size]; + v = buf[(j/2) * (w/2) + i/2 + y_array_size + y_array_size/4]; + ymap[yidx++] = y1; + umap[uidx++] = u; + vmap[vidx++] = v; + } + } + } + break; + case FOURCC_UYVY: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + u = buf[0]; + y1 = buf[1]; + v = buf[2]; + y2 = buf[3]; + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + umap[uidx++] = u; + vmap[vidx++] = v; + vmap[vidx++] = v; + } + break; + case FOURCC_YUY2: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + y1 = buf[0]; + u = buf[1]; + y2 = buf[2]; + v = buf[3]; + + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + umap[uidx++] = u; + vmap[vidx++] = v; + vmap[vidx++] = v; + } + break; + default: + debug_assert(!"Unsupported yuv format!"); + break; + } + + screen->transfer_unmap(screen, ytrans); + screen->transfer_unmap(screen, utrans); + screen->transfer_unmap(screen, vtrans); + screen->tex_transfer_destroy(ytrans); + screen->tex_transfer_destroy(utrans); + screen->tex_transfer_destroy(vtrans); +} + + +static void +setup_vs_video_constants(struct xorg_renderer *r, struct exa_pixmap_priv *dst) +{ + int width = dst->tex->width[0]; + int height = dst->tex->height[0]; + const int param_bytes = 8 * sizeof(float); + float vs_consts[8] = { + 2.f/width, 2.f/height, 1, 1, + -1, -1, 0, 0 + }; + + renderer_set_constants(r, PIPE_SHADER_VERTEX, + vs_consts, param_bytes); +} + +static void +setup_fs_video_constants(struct xorg_renderer *r, boolean hdtv) +{ + const int param_bytes = 12 * sizeof(float); + const float *video_constants = (hdtv) ? bt_709 : bt_601; + + renderer_set_constants(r, PIPE_SHADER_FRAGMENT, + video_constants, param_bytes); +} + +static void +draw_yuv(struct xorg_xv_port_priv *port, int src_x, int src_y, + int dst_x, int dst_y, + int w, int h) +{ + int pos[4] = {src_x, src_y, + dst_x, dst_y}; + struct pipe_texture **textures = port->yuv[port->current_set]; + + renderer_draw_textures(port->r, + pos, w, h, + textures, + 3, /*bound samplers/textures */ + NULL, NULL /* no transformations */); +} + +static void +bind_blend_state(struct xorg_xv_port_priv *port) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.blend_enable = 1; + blend.colormask |= PIPE_MASK_RGBA; + + /* porter&duff src */ + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + + cso_set_blend(port->r->cso, &blend); +} + + +static void +bind_shaders(struct xorg_xv_port_priv *port) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xorg_shader shader; + + vs_traits |= VS_YUV; + fs_traits |= FS_YUV; + + shader = xorg_shaders_get(port->r->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(port->r->cso, shader.vs); + cso_set_fragment_shader_handle(port->r->cso, shader.fs); +} + +static INLINE void +conditional_flush(struct pipe_context *pipe, struct pipe_texture **tex, + int num) +{ + int i; + for (i = 0; i < num; ++i) { + if (tex[i] && pipe->is_texture_referenced(pipe, tex[i], 0, 0) & + PIPE_REFERENCED_FOR_WRITE) { + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + return; + } + } +} + +static void +bind_samplers(struct xorg_xv_port_priv *port) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state sampler; + struct pipe_texture **dst = port->yuv[port->current_set]; + + memset(&sampler, 0, sizeof(struct pipe_sampler_state)); + + conditional_flush(port->r->pipe, dst, 3); + + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.normalized_coords = 1; + + samplers[0] = &sampler; + samplers[1] = &sampler; + samplers[2] = &sampler; + + + cso_set_samplers(port->r->cso, 3, + (const struct pipe_sampler_state **)samplers); + cso_set_sampler_textures(port->r->cso, 3, + dst); +} + +static int +display_video(ScrnInfoPtr pScrn, struct xorg_xv_port_priv *pPriv, int id, + RegionPtr dstRegion, + int src_x, int src_y, int src_w, int src_h, + int dstX, int dstY, + short width, short height, + PixmapPtr pPixmap) +{ + modesettingPtr ms = modesettingPTR(pScrn); + BoxPtr pbox; + int nbox; + int dxo, dyo; + Bool hdtv; + int x, y, w, h; + struct exa_pixmap_priv *dst = exaGetPixmapDriverPrivate(pPixmap); + + if (!dst || !dst->tex) + XORG_FALLBACK("Xv destination %s", !dst ? "!dst" : "!dst->tex"); + + hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); + + REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x, + -pPixmap->screen_y); + + dxo = dstRegion->extents.x1; + dyo = dstRegion->extents.y1; + + pbox = REGION_RECTS(dstRegion); + nbox = REGION_NUM_RECTS(dstRegion); + + renderer_bind_framebuffer(pPriv->r, dst); + renderer_bind_viewport(pPriv->r, dst); + bind_blend_state(pPriv); + renderer_bind_rasterizer(pPriv->r); + bind_shaders(pPriv); + bind_samplers(pPriv); + setup_vs_video_constants(pPriv->r, dst); + setup_fs_video_constants(pPriv->r, hdtv); + + while (nbox--) { + int box_x1 = pbox->x1; + int box_y1 = pbox->y1; + int box_x2 = pbox->x2; + int box_y2 = pbox->y2; + + x = box_x1; + y = box_y1; + w = box_x2 - box_x1; + h = box_y2 - box_y1; + + draw_yuv(pPriv, src_x, src_y, x, y, w, h); + + pbox++; + } + DamageDamageRegion(&pPixmap->drawable, dstRegion); + + return TRUE; } static int @@ -82,7 +504,58 @@ put_image(ScrnInfoPtr pScrn, Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) { - return 0; + struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + PixmapPtr pPixmap; + INT32 x1, x2, y1, y2; + int srcPitch; + BoxRec dstBox; + int ret; + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, + width, height)) + return Success; + + switch (id) { + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = width << 1; + break; + } + + ret = check_yuv_textures(pPriv, width, height); + + if (ret) + return ret; + + copy_packed_data(pScrn, pPriv, id, buf, srcPitch, + src_x, src_y, width, height); + + if (pDraw->type == DRAWABLE_WINDOW) { + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); + } else { + pPixmap = (PixmapPtr)pDraw; + } + + display_video(pScrn, pPriv, id, clipBoxes, + src_x, src_y, src_w, src_h, + drw_x, drw_y, + drw_w, drw_h, pPixmap); + + pPriv->current_set = (pPriv->current_set + 1) & 1; + return Success; } static int @@ -91,14 +564,34 @@ query_image_attributes(ScrnInfoPtr pScrn, unsigned short *w, unsigned short *h, int *pitches, int *offsets) { - return 0; + int size; + + if (*w > IMAGE_MAX_WIDTH) + *w = IMAGE_MAX_WIDTH; + if (*h > IMAGE_MAX_HEIGHT) + *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; } static struct xorg_xv_port_priv * -port_priv_create(ScreenPtr pScreen) +port_priv_create(struct xorg_renderer *r) { - /*ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];*/ - /*modesettingPtr ms = modesettingPTR(pScrn);*/ struct xorg_xv_port_priv *priv = NULL; priv = calloc(1, sizeof(struct xorg_xv_port_priv)); @@ -106,7 +599,11 @@ port_priv_create(ScreenPtr pScreen) if (!priv) return NULL; - REGION_NULL(pScreen, &priv->clip); + priv->r = r; + + REGION_NULL(pScreen, &priv->clip); + + debug_assert(priv && priv->r); return priv; } @@ -114,8 +611,8 @@ port_priv_create(ScreenPtr pScreen) static XF86VideoAdaptorPtr xorg_setup_textured_adapter(ScreenPtr pScreen) { - /*ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];*/ - /*modesettingPtr ms = modesettingPTR(pScrn);*/ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); XF86VideoAdaptorPtr adapt; XF86AttributePtr attrs; DevUnion *dev_unions; @@ -124,6 +621,9 @@ xorg_setup_textured_adapter(ScreenPtr pScreen) nattributes = NUM_TEXTURED_ATTRIBUTES; + debug_assert(ms->exa); + debug_assert(ms->exa->renderer); + adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); dev_unions = calloc(nports, sizeof(DevUnion)); attrs = calloc(nattributes, sizeof(XF86AttributeRec)); @@ -161,7 +661,7 @@ xorg_setup_textured_adapter(ScreenPtr pScreen) for (i = 0; i < nports; i++) { struct xorg_xv_port_priv *priv = - port_priv_create(pScreen); + port_priv_create(ms->exa->renderer); adapt->pPortPrivates[i].ptr = (pointer) (priv); adapt->nPorts++; |