summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2015-07-22 11:59:06 +0300
committerChris Wilson <chris@chris-wilson.co.uk>2016-07-14 20:44:56 +0100
commit1c449ffa585682b85b5581a46d7e7ca369f2ce38 (patch)
tree998c1c1c7e213964177844ce19046cfdc008695c
parent01e5845421bac4ed5862781c98e0f58445adf90e (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.c270
-rw-r--r--src/sna/sna_video_textured.c16
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;