Skip to content

Commit

Permalink
Support Xv CSC knobs
Browse files Browse the repository at this point in the history
YUV CSC will be performed by display controller instead of using GR2D
for that, but only if Xv and kernel DRM driver support necessary bits.
  • Loading branch information
digetx committed Feb 7, 2020
1 parent 2890c00 commit 036fb9a
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 30 deletions.
12 changes: 0 additions & 12 deletions src/host1x.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,6 @@
#ifndef HOST1X_H
#define HOST1X_H

#define FLOAT_TO_FIXED_6_12(fp) \
(((int32_t) (fp * 4096.0f + 0.5f)) & ((1 << 18) - 1))

#define FLOAT_TO_FIXED_s2_7(fp) \
(((fp < 0.0f) << 9) | (((int32_t) (fabs(fp) * 128.0f)) & ((1 << 9) - 1)))

#define FLOAT_TO_FIXED_s1_7(fp) \
(((fp < 0.0f) << 8) | (((int32_t) (fabs(fp) * 128.0f)) & ((1 << 8) - 1)))

#define FLOAT_TO_FIXED_0_8(fp) \
(((int32_t) (fp * 256.0f + 0.5f)) & ((1 << 8) - 1))

#define HOST1X_OPCODE_SETCL(offset, classid, mask) \
((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f))
#define HOST1X_OPCODE_INCR(offset, count) \
Expand Down
5 changes: 4 additions & 1 deletion src/presentation_queue_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ static void pqt_display_xv(tegra_pqt *pqt, tegra_surface *surf, bool block)
surf->shared->dst_y0,
surf->shared->dst_width,
surf->shared->dst_height);

tegra_xv_apply_csc(dev, &surf->shared->csc);
} else if (surf->xv_img) {
DebugMsg("surface %u RGB overlay\n", surf->surface_id);

Expand Down Expand Up @@ -462,6 +464,7 @@ static void transit_display_to_dri(tegra_pqt *pqt)

XvStopVideo(dev->display, dev->xv_port, pqt->drawable);
memset(&pqt->bg_old_state, 0, sizeof(pqt->bg_old_state));
tegra_xv_reset_csc(dev);

pqt->disp_state = TEGRA_PQT_DRI;
}
Expand Down Expand Up @@ -519,7 +522,7 @@ static void pqt_update_dri_buffer(tegra_pqt *pqt, tegra_surface *surf)
ret = host1x_gr2d_surface_blit(&surf->stream_2d,
surf->shared->video->pixbuf,
pqt->dri_pixbuf,
&surf->shared->csc,
&surf->shared->csc.gr2d,
surf->shared->src_x0,
surf->shared->src_y0,
surf->shared->src_width,
Expand Down
54 changes: 44 additions & 10 deletions src/surface_mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,51 @@ static bool custom_csc(VdpCSCMatrix const csc_matrix)
return false;
}

static bool mixer_apply_vdp_csc_to_xv(tegra_mixer *mix,
VdpCSCMatrix const cscmat)
{
tegra_device *dev = mix->dev;
uint32_t val0, val1;

if (!tegra_xv_initialize_csc(dev))
return false;

val0 = mix->csc.gr2d.yos & 0xff;
val1 = FLOAT_TO_FIXED_s2_8( CLAMP(cscmat[0][0], 0.0f, 1.98f) );

mix->csc.xv.yof_kyrgb = (val1 << 16) | val0;

val0 = FLOAT_TO_FIXED_s2_8( CLAMP(cscmat[0][1], -3.98f, 3.98f) );
val1 = FLOAT_TO_FIXED_s2_8( CLAMP(cscmat[0][2], -3.98f, 3.98f) );

mix->csc.xv.kur_kvr = (val1 << 16) | val0;

val0 = FLOAT_TO_FIXED_s1_8( CLAMP(cscmat[1][1], -1.98f, 1.98f) );
val1 = FLOAT_TO_FIXED_s1_8( CLAMP(cscmat[1][2], -1.98f, 1.98f) );

mix->csc.xv.kug_kvg = (val1 << 16) | val0;

val0 = FLOAT_TO_FIXED_s2_8( CLAMP(cscmat[2][1], -3.98f, 3.98f) );
val1 = FLOAT_TO_FIXED_s2_8( CLAMP(cscmat[2][2], -3.98f, 3.98f) );

mix->csc.xv.kub_kvb = (val1 << 16) | val0;

return true;
}

static void mixer_apply_vdp_csc(tegra_mixer *mix, VdpCSCMatrix const cscmat)
{
mix->csc.yos = -16;
mix->csc.cvr = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[0][2], -3.98f, 3.98f) );
mix->csc.cub = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[2][1], -3.98f, 3.98f) );
mix->csc.cyx = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[0][0], -1.98f, 1.98f) );
mix->csc.cur = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[0][1], -3.98f, 3.98f) );
mix->csc.cug = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[1][1], -1.98f, 1.98f) );
mix->csc.cvb = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[2][2], -3.98f, 3.98f) );
mix->csc.cvg = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[1][2], -1.98f, 1.98f) );
mix->custom_csc = custom_csc(cscmat);
mix->csc.gr2d.yos = -16;
mix->csc.gr2d.cyx = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[0][0], -1.98f, 1.98f) );
mix->csc.gr2d.cur = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[0][1], -3.98f, 3.98f) );
mix->csc.gr2d.cvr = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[0][2], -3.98f, 3.98f) );
mix->csc.gr2d.cug = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[1][1], -1.98f, 1.98f) );
mix->csc.gr2d.cvg = FLOAT_TO_FIXED_s1_7( CLAMP(cscmat[1][2], -1.98f, 1.98f) );
mix->csc.gr2d.cub = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[2][1], -3.98f, 3.98f) );
mix->csc.gr2d.cvb = FLOAT_TO_FIXED_s2_7( CLAMP(cscmat[2][2], -3.98f, 3.98f) );

mix->custom_csc = (!mixer_apply_vdp_csc_to_xv(mix, cscmat) &&
custom_csc(cscmat));
}

VdpStatus vdp_video_mixer_query_feature_support(VdpDevice device,
Expand Down Expand Up @@ -676,7 +710,7 @@ VdpStatus vdp_video_mixer_render(
ret = host1x_gr2d_surface_blit(&dest_surf->stream_2d,
video_surf->pixbuf,
dest_surf->pixbuf,
&mix->csc,
&mix->csc.gr2d,
src_vid_x0,
src_vid_y0,
src_vid_width,
Expand Down
4 changes: 2 additions & 2 deletions src/surface_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ static VdpStatus surface_render_bitmap_surface(
if (shared) {
ret = rotate_surface_gr2d(shared->video,
dst_surf,
&shared->csc,
&shared->csc.gr2d,
rotate,
0, 0,
shared->src_width,
Expand Down Expand Up @@ -688,7 +688,7 @@ static VdpStatus surface_render_bitmap_surface(
if (shared) {
ret = rotate_surface_gr2d(shared->video,
dst_surf,
&shared->csc,
&shared->csc.gr2d,
rotate,
0, 0,
shared->src_width,
Expand Down
4 changes: 2 additions & 2 deletions src/surface_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ static XvImage * create_video_xv(tegra_surface *video)

tegra_shared_surface *create_shared_surface(tegra_surface *disp,
tegra_surface *video,
struct host1x_csc_params *csc,
tegra_csc *csc,
uint32_t src_x0,
uint32_t src_y0,
uint32_t src_width,
Expand Down Expand Up @@ -310,7 +310,7 @@ int shared_surface_transfer_video(tegra_surface *disp)
ret = host1x_gr2d_surface_blit(&disp->stream_2d,
video->pixbuf,
disp->pixbuf,
&shared->csc,
&shared->csc.gr2d,
shared->src_x0,
shared->src_y0,
shared->src_width,
Expand Down
148 changes: 148 additions & 0 deletions src/vdpau_tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

static pthread_mutex_t xv_lock = PTHREAD_MUTEX_INITIALIZER;

bool tegra_vdpau_debug;
bool tegra_vdpau_force_xv;
bool tegra_vdpau_force_dri;
Expand Down Expand Up @@ -70,6 +72,152 @@ bool tegra_check_xv_atom(tegra_device *dev, char const *atom_name)
return i < count;
}

static bool __tegra_xv_apply_csc(tegra_device *dev, tegra_csc *csc)
{
int32_t val, ret;

if (dev->xv_csc.applied) {
if (memcmp(&dev->xv_csc.old.xv, &csc->xv, sizeof(csc->xv)) == 0) {
return true;
}
}

dev->xv_csc.applied = false;

ret = XvSetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_YOF_KYRGB,
csc->xv.yof_kyrgb);
if (ret != Success) {
ErrorMsg("failed to set XV_TEGRA_YOF_KYRGB %d\n", ret);
return false;
}

ret = XvSetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_KUR_KVR,
csc->xv.kur_kvr);
if (ret != Success) {
ErrorMsg("failed to set XV_TEGRA_KUR_KVR %d\n", ret);
return false;
}

ret = XvSetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_KUG_KVG,
csc->xv.kug_kvg);
if (ret != Success) {
ErrorMsg("failed to set XV_TEGRA_KUG_KVG %d\n", ret);
return false;
}

ret = XvSetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_KUB_KVB,
csc->xv.kub_kvb);
if (ret != Success) {
ErrorMsg("failed to set XV_TEGRA_KUB_KVB %d\n", ret);
return false;
}

ret = XvSetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_update,
1);
if (ret != Success) {
ErrorMsg("failed to set XV_TEGRA_CSC_UPDATE %d\n", ret);
dev->xv_csc.ready = false;
return false;
}

ret = XvGetPortAttribute(dev->display, dev->xv_port,
dev->xv_csc.xvCSC_update, &val);
if (ret != Success || !val) {
ErrorMsg("failed to get XV_TEGRA_CSC_UPDATE %d val %d\n", ret, val);
dev->xv_csc.ready = false;
return false;
}

dev->xv_csc.old.xv = csc->xv;
dev->xv_csc.applied = true;

return true;
}

bool tegra_xv_initialize_csc(tegra_device *dev)
{
pthread_mutex_lock(&xv_lock);

if (!dev->xv_csc.inited && dev->xv_ready) {
if (tegra_check_xv_atom(dev, "XV_TEGRA_YOF_KYRGB"))
dev->xv_csc.xvCSC_YOF_KYRGB = XInternAtom(dev->display,
"XV_TEGRA_YOF_KYRGB",
false);

if (tegra_check_xv_atom(dev, "XV_TEGRA_KUR_KVR"))
dev->xv_csc.xvCSC_KUR_KVR = XInternAtom(dev->display,
"XV_TEGRA_KUR_KVR",
false);

if (tegra_check_xv_atom(dev, "XV_TEGRA_KUG_KVG"))
dev->xv_csc.xvCSC_KUG_KVG = XInternAtom(dev->display,
"XV_TEGRA_KUG_KVG",
false);

if (tegra_check_xv_atom(dev, "XV_TEGRA_KUB_KVB"))
dev->xv_csc.xvCSC_KUB_KVB = XInternAtom(dev->display,
"XV_TEGRA_KUB_KVB",
false);

if (tegra_check_xv_atom(dev, "XV_TEGRA_CSC_UPDATE"))
dev->xv_csc.xvCSC_update = XInternAtom(dev->display,
"XV_TEGRA_CSC_UPDATE",
false);
if (dev->xv_csc.xvCSC_YOF_KYRGB != None &&
dev->xv_csc.xvCSC_KUR_KVR != None &&
dev->xv_csc.xvCSC_KUG_KVG != None &&
dev->xv_csc.xvCSC_KUB_KVB != None &&
dev->xv_csc.xvCSC_update != None)
{
tegra_csc default_csc = {
.xv = {
.yof_kyrgb = 0x012a00f0,
.kur_kvr = 0x01980000,
.kug_kvg = 0x032f039b,
.kub_kvb = 0x00000204,
},
};

dev->xv_csc.ready = __tegra_xv_apply_csc(dev, &default_csc);
}

if (!dev->xv_csc.ready) {
ErrorMsg("XV colorspace conversion not available, update Opentegra Xorg driver and/or Linux kernel to get video overlay CSC support\n");
}

dev->xv_csc.inited = true;
}

pthread_mutex_unlock(&xv_lock);

return dev->xv_csc.ready;
}

void tegra_xv_reset_csc(tegra_device *dev)
{
pthread_mutex_lock(&xv_lock);
dev->xv_csc.applied = false;
pthread_mutex_unlock(&xv_lock);
}

bool tegra_xv_apply_csc(tegra_device *dev, tegra_csc *csc)
{
int ret = false;

pthread_mutex_lock(&xv_lock);
if (dev->xv_csc.ready) {
ret = __tegra_xv_apply_csc(dev, csc);
}
pthread_mutex_unlock(&xv_lock);

return ret;
}

VdpTime get_time(void)
{
struct timespec tp;
Expand Down
Loading

0 comments on commit 036fb9a

Please sign in to comment.