Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proof of concept OSD code. #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions presentation_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,26 @@ VdpStatus vdp_presentation_queue_display(VdpPresentationQueue presentation_queue
int x,y;
XTranslateCoordinates(q->device->display, q->target->drawable, RootWindow(q->device->display, q->device->screen), 0, 0, &x, &y, &c);
XClearWindow(q->device->display, q->target->drawable);
if (os->data && !os->data_clear)
{
GC gc = XCreateGC(q->device->display, q->target->drawable, 0, 0);
const uint32_t *src = os->data;
uint32_t x, y;
for (y = 0; y < os->height; y++)
{
for (x = 0; x < os->width; x++)
{
uint32_t v = *src++;
if ((v >> 24) > 0x80)
{
XSetForeground(q->device->display, gc, v);
XDrawPoint(q->device->display, q->target->drawable, gc, x, y);
}
}
}
XFreeGC(q->device->display, gc);
XFlush(q->device->display);
}

__disp_layer_info_t layer_info;
memset(&layer_info, 0, sizeof(layer_info));
Expand Down Expand Up @@ -287,6 +307,25 @@ VdpStatus vdp_presentation_queue_display(VdpPresentationQueue presentation_queue

ioctl(q->target->fd, DISP_CMD_LAYER_BOTTOM, args);
ioctl(q->target->fd, DISP_CMD_LAYER_OPEN, args);
// Note: might be more reliable (but slower and problematic when there
// are driver issues and the GET functions return wrong values) to query the
// old values instead of relying on our internal csc_change.
// Since the driver calculates a matrix out of these values after each
// set doing this unconditionally is costly.
if (os->csc_change) {
ioctl(q->target->fd, DISP_CMD_LAYER_ENHANCE_OFF, args);
args[2] = 0xff * os->brightness + 0x20;
ioctl(q->target->fd, DISP_CMD_LAYER_SET_BRIGHT, args);
args[2] = 0x20 * os->contrast;
ioctl(q->target->fd, DISP_CMD_LAYER_SET_CONTRAST, args);
args[2] = 0x20 * os->saturation;
ioctl(q->target->fd, DISP_CMD_LAYER_SET_SATURATION, args);
// hue scale is randomly chosen, no idea how it maps exactly
args[2] = (32 / 3.14) * os->hue + 0x20;
ioctl(q->target->fd, DISP_CMD_LAYER_SET_HUE, args);
ioctl(q->target->fd, DISP_CMD_LAYER_ENHANCE_ON, args);
os->csc_change = 0;
}

return VDP_STATUS_OK;
}
Expand Down
97 changes: 94 additions & 3 deletions surface_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
*
*/

#include <string.h>
#include "vdpau_private.h"

VdpStatus vdp_output_surface_create(VdpDevice device, VdpRGBAFormat rgba_format, uint32_t width, uint32_t height, VdpOutputSurface *surface)
{
if (!surface)
return VDP_STATUS_INVALID_POINTER;

if (!width || !height)
if (!width || !height || width >= 16384 || height >= 16384)
return VDP_STATUS_INVALID_SIZE;

device_ctx_t *dev = handle_get(device);
Expand All @@ -38,7 +39,11 @@ VdpStatus vdp_output_surface_create(VdpDevice device, VdpRGBAFormat rgba_format,
out->width = width;
out->height = height;
out->rgba_format = rgba_format;
out->contrast = 1.0;
out->saturation = 1.0;
out->device = dev;
// Do not allocate data yet, we might not need to
out->data = NULL;

int handle = handle_create(out);
if (handle == -1)
Expand Down Expand Up @@ -106,16 +111,58 @@ VdpStatus vdp_output_surface_put_bits_native(VdpOutputSurface surface, void cons
return VDP_STATUS_OK;
}

static int valid_rect(const VdpRect *rect, const output_surface_ctx_t *out)
{
return rect->x0 <= rect->x1 &&
rect->y0 <= rect->y1 &&
rect->x1 < out->width &&
rect->y1 < out->height;
}

VdpStatus vdp_output_surface_put_bits_indexed(VdpOutputSurface surface, VdpIndexedFormat source_indexed_format, void const *const *source_data, uint32_t const *source_pitch, VdpRect const *destination_rect, VdpColorTableFormat color_table_format, void const *color_table)
{
output_surface_ctx_t *out = handle_get(surface);
if (!out)
return VDP_STATUS_INVALID_HANDLE;

VDPAU_DBG_ONCE("%s called but unimplemented!", __func__);
if (!valid_rect(destination_rect, out))
return VDP_STATUS_INVALID_SIZE;

if (out->rgba_format != VDP_RGBA_FORMAT_B8G8R8A8 ||
source_indexed_format != VDP_INDEXED_FORMAT_I8A8 ||
color_table_format != VDP_COLOR_TABLE_FORMAT_B8G8R8X8)
{
VDPAU_DBG_ONCE("%s called but unimplemented!", __func__);
return VDP_STATUS_OK;
}

if (!out->data)
out->data = calloc(out->width * 4, out->height);
if (!out->data)
return VDP_STATUS_RESOURCES;

const uint32_t *palette = color_table;
uint32_t w = destination_rect->x1 - destination_rect->x0;
uint32_t h = destination_rect->y1 - destination_rect->y0;
uint32_t *dst = out->data;
dst += destination_rect->y0 * out->width + destination_rect->x0;
uint32_t dst_step = out->width - w;
const uint8_t *src = source_data[0];
if (source_pitch[0] < 2 * w)
return VDP_STATUS_INVALID_SIZE;
uint32_t src_step = source_pitch[0] - 2*w;
uint32_t x, y;
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
*dst = palette[*src++] & 0x00ffffffu;
*dst++ |= *src++ << 24;
}
src += src_step;
dst += dst_step;
}
out->data_clear = 0;
return VDP_STATUS_OK;
}

Expand All @@ -138,14 +185,58 @@ VdpStatus vdp_output_surface_render_output_surface(VdpOutputSurface destination_
if (!out)
return VDP_STATUS_INVALID_HANDLE;

if (source_surface == VDP_INVALID_HANDLE)
{
// for now assume destination_rect == NULL and
// always clear the whole surface
if (out->data)
{
free(out->data);
out->data = NULL;
}
return VDP_STATUS_OK;
}

output_surface_ctx_t *in = handle_get(source_surface);
if (!in)
return VDP_STATUS_INVALID_HANDLE;

VDPAU_DBG_ONCE("%s called but unimplemented!", __func__);
if (!valid_rect(source_rect, in) ||
!valid_rect(destination_rect, out))
return VDP_STATUS_INVALID_SIZE;

if (out->rgba_format != VDP_RGBA_FORMAT_B8G8R8A8 ||
!in->data)
{
VDPAU_DBG_ONCE("%s called but unimplemented!", __func__);
return VDP_STATUS_OK;
}

if (out->data && out->data_clear)
memset(out->data, 0, out->width * 4 * out->height);
if (!out->data)
out->data = calloc(out->width * 4, out->height);
if (!out->data)
return VDP_STATUS_RESOURCES;

uint32_t w = destination_rect->x1 - destination_rect->x0;
uint32_t ws = source_rect->x1 - source_rect->x0;
if (ws < w) w = ws;
uint32_t h = destination_rect->y1 - destination_rect->y0;
uint32_t hs = source_rect->y1 - source_rect->y0;
if (hs < h) h = hs;
uint32_t *dst = out->data;
dst += destination_rect->y0 * out->width + destination_rect->x0;
const uint32_t *src = in->data;
src += source_rect->y0 * in->width + source_rect->x0;
uint32_t y;
for (y = 0; y < h; y++)
{
memcpy(dst, src, w * 4);
src += in->width;
dst += out->width;
}
out->data_clear = 0;
return VDP_STATUS_OK;
}

Expand Down
12 changes: 12 additions & 0 deletions vdpau_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,27 @@ typedef struct
typedef struct
{
device_ctx_t *device;
int csc_change;
float brightness;
float contrast;
float saturation;
float hue;
} mixer_ctx_t;

typedef struct
{
device_ctx_t *device;
VdpRGBAFormat rgba_format;
uint32_t width, height;
int data_clear; // data should be treated as clear
uint32_t *data;
video_surface_ctx_t *vs;
VdpRect video_src_rect, video_dst_rect;
int csc_change;
float brightness;
float contrast;
float saturation;
float hue;
} output_surface_ctx_t;

#ifndef ARRAY_SIZE
Expand Down
72 changes: 58 additions & 14 deletions video_mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*
*/

#include <math.h>
#include "vdpau_private.h"

VdpStatus vdp_video_mixer_create(VdpDevice device, uint32_t feature_count, VdpVideoMixerFeature const *features, uint32_t parameter_count, VdpVideoMixerParameter const *parameters, void const *const *parameter_values, VdpVideoMixer *mixer)
Expand All @@ -30,6 +31,8 @@ VdpStatus vdp_video_mixer_create(VdpDevice device, uint32_t feature_count, VdpVi
return VDP_STATUS_RESOURCES;

mix->device = dev;
mix->contrast = 1.0;
mix->saturation = 1.0;

int handle = handle_create(mix);
if (handle == -1)
Expand Down Expand Up @@ -76,6 +79,8 @@ VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer, VdpOutputSurface backgroun
if (!os)
return VDP_STATUS_INVALID_HANDLE;

os->data_clear = 1;

os->vs = handle_get(video_surface_current);
if (!(os->vs))
return VDP_STATUS_INVALID_HANDLE;
Expand All @@ -92,6 +97,12 @@ VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer, VdpOutputSurface backgroun
os->video_src_rect.y1 = os->vs->height;
}
}
os->csc_change = mix->csc_change;
os->brightness = mix->brightness;
os->contrast = mix->contrast;
os->saturation = mix->saturation;
os->hue = mix->hue;
mix->csc_change = 0;

if (layer_count != 0)
VDPAU_DBG_ONCE("Requested unimplemented additional layers");
Expand Down Expand Up @@ -145,6 +156,26 @@ VdpStatus vdp_video_mixer_get_feature_enables(VdpVideoMixer mixer, uint32_t feat
return VDP_STATUS_ERROR;
}

static void set_csc_matrix(mixer_ctx_t *mix, const VdpCSCMatrix *matrix)
{
mix->csc_change = 1;
// default contrast for full-range has 1.0 as luma coefficients
mix->contrast = ((*matrix)[0][0] + (*matrix)[1][0] + (*matrix)[2][0]) / 3;
// the way brightness and contrast work with this driver, brightness
// is the brightness of a "black" pixel
mix->brightness = ((*matrix)[0][1] + (*matrix)[1][1] + (*matrix)[2][1]) / 2 +
((*matrix)[0][2] + (*matrix)[1][2] + (*matrix)[2][2]) / 2 +
(*matrix)[0][3] + (*matrix)[1][3] + (*matrix)[2][3];
mix->brightness /= 3;

float sin = (*matrix)[0][1] + (*matrix)[2][2];
float cos = (*matrix)[0][2] + (*matrix)[2][1];
float e = 0.001;
if (-e < cos && cos < e) mix->hue = M_PI;
else mix->hue = atanf(sin/cos);
mix->saturation = sqrtf(sin * sin + cos * cos) / (1.403 + 1.773);
}

VdpStatus vdp_video_mixer_set_attribute_values(VdpVideoMixer mixer, uint32_t attribute_count, VdpVideoMixerAttribute const *attributes, void const *const *attribute_values)
{
if (!attributes || !attribute_values)
Expand All @@ -154,6 +185,10 @@ VdpStatus vdp_video_mixer_set_attribute_values(VdpVideoMixer mixer, uint32_t att
if (!mix)
return VDP_STATUS_INVALID_HANDLE;

uint32_t i;
for (i = 0; i < attribute_count; i++)
if (attributes[i] == VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX)
set_csc_matrix(mix, (const VdpCSCMatrix *)attribute_values[i]);

return VDP_STATUS_OK;
}
Expand Down Expand Up @@ -305,20 +340,29 @@ VdpStatus vdp_generate_csc_matrix(VdpProcamp *procamp, VdpColorStandard standard
if (procamp->struct_version > VDP_PROCAMP_VERSION)
return VDP_STATUS_INVALID_STRUCT_VERSION;

(*csc_matrix)[0][0] = 1.164000;
(*csc_matrix)[0][1] = 0.000000;
(*csc_matrix)[0][2] = 1.596000;
(*csc_matrix)[0][3] = -0.874165;

(*csc_matrix)[1][0] = 1.164000;
(*csc_matrix)[1][1] = -0.391000;
(*csc_matrix)[1][2] = -0.813000;
(*csc_matrix)[1][3] = 0.531326;

(*csc_matrix)[2][0] = 1.164000;
(*csc_matrix)[2][1] = 2.018000;
(*csc_matrix)[2][2] = 0.000000;
(*csc_matrix)[2][3] = -1.085992;
// BT.601 table
(*csc_matrix)[0][1] = 0.000;
(*csc_matrix)[0][2] = 1.403;

(*csc_matrix)[1][1] = -0.344;
(*csc_matrix)[1][2] = -0.714;

(*csc_matrix)[2][1] = 1.773;
(*csc_matrix)[2][2] = 0.000;

float uvcos = procamp->saturation * cosf(procamp->hue);
float uvsin = procamp->saturation * sinf(procamp->hue);
int i;
for (i = 0; i < 3; i++) {
(*csc_matrix)[i][0] = procamp->contrast;
float u = (*csc_matrix)[i][1] * uvcos + (*csc_matrix)[i][2] * uvsin;
float v = (*csc_matrix)[i][1] * uvsin + (*csc_matrix)[i][2] * uvcos;
(*csc_matrix)[i][1] = u;
(*csc_matrix)[i][2] = v;
(*csc_matrix)[i][3] = - (u + v) / 2;
(*csc_matrix)[i][3] += 0.5 - procamp->contrast / 2;
(*csc_matrix)[i][3] += procamp->brightness;
}

return VDP_STATUS_OK;
}