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

Add rescaled screen detection and screen1 (/dev/fb1) support #63

Open
wants to merge 1 commit 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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,20 @@ $ export VDPAU_DISABLE_G2D=1

If using G2D (A10/A20), make sure to have write access to `/dev/g2d`.

# Play video on second screen

Because X video driver is baypassed and own disp layers are directly used, physical screen number must be specified using VDPAU_SCREEN env var. If VDPAU_SCREEN is not specified, the same screen number than the one used by the X server will be used.

This is enough for the most common Xorg configurations:

* 1 screen: Xorg screen 0 is physical screen 0
* 2 screens: Xorg screen 0 is physical screen 0 and Xorg screen 1 is physical screen 1.

If your Xorg configuration is different, you must set VDPAU_SCREEN env var to 0 or 1 (even if using extended desktop configurations, see limitations below).

# Limitations:

* Output bypasses X video driver by opening own disp layers. You can't use Xv from fbturbo at the same time, and on H3 the video is always on top and can't be overlapped by other windows.
* OSD partly breaks X11 integration due to hardware limitations. The video area can't be overlapped by other windows. For fullscreen use this is no problem.
* There is no [OpenGL interoperation feature] (https://www.opengl.org/registry/specs/NV/vdpau_interop.txt) because we are on ARM and only have OpenGL/ES available.
* VDPAU_SCREEN must be specified if Xorg screen numbers doesn't match physical screen numbers. Also if video is played in second monitor when using a extended desktop configuration (such as Xinerama). In this case, video can't be played partially in one monitor and partially in the other.
13 changes: 12 additions & 1 deletion device.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ VdpStatus vdp_imp_device_create_x11(Display *display,

char *env_vdpau_osd = getenv("VDPAU_OSD");
char *env_vdpau_g2d = getenv("VDPAU_DISABLE_G2D");
char *env_vdpau_screen = getenv("VDPAU_SCREEN");

if (env_vdpau_screen) {
dev->screen_i = atoi(env_vdpau_screen);
VDPAU_DBG("VDPAU_SCREEN set to %d", dev->screen_i);
}
else {
dev->screen_i = screen; // try same than X screen
VDPAU_DBG("VDPAU_SCREEN not set, trying screen %d", dev->screen_i);
}

if (env_vdpau_osd && strncmp(env_vdpau_osd, "1", 1) == 0)
dev->osd_enabled = 1;
else
Expand All @@ -71,7 +82,7 @@ VdpStatus vdp_imp_device_create_x11(Display *display,

if (!dev->g2d_enabled)
VDPAU_DBG("OSD enabled, using pixman");

return VDP_STATUS_OK;
}

Expand Down
2 changes: 1 addition & 1 deletion presentation_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ VdpStatus vdp_presentation_queue_target_create_x11(VdpDevice device,
qt->drawable = drawable;
XSetWindowBackground(dev->display, drawable, 0x000102);

qt->disp = sunxi_disp_open(dev->osd_enabled);
qt->disp = sunxi_disp_open(dev->screen_i, dev->osd_enabled);

if (!qt->disp)
qt->disp = sunxi_disp2_open(dev->osd_enabled);
Expand Down
43 changes: 32 additions & 11 deletions sunxi_disp.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ struct sunxi_disp_private
int fd;
int video_layer;
int osd_layer;
int sc_src_width;
int sc_src_height;
int sc_width;
int sc_height;
int screen_i;
__disp_layer_info_t video_info;
__disp_layer_info_t osd_info;
};
Expand All @@ -43,7 +48,7 @@ static void sunxi_disp_close_video_layer(struct sunxi_disp *sunxi_disp);
static int sunxi_disp_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface);
static void sunxi_disp_close_osd_layer(struct sunxi_disp *sunxi_disp);

struct sunxi_disp *sunxi_disp_open(int osd_enabled)
struct sunxi_disp *sunxi_disp_open(int screen_i, int osd_enabled)
{
struct sunxi_disp_private *disp = calloc(1, sizeof(*disp));

Expand All @@ -55,7 +60,23 @@ struct sunxi_disp *sunxi_disp_open(int osd_enabled)
if (ioctl(disp->fd, DISP_CMD_VERSION, &tmp) < 0)
goto err_version;

uint32_t args[4] = { 0, DISP_LAYER_WORK_MODE_SCALER, 0, 0 };
disp->screen_i = screen_i;

__disp_layer_info_t layer_info;
uint32_t args[4] = { disp->screen_i, 100, (uint32_t)&layer_info, 0 };
disp->sc_src_width = 1;
disp->sc_src_height = 1;
disp->sc_width = 1;
disp->sc_height = 1;
if(ioctl(disp->fd, DISP_CMD_LAYER_GET_PARA, args) >= 0 && layer_info.mode == DISP_LAYER_WORK_MODE_SCALER)
{
disp->sc_src_width = layer_info.src_win.width;
disp->sc_src_height = layer_info.src_win.height;
disp->sc_width = layer_info.scn_win.width;
disp->sc_height = layer_info.scn_win.height;
}
args[1] = DISP_LAYER_WORK_MODE_SCALER;
args[2] = 0;
disp->video_layer = ioctl(disp->fd, DISP_CMD_LAYER_REQUEST, args);
if (disp->video_layer == 0)
goto err_video_layer;
Expand Down Expand Up @@ -124,7 +145,7 @@ static void sunxi_disp_close(struct sunxi_disp *sunxi_disp)
{
struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp;

uint32_t args[4] = { 0, disp->video_layer, 0, 0 };
uint32_t args[4] = { disp->screen_i, disp->video_layer, 0, 0 };
ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args);
ioctl(disp->fd, DISP_CMD_LAYER_RELEASE, args);

Expand Down Expand Up @@ -182,10 +203,10 @@ static int sunxi_disp_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int
disp->video_info.src_win.y = surface->video_src_rect.y0;
disp->video_info.src_win.width = surface->video_src_rect.x1 - surface->video_src_rect.x0;
disp->video_info.src_win.height = surface->video_src_rect.y1 - surface->video_src_rect.y0;
disp->video_info.scn_win.x = x + surface->video_dst_rect.x0;
disp->video_info.scn_win.y = y + surface->video_dst_rect.y0;
disp->video_info.scn_win.width = surface->video_dst_rect.x1 - surface->video_dst_rect.x0;
disp->video_info.scn_win.height = surface->video_dst_rect.y1 - surface->video_dst_rect.y0;
disp->video_info.scn_win.x = x * disp->sc_width / disp->sc_src_width + surface->video_dst_rect.x0 * disp->sc_width / disp->sc_src_width;
disp->video_info.scn_win.y = y * disp->sc_height / disp->sc_src_height + surface->video_dst_rect.y0 * disp->sc_height / disp->sc_src_height;
disp->video_info.scn_win.width = (surface->video_dst_rect.x1 - surface->video_dst_rect.x0) * disp->sc_width / disp->sc_src_width;
disp->video_info.scn_win.height = (surface->video_dst_rect.y1 - surface->video_dst_rect.y0) * disp->sc_height / disp->sc_src_height;

if (disp->video_info.scn_win.y < 0)
{
Expand All @@ -197,7 +218,7 @@ static int sunxi_disp_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int
disp->video_info.scn_win.height -= scn_clip;
}

uint32_t args[4] = { 0, disp->video_layer, (unsigned long)(&disp->video_info), 0 };
uint32_t args[4] = { disp->screen_i, disp->video_layer, (unsigned long)(&disp->video_info), 0 };
ioctl(disp->fd, DISP_CMD_LAYER_SET_PARA, args);

ioctl(disp->fd, DISP_CMD_LAYER_OPEN, args);
Expand Down Expand Up @@ -230,7 +251,7 @@ static void sunxi_disp_close_video_layer(struct sunxi_disp *sunxi_disp)
{
struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp;

uint32_t args[4] = { 0, disp->video_layer, 0, 0 };
uint32_t args[4] = { disp->screen_i, disp->video_layer, 0, 0 };
ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args);
}

Expand Down Expand Up @@ -261,7 +282,7 @@ static int sunxi_disp_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y,
disp->osd_info.scn_win.width = min_nz(width, surface->rgba.dirty.x1) - surface->rgba.dirty.x0;
disp->osd_info.scn_win.height = min_nz(height, surface->rgba.dirty.y1) - surface->rgba.dirty.y0;

uint32_t args[4] = { 0, disp->osd_layer, (unsigned long)(&disp->osd_info), 0 };
uint32_t args[4] = { disp->screen_i, disp->osd_layer, (unsigned long)(&disp->osd_info), 0 };
ioctl(disp->fd, DISP_CMD_LAYER_SET_PARA, args);

ioctl(disp->fd, DISP_CMD_LAYER_OPEN, args);
Expand All @@ -273,6 +294,6 @@ static void sunxi_disp_close_osd_layer(struct sunxi_disp *sunxi_disp)
{
struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp;

uint32_t args[4] = { 0, disp->osd_layer, 0, 0 };
uint32_t args[4] = { disp->screen_i, disp->osd_layer, 0, 0 };
ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args);
}
2 changes: 1 addition & 1 deletion sunxi_disp.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct sunxi_disp
void (*close_osd_layer)(struct sunxi_disp *sunxi_disp);
};

struct sunxi_disp *sunxi_disp_open(int osd_enabled);
struct sunxi_disp *sunxi_disp_open(int screen_i, int osd_enabled);
struct sunxi_disp *sunxi_disp2_open(int osd_enabled);
struct sunxi_disp *sunxi_disp1_5_open(int osd_enabled);

Expand Down
3 changes: 2 additions & 1 deletion vdpau_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ typedef struct
{
cedrus_t *cedrus;
Display *display;
int screen;
int screen; // X screen
VdpPreemptionCallback *preemption_callback;
void *preemption_callback_context;
int fd;
int g2d_fd;
int osd_enabled;
int g2d_enabled;
int screen_i; // sunxi disp screen
} device_ctx_t;

typedef struct
Expand Down