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>
This commit is contained in:
Ville Syrjälä 2015-07-22 11:59:06 +03:00 committed by Chris Wilson
parent 01e5845421
commit 1c449ffa58
2 changed files with 282 additions and 4 deletions

View File

@ -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"
@ -3123,6 +3124,273 @@ gen2_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
return true;
}
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,
@ -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;

View File

@ -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;