diff options
author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2015-07-22 11:59:06 +0300 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2016-07-14 20:44:56 +0100 |
commit | 1c449ffa585682b85b5581a46d7e7ca369f2ce38 (patch) | |
tree | 998c1c1c7e213964177844ce19046cfdc008695c | |
parent | 01e5845421bac4ed5862781c98e0f58445adf90e (diff) |
sna/gen2/video: Implement textured video support
Add textured video support for gen2. The hardware can only deal with
packed YUV formats, so only those will be exposed.
Modelled after the gen3 textured video code.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
-rw-r--r-- | src/sna/gen2_render.c | 270 | ||||
-rw-r--r-- | src/sna/sna_video_textured.c | 16 |
2 files changed, 282 insertions, 4 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c index 33b986e6..c6eceda5 100644 --- a/src/sna/gen2_render.c +++ b/src/sna/gen2_render.c @@ -35,6 +35,7 @@ #include "sna_reg.h" #include "sna_render.h" #include "sna_render_inline.h" +#include "sna_video.h" #include "gen2_render.h" @@ -3124,6 +3125,273 @@ gen2_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo, } static void +gen2_emit_video_state(struct sna *sna, + struct sna_video *video, + struct sna_video_frame *frame, + PixmapPtr pixmap, + struct kgem_bo *dst_bo, + int width, int height, + bool bilinear) +{ + uint32_t ms1, v, unwind; + + gen2_emit_target(sna, dst_bo, width, height, + sna_format_for_depth(pixmap->drawable.depth)); + + unwind = sna->kgem.nbatch; + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | + I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2); + BATCH(1 << 12); + BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY); + BATCH(S8_ENABLE_COLOR_BUFFER_WRITE); + if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1, + sna->kgem.batch + unwind + 1, + 3 * sizeof(uint32_t)) == 0) + sna->kgem.nbatch = unwind; + else + sna->render_state.gen2.ls1 = unwind; + + gen2_disable_logic_op(sna); + + unwind = sna->kgem.nbatch; + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | + LOAD_TEXTURE_BLEND_STAGE(0) | 1); + BATCH(TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OUTPUT_WRITE_CURRENT | + TB0C_OP_ARG1 | TB0C_ARG1_SEL_TEXEL0); + BATCH(TB0A_RESULT_SCALE_1X | TB0A_OUTPUT_WRITE_CURRENT | + TB0A_OP_ARG1 | TB0A_ARG1_SEL_ONE); + if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1, + sna->kgem.batch + unwind + 1, + 2 * sizeof(uint32_t)) == 0) + sna->kgem.nbatch = unwind; + else + sna->render_state.gen2.ls2 = unwind; + + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(0) | 4); + BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch, + frame->bo, + I915_GEM_DOMAIN_SAMPLER << 16, + 0)); + ms1 = MAPSURF_422 | TM0S1_COLORSPACE_CONVERSION; + switch (frame->id) { + case FOURCC_YUY2: + ms1 |= MT_422_YCRCB_NORMAL; + break; + case FOURCC_UYVY: + ms1 |= MT_422_YCRCB_SWAPY; + break; + } + BATCH(((frame->height - 1) << TM0S1_HEIGHT_SHIFT) | + ((frame->width - 1) << TM0S1_WIDTH_SHIFT) | + ms1 | + gen2_sampler_tiling_bits(frame->bo->tiling)); + BATCH((frame->pitch[0] / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D); + if (bilinear) + BATCH(FILTER_LINEAR << TM0S3_MAG_FILTER_SHIFT | + FILTER_LINEAR << TM0S3_MIN_FILTER_SHIFT | + MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT); + else + BATCH(FILTER_NEAREST << TM0S3_MAG_FILTER_SHIFT | + FILTER_NEAREST << TM0S3_MIN_FILTER_SHIFT | + MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT); + BATCH(0); /* default color */ + + BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(0) | + ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) | + ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP)); + + v = _3DSTATE_VERTEX_FORMAT_2_CMD | TEXCOORDFMT_2D; + if (sna->render_state.gen2.vft != v) { + BATCH(v); + sna->render_state.gen2.vft = v; + } +} + +static void +gen2_video_get_batch(struct sna *sna, struct kgem_bo *bo) +{ + kgem_set_mode(&sna->kgem, KGEM_RENDER, bo); + + if (!kgem_check_batch(&sna->kgem, 120) || + !kgem_check_reloc(&sna->kgem, 4) || + !kgem_check_exec(&sna->kgem, 2)) { + _kgem_submit(&sna->kgem); + _kgem_set_mode(&sna->kgem, KGEM_RENDER); + } + + if (sna->render_state.gen2.need_invariant) + gen2_emit_invariant(sna); +} + +static int +gen2_get_inline_rectangles(struct sna *sna, int want, int floats_per_vertex) +{ + int size = floats_per_vertex * 3; + int rem = batch_space(sna) - 1; + + if (size * want > rem) + want = rem / size; + + return want; +} + +static bool +gen2_render_video(struct sna *sna, + struct sna_video *video, + struct sna_video_frame *frame, + RegionPtr dstRegion, + PixmapPtr pixmap) +{ + struct sna_pixmap *priv = sna_pixmap(pixmap); + const BoxRec *pbox = region_rects(dstRegion); + int nbox = region_num_rects(dstRegion); + int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1; + int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1; + int src_width = frame->src.x2 - frame->src.x1; + int src_height = frame->src.y2 - frame->src.y1; + float src_offset_x, src_offset_y; + float src_scale_x, src_scale_y; + int pix_xoff, pix_yoff; + struct kgem_bo *dst_bo; + bool bilinear; + int copy = 0; + + DBG(("%s: src:%dx%d (frame:%dx%d) -> dst:%dx%d\n", __FUNCTION__, + src_width, src_height, frame->width, frame->height, dst_width, dst_height)); + + assert(priv->gpu_bo); + dst_bo = priv->gpu_bo; + + bilinear = src_width != dst_width || src_height != dst_height; + + src_scale_x = (float)src_width / dst_width / frame->width; + src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x; + + src_scale_y = (float)src_height / dst_height / frame->height; + src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y; + DBG(("%s: src offset (%f, %f), scale (%f, %f)\n", + __FUNCTION__, src_offset_x, src_offset_y, src_scale_x, src_scale_y)); + + if (too_large(pixmap->drawable.width, pixmap->drawable.height) || + dst_bo->pitch > MAX_3D_PITCH) { + int bpp = pixmap->drawable.bitsPerPixel; + + if (too_large(dst_width, dst_height)) + return false; + + dst_bo = kgem_create_2d(&sna->kgem, + dst_width, dst_height, bpp, + kgem_choose_tiling(&sna->kgem, + I915_TILING_X, + dst_width, dst_height, bpp), + 0); + if (!dst_bo) + return false; + + pix_xoff = -dstRegion->extents.x1; + pix_yoff = -dstRegion->extents.y1; + copy = 1; + } else { + /* Set up the offset for translating from the given region + * (in screen coordinates) to the backing pixmap. + */ +#ifdef COMPOSITE + pix_xoff = -pixmap->screen_x + pixmap->drawable.x; + pix_yoff = -pixmap->screen_y + pixmap->drawable.y; +#else + pix_xoff = 0; + pix_yoff = 0; +#endif + + dst_width = pixmap->drawable.width; + dst_height = pixmap->drawable.height; + } + + gen2_video_get_batch(sna, dst_bo); + gen2_emit_video_state(sna, video, frame, pixmap, + dst_bo, dst_width, dst_height, bilinear); + do { + int nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4); + if (nbox_this_time == 0) { + gen2_video_get_batch(sna, dst_bo); + gen2_emit_video_state(sna, video, frame, pixmap, + dst_bo, dst_width, dst_height, bilinear); + nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4); + assert(nbox_this_time); + } + nbox -= nbox_this_time; + + BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST | + ((12 * nbox_this_time) - 1)); + do { + int box_x1 = pbox->x1; + int box_y1 = pbox->y1; + int box_x2 = pbox->x2; + int box_y2 = pbox->y2; + + pbox++; + + DBG(("%s: dst (%d, %d), (%d, %d) + (%d, %d); src (%f, %f), (%f, %f)\n", + __FUNCTION__, box_x1, box_y1, box_x2, box_y2, pix_xoff, pix_yoff, + box_x1 * src_scale_x + src_offset_x, + box_y1 * src_scale_y + src_offset_y, + box_x2 * src_scale_x + src_offset_x, + box_y2 * src_scale_y + src_offset_y)); + + /* bottom right */ + BATCH_F(box_x2 + pix_xoff); + BATCH_F(box_y2 + pix_yoff); + BATCH_F(box_x2 * src_scale_x + src_offset_x); + BATCH_F(box_y2 * src_scale_y + src_offset_y); + + /* bottom left */ + BATCH_F(box_x1 + pix_xoff); + BATCH_F(box_y2 + pix_yoff); + BATCH_F(box_x1 * src_scale_x + src_offset_x); + BATCH_F(box_y2 * src_scale_y + src_offset_y); + + /* top left */ + BATCH_F(box_x1 + pix_xoff); + BATCH_F(box_y1 + pix_yoff); + BATCH_F(box_x1 * src_scale_x + src_offset_x); + BATCH_F(box_y1 * src_scale_y + src_offset_y); + } while (--nbox_this_time); + } while (nbox); + + if (copy) { +#ifdef COMPOSITE + pix_xoff = -pixmap->screen_x + pixmap->drawable.x; + pix_yoff = -pixmap->screen_y + pixmap->drawable.y; +#else + pix_xoff = 0; + pix_yoff = 0; +#endif + sna_blt_copy_boxes(sna, GXcopy, + dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1, + priv->gpu_bo, pix_xoff, pix_yoff, + pixmap->drawable.bitsPerPixel, + region_rects(dstRegion), + region_num_rects(dstRegion)); + + kgem_bo_destroy(&sna->kgem, dst_bo); + } + + if (!DAMAGE_IS_ALL(priv->gpu_damage)) { + if ((pix_xoff | pix_yoff) == 0) { + sna_damage_add(&priv->gpu_damage, dstRegion); + } else { + sna_damage_add_boxes(&priv->gpu_damage, + region_rects(dstRegion), + region_num_rects(dstRegion), + pix_xoff, pix_yoff); + } + } + + return true; +} + +static void gen2_render_copy_setup_source(struct sna_composite_channel *channel, const DrawableRec *draw, struct kgem_bo *bo) @@ -3537,7 +3805,7 @@ const char *gen2_render_init(struct sna *sna, const char *backend) render->copy = gen2_render_copy; render->copy_boxes = gen2_render_copy_boxes; - /* XXX YUV color space conversion for video? */ + render->video = gen2_render_video; render->reset = gen2_render_reset; render->flush = gen2_render_flush; diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c index f5b7e98d..3cce5cf1 100644 --- a/src/sna/sna_video_textured.c +++ b/src/sna/sna_video_textured.c @@ -48,7 +48,12 @@ static const XvAttributeRec Attributes[] = { //{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"}, }; -static const XvImageRec Images[] = { +static const XvImageRec gen2_Images[] = { + XVIMAGE_YUY2, + XVIMAGE_UYVY, +}; + +static const XvImageRec gen3_Images[] = { XVIMAGE_YUY2, XVIMAGE_YV12, XVIMAGE_I420, @@ -366,8 +371,13 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen) ARRAY_SIZE(Formats)); adaptor->nAttributes = ARRAY_SIZE(Attributes); adaptor->pAttributes = (XvAttributeRec *)Attributes; - adaptor->nImages = ARRAY_SIZE(Images); - adaptor->pImages = (XvImageRec *)Images; + if (sna->kgem.gen < 030) { + adaptor->nImages = ARRAY_SIZE(gen2_Images); + adaptor->pImages = (XvImageRec *)gen2_Images; + } else { + adaptor->nImages = ARRAY_SIZE(gen3_Images); + adaptor->pImages = (XvImageRec *)gen3_Images; + } #if XORG_XV_VERSION < 2 adaptor->ddAllocatePort = sna_xv_alloc_port; adaptor->ddFreePort = sna_xv_free_port; |