mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Custom sizes with XRandR (#25)
* xserver dummy with RandR. * update. * remove screen configurations from xorg. * screen size cannot be nil anymore. * use predefined screen configurations. * use screen configurations. * fix error. * remove comment.
This commit is contained in:
parent
bfabee12e2
commit
f8b128e1e9
41
Dockerfile
41
Dockerfile
@ -1,3 +1,33 @@
|
||||
#
|
||||
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
|
||||
#
|
||||
FROM debian:bullseye-slim as xserver-xorg-video-dummy
|
||||
|
||||
WORKDIR /usr/local/src
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN set -eux; \
|
||||
cp /etc/apt/sources.list /etc/apt/sources.list~; \
|
||||
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list; \
|
||||
cat /etc/apt/sources.list~ >> /etc/apt/sources.list; \
|
||||
apt-get update; \
|
||||
apt-get install -y dpkg-dev git; \
|
||||
apt-get build-dep -y xserver-xorg-video-dummy; \
|
||||
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
|
||||
#
|
||||
# clean up
|
||||
apt-get clean -y; \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||
|
||||
COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
|
||||
|
||||
RUN set -eux; \
|
||||
cd xserver-xorg-video-dummy; \
|
||||
patch -p1 < /tmp/xdummy-randr.patch; \
|
||||
bash ./autogen.sh; \
|
||||
make; \
|
||||
make install;
|
||||
|
||||
#
|
||||
# Stage 1: Build.
|
||||
#
|
||||
@ -12,6 +42,10 @@ RUN set -eux; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
||||
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
||||
# install libxcvt-dev (not available in debian:bullseye)
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb ./libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||
#
|
||||
# clean up
|
||||
apt-get clean -y; \
|
||||
@ -57,6 +91,10 @@ RUN set -eux; \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-pulseaudio; \
|
||||
# install libxcvt0 (not available in debian:bullseye)
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||
rm ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||
#
|
||||
# create a non-root user
|
||||
groupadd --gid $USER_GID $USERNAME; \
|
||||
@ -95,6 +133,9 @@ RUN set -eux; \
|
||||
apt-get clean -y; \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||
|
||||
# replace version
|
||||
COPY --from=xserver-xorg-video-dummy /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
|
||||
|
||||
#
|
||||
# copy runtime configs
|
||||
COPY --chown=neko:neko runtime/.Xresources /home/$USERNAME/.Xresources
|
||||
|
@ -1,6 +1,36 @@
|
||||
ARG UBUNTU_RELEASE=20.04
|
||||
ARG CUDA_VERSION=11.2.2
|
||||
|
||||
#
|
||||
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
|
||||
#
|
||||
FROM debian:bullseye-slim as xserver-xorg-video-dummy
|
||||
|
||||
WORKDIR /usr/local/src
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN set -eux; \
|
||||
cp /etc/apt/sources.list /etc/apt/sources.list~; \
|
||||
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list; \
|
||||
cat /etc/apt/sources.list~ >> /etc/apt/sources.list; \
|
||||
apt-get update; \
|
||||
apt-get install -y dpkg-dev git; \
|
||||
apt-get build-dep -y xserver-xorg-video-dummy; \
|
||||
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
|
||||
#
|
||||
# clean up
|
||||
apt-get clean -y; \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||
|
||||
COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
|
||||
|
||||
RUN set -eux; \
|
||||
cd xserver-xorg-video-dummy; \
|
||||
patch -p1 < /tmp/xdummy-randr.patch; \
|
||||
bash ./autogen.sh; \
|
||||
make; \
|
||||
make install;
|
||||
|
||||
#
|
||||
# Stage 1: Build.
|
||||
#
|
||||
@ -15,6 +45,10 @@ RUN set -eux; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
||||
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
||||
# install libxcvt-dev (not available in debian:bullseye)
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb ./libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||
#
|
||||
# clean up
|
||||
apt-get clean -y; \
|
||||
@ -73,6 +107,10 @@ RUN set -eux; \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-pulseaudio; \
|
||||
# install libxcvt0 (not available in debian:bullseye)
|
||||
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||
rm ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||
#
|
||||
# create a non-root user
|
||||
groupadd --gid $USER_GID $USERNAME; \
|
||||
@ -111,6 +149,9 @@ RUN set -eux; \
|
||||
apt-get clean -y; \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||
|
||||
# replace version
|
||||
COPY --from=xserver-xorg-video-dummy /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
|
||||
|
||||
#
|
||||
# Install and configure Vulkan manually
|
||||
RUN if [ "${UBUNTU_RELEASE}" = "18.04" ]; then apt-get update && apt-get install --no-install-recommends -y vulkan-utils; else apt-get update && apt-get install --no-install-recommends -y vulkan-tools; fi && \
|
||||
|
@ -20,12 +20,11 @@ type ScreenConfigurationPayload struct {
|
||||
func (h *RoomHandler) screenConfiguration(w http.ResponseWriter, r *http.Request) error {
|
||||
size := h.desktop.GetScreenSize()
|
||||
|
||||
if size == nil {
|
||||
return utils.HttpInternalServerError().WithInternalMsg("unable to get screen configuration")
|
||||
}
|
||||
|
||||
payload := ScreenConfigurationPayload(*size)
|
||||
return utils.HttpSuccess(w, payload)
|
||||
return utils.HttpSuccess(w, ScreenConfigurationPayload{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: size.Rate,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.Request) error {
|
||||
@ -34,30 +33,37 @@ func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.R
|
||||
return err
|
||||
}
|
||||
|
||||
size := types.ScreenSize(*data)
|
||||
if err := h.desktop.SetScreenSize(size); err != nil {
|
||||
size, err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||
Width: data.Width,
|
||||
Height: data.Height,
|
||||
Rate: data.Rate,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return utils.HttpUnprocessableEntity("cannot set screen size").WithInternalErr(err)
|
||||
}
|
||||
|
||||
payload := message.ScreenSize(*data)
|
||||
h.sessions.Broadcast(event.SCREEN_UPDATED, payload)
|
||||
h.sessions.Broadcast(event.SCREEN_UPDATED, message.ScreenSize{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: size.Rate,
|
||||
})
|
||||
|
||||
return utils.HttpSuccess(w, data)
|
||||
}
|
||||
|
||||
// TODO: remove.
|
||||
func (h *RoomHandler) screenConfigurationsList(w http.ResponseWriter, r *http.Request) error {
|
||||
list := []ScreenConfigurationPayload{}
|
||||
configurations := h.desktop.ScreenConfigurations()
|
||||
|
||||
ScreenConfigurations := h.desktop.ScreenConfigurations()
|
||||
for _, size := range ScreenConfigurations {
|
||||
for _, fps := range size.Rates {
|
||||
list := make([]ScreenConfigurationPayload, 0, len(configurations))
|
||||
for _, conf := range configurations {
|
||||
list = append(list, ScreenConfigurationPayload{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: fps,
|
||||
Width: conf.Width,
|
||||
Height: conf.Height,
|
||||
Rate: conf.Rate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return utils.HttpSuccess(w, list)
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCt
|
||||
}
|
||||
|
||||
screen := desktop.GetScreenSize()
|
||||
pipeline, err := pipelineConf.GetPipeline(*screen)
|
||||
pipeline, err := pipelineConf.GetPipeline(screen)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ func (manager *DesktopManagerCtx) Start() {
|
||||
|
||||
xorg.GetScreenConfigurations()
|
||||
|
||||
err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
|
||||
width, height, rate, err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
|
||||
manager.logger.Err(err).
|
||||
Str("screen_size", fmt.Sprintf("%dx%d@%d", manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)).
|
||||
Str("screen_size", fmt.Sprintf("%dx%d@%d", width, height, rate)).
|
||||
Msgf("setting initial screen size")
|
||||
|
||||
go xevent.EventLoop(manager.config.Display)
|
||||
|
@ -66,11 +66,26 @@ func (manager *DesktopManagerCtx) ResetKeys() {
|
||||
xorg.ResetKeys()
|
||||
}
|
||||
|
||||
func (manager *DesktopManagerCtx) ScreenConfigurations() map[int]types.ScreenConfiguration {
|
||||
return xorg.ScreenConfigurations
|
||||
func (manager *DesktopManagerCtx) ScreenConfigurations() []types.ScreenSize {
|
||||
var configs []types.ScreenSize
|
||||
for _, size := range xorg.ScreenConfigurations {
|
||||
for _, fps := range size.Rates {
|
||||
// filter out all irrelevant rates
|
||||
if fps > 60 || (fps > 30 && fps%10 != 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
configs = append(configs, types.ScreenSize{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: fps,
|
||||
})
|
||||
}
|
||||
}
|
||||
return configs
|
||||
}
|
||||
|
||||
func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) error {
|
||||
func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) (types.ScreenSize, error) {
|
||||
mu.Lock()
|
||||
manager.emmiter.Emit("before_screen_size_change")
|
||||
|
||||
@ -79,10 +94,15 @@ func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) error {
|
||||
mu.Unlock()
|
||||
}()
|
||||
|
||||
return xorg.ChangeScreenSize(size.Width, size.Height, size.Rate)
|
||||
w, h, r, err := xorg.ChangeScreenSize(size.Width, size.Height, size.Rate)
|
||||
return types.ScreenSize{
|
||||
Width: w,
|
||||
Height: h,
|
||||
Rate: r,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (manager *DesktopManagerCtx) GetScreenSize() *types.ScreenSize {
|
||||
func (manager *DesktopManagerCtx) GetScreenSize() types.ScreenSize {
|
||||
return xorg.GetScreenSize()
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,20 @@ func (h *MessageHandlerCtx) screenSet(session types.Session, payload *message.Sc
|
||||
return errors.New("is not the admin")
|
||||
}
|
||||
|
||||
data := types.ScreenSize(*payload)
|
||||
if err := h.desktop.SetScreenSize(data); err != nil {
|
||||
size, err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||
Width: payload.Width,
|
||||
Height: payload.Height,
|
||||
Rate: payload.Rate,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.sessions.Broadcast(event.SCREEN_UPDATED, payload)
|
||||
h.sessions.Broadcast(event.SCREEN_UPDATED, message.ScreenSize{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: size.Rate,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
@ -25,8 +23,10 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
||||
}
|
||||
|
||||
size := h.desktop.GetScreenSize()
|
||||
if size == nil {
|
||||
return errors.New("could not get screen size")
|
||||
screenSize := message.ScreenSize{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: size.Rate,
|
||||
}
|
||||
|
||||
sessions := map[string]message.SessionData{}
|
||||
@ -44,7 +44,7 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
||||
message.SystemInit{
|
||||
SessionId: session.ID(),
|
||||
ControlHost: controlHost,
|
||||
ScreenSize: message.ScreenSize(*size),
|
||||
ScreenSize: screenSize,
|
||||
Sessions: sessions,
|
||||
Settings: h.sessions.Settings(),
|
||||
ScreencastEnabled: h.capture.Screencast().Enabled(),
|
||||
@ -57,22 +57,22 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
||||
}
|
||||
|
||||
func (h *MessageHandlerCtx) systemAdmin(session types.Session) error {
|
||||
screenSizesList := []message.ScreenSize{}
|
||||
for _, size := range h.desktop.ScreenConfigurations() {
|
||||
for _, rate := range size.Rates {
|
||||
screenSizesList = append(screenSizesList, message.ScreenSize{
|
||||
Width: size.Width,
|
||||
Height: size.Height,
|
||||
Rate: rate,
|
||||
configurations := h.desktop.ScreenConfigurations()
|
||||
|
||||
list := make([]message.ScreenSize, 0, len(configurations))
|
||||
for _, conf := range configurations {
|
||||
list = append(list, message.ScreenSize{
|
||||
Width: conf.Width,
|
||||
Height: conf.Height,
|
||||
Rate: conf.Rate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
broadcast := h.capture.Broadcast()
|
||||
session.Send(
|
||||
event.SYSTEM_ADMIN,
|
||||
message.SystemAdmin{
|
||||
ScreenSizesList: screenSizesList,
|
||||
ScreenSizesList: list, // TODO: remove
|
||||
BroadcastStatus: message.BroadcastStatus{
|
||||
IsActive: broadcast.Started(),
|
||||
URL: broadcast.Url(),
|
||||
|
@ -188,16 +188,13 @@ func (config *VideoConfig) GetPipeline(screen ScreenSize) (string, error) {
|
||||
}[:], " "), nil
|
||||
}
|
||||
|
||||
func (config *VideoConfig) GetBitrateFn(getScreen func() *ScreenSize) func() (int, error) {
|
||||
func (config *VideoConfig) GetBitrateFn(getScreen func() ScreenSize) func() (int, error) {
|
||||
return func() (int, error) {
|
||||
if config.Bitrate > 0 {
|
||||
return config.Bitrate, nil
|
||||
}
|
||||
|
||||
screen := getScreen()
|
||||
if screen == nil {
|
||||
return 0, fmt.Errorf("screen is nil")
|
||||
}
|
||||
|
||||
values := map[string]any{
|
||||
"width": screen.Width,
|
||||
|
@ -19,12 +19,6 @@ type ScreenSize struct {
|
||||
Rate int16
|
||||
}
|
||||
|
||||
type ScreenConfiguration struct {
|
||||
Width int
|
||||
Height int
|
||||
Rates map[int]int16
|
||||
}
|
||||
|
||||
type KeyboardModifiers struct {
|
||||
NumLock *bool
|
||||
CapsLock *bool
|
||||
@ -57,9 +51,9 @@ type DesktopManager interface {
|
||||
ButtonPress(code uint32) error
|
||||
KeyPress(codes ...uint32) error
|
||||
ResetKeys()
|
||||
ScreenConfigurations() map[int]ScreenConfiguration
|
||||
SetScreenSize(ScreenSize) error
|
||||
GetScreenSize() *ScreenSize
|
||||
ScreenConfigurations() []ScreenSize
|
||||
SetScreenSize(ScreenSize) (ScreenSize, error)
|
||||
GetScreenSize() ScreenSize
|
||||
SetKeyboardMap(KeyboardMap) error
|
||||
GetKeyboardMap() (*KeyboardMap, error)
|
||||
SetKeyboardModifiers(mod KeyboardModifiers)
|
||||
|
148
pkg/xorg/xorg.c
148
pkg/xorg/xorg.c
@ -229,6 +229,82 @@ void XKey(KeySym keysym, int down) {
|
||||
XSync(display, 0);
|
||||
}
|
||||
|
||||
Status XSetScreenConfiguration(int width, int height, short *rate) {
|
||||
Display *display = getXDisplay();
|
||||
Window root = RootWindow(display, 0);
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, root);
|
||||
|
||||
XRRScreenSize *xrrs;
|
||||
int num_sizes;
|
||||
xrrs = XRRConfigSizes(conf, &num_sizes);
|
||||
|
||||
int size_index = -1;
|
||||
for (int i = 0; i < num_sizes; i++) {
|
||||
if (xrrs[i].width == width && xrrs[i].height == height) {
|
||||
size_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we cannot find the size
|
||||
if (size_index == -1) {
|
||||
return RRSetConfigFailed;
|
||||
}
|
||||
|
||||
short current_rate = 0;
|
||||
if (rate != NULL) {
|
||||
short *rates;
|
||||
int num_rates;
|
||||
rates = XRRConfigRates(conf, size_index, &num_rates);
|
||||
|
||||
// try to find the nearest rate
|
||||
short nearest_rate = 0;
|
||||
float diff = 0;
|
||||
for (int i = 0; i < num_rates; i++) {
|
||||
if (nearest_rate == 0 || abs(rates[i] - *rate) < diff) {
|
||||
nearest_rate = rates[i];
|
||||
diff = abs(rates[i] - *rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest_rate != 0 && diff < 10) {
|
||||
current_rate = nearest_rate;
|
||||
}
|
||||
|
||||
*rate = current_rate;
|
||||
}
|
||||
|
||||
Status status;
|
||||
status = XRRSetScreenConfigAndRate(display, conf, root, size_index, RR_Rotate_0, current_rate, CurrentTime);
|
||||
|
||||
XRRFreeScreenConfigInfo(conf);
|
||||
return status;
|
||||
}
|
||||
|
||||
void XGetScreenConfiguration(int *width, int *height, short *rate) {
|
||||
Display *display = getXDisplay();
|
||||
Window root = RootWindow(display, 0);
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, root);
|
||||
|
||||
Rotation current_rotation;
|
||||
SizeID current_size_id = XRRConfigCurrentConfiguration(conf, ¤t_rotation);
|
||||
|
||||
XRRScreenSize *xrrs;
|
||||
int num_sizes;
|
||||
xrrs = XRRConfigSizes(conf, &num_sizes);
|
||||
|
||||
// if we cannot find the size
|
||||
if (current_size_id >= num_sizes) {
|
||||
return;
|
||||
}
|
||||
|
||||
*width = xrrs[current_size_id].width;
|
||||
*height = xrrs[current_size_id].height;
|
||||
*rate = XRRConfigCurrentRate(conf);
|
||||
|
||||
XRRFreeScreenConfigInfo(conf);
|
||||
}
|
||||
|
||||
void XGetScreenConfigurations() {
|
||||
Display *display = getXDisplay();
|
||||
Window root = RootWindow(display, 0);
|
||||
@ -248,23 +324,71 @@ void XGetScreenConfigurations() {
|
||||
}
|
||||
}
|
||||
|
||||
void XSetScreenConfiguration(int index, short rate) {
|
||||
// Inspired by https://github.com/raboof/xrandr/blob/master/xrandr.c
|
||||
void XCreateScreenMode(int width, int height, short rate) {
|
||||
Display *display = getXDisplay();
|
||||
Window root = RootWindow(display, 0);
|
||||
XRRSetScreenConfigAndRate(display, XRRGetScreenInfo(display, root), root, index, RR_Rotate_0, rate, CurrentTime);
|
||||
|
||||
char name[128];
|
||||
XRRModeInfo mode;
|
||||
mode = XCreateScreenModeInfo(width, height, rate);
|
||||
|
||||
snprintf(name, sizeof name, "%dx%d_%d", width, height, rate);
|
||||
mode.nameLength = strlen(name);
|
||||
mode.name = name;
|
||||
|
||||
// create new mode
|
||||
XRRCreateMode(display, root, &mode);
|
||||
XSync(display, 0);
|
||||
|
||||
// find newly created mode in resources
|
||||
RRMode mode_id;
|
||||
XRRScreenResources *resources = XRRGetScreenResources(display, root);
|
||||
for (int i = 0; i < resources->nmode; ++i) {
|
||||
if (strcmp(resources->modes[i].name, mode.name) == 0) {
|
||||
mode_id = resources->modes[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add new mode to all outputs
|
||||
for (int i = 0; i < resources->noutput; ++i) {
|
||||
XRRAddOutputMode(display, resources->outputs[i], mode_id);
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(resources);
|
||||
}
|
||||
|
||||
int XGetScreenSize() {
|
||||
Display *display = getXDisplay();
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
||||
Rotation original_rotation;
|
||||
return XRRConfigCurrentConfiguration(conf, &original_rotation);
|
||||
}
|
||||
// Inspired by https://fossies.org/linux/xwayland/hw/xwayland/xwayland-cvt.c
|
||||
XRRModeInfo XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) {
|
||||
XRRModeInfo modeinfo;
|
||||
memset(&modeinfo, 0, sizeof modeinfo);
|
||||
|
||||
short XGetScreenRate() {
|
||||
Display *display = getXDisplay();
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
||||
return XRRConfigCurrentRate(conf);
|
||||
#ifdef _LIBCVT_H_
|
||||
struct libxcvt_mode_info *mode_info;
|
||||
|
||||
// get screen mode from libxcvt, if available
|
||||
mode_info = libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, false, false);
|
||||
|
||||
modeinfo.width = mode_info->hdisplay;
|
||||
modeinfo.height = mode_info->vdisplay;
|
||||
modeinfo.dotClock = mode_info->dot_clock * 1000;
|
||||
modeinfo.hSyncStart = mode_info->hsync_start;
|
||||
modeinfo.hSyncEnd = mode_info->hsync_end;
|
||||
modeinfo.hTotal = mode_info->htotal;
|
||||
modeinfo.vSyncStart = mode_info->vsync_start;
|
||||
modeinfo.vSyncEnd = mode_info->vsync_end;
|
||||
modeinfo.vTotal = mode_info->vtotal;
|
||||
modeinfo.modeFlags = mode_info->mode_flags;
|
||||
|
||||
free(mode_info);
|
||||
#else
|
||||
// fallback to a simple mode without refresh rate
|
||||
modeinfo.width = hdisplay;
|
||||
modeinfo.height = vdisplay;
|
||||
#endif
|
||||
|
||||
return modeinfo;
|
||||
}
|
||||
|
||||
void XSetKeyboardModifier(int mod, int on) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package xorg
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes
|
||||
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes -lxcvt
|
||||
|
||||
#include "xorg.h"
|
||||
*/
|
||||
@ -27,7 +27,13 @@ const (
|
||||
KbdModNumLock KbdMod = 16
|
||||
)
|
||||
|
||||
var ScreenConfigurations = make(map[int]types.ScreenConfiguration)
|
||||
type ScreenConfiguration struct {
|
||||
Width int
|
||||
Height int
|
||||
Rates map[int]int16
|
||||
}
|
||||
|
||||
var ScreenConfigurations = make(map[int]ScreenConfiguration)
|
||||
|
||||
var debounce_button = make(map[uint32]time.Time)
|
||||
var debounce_key = make(map[uint32]time.Time)
|
||||
@ -178,40 +184,46 @@ func CheckKeys(duration time.Duration) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeScreenSize(width int, height int, rate int16) error {
|
||||
// set screen configuration, create new one if not exists
|
||||
func ChangeScreenSize(width int, height int, rate int16) (int, int, int16, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for index, size := range ScreenConfigurations {
|
||||
if size.Width == width && size.Height == height {
|
||||
for _, fps := range size.Rates {
|
||||
if rate == fps {
|
||||
C.XSetScreenConfiguration(C.int(index), C.short(fps))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// round width and height to 8
|
||||
width = width - (width % 8)
|
||||
height = height - (height % 8)
|
||||
|
||||
// convert variables to C types
|
||||
c_width, c_height, c_rate := C.int(width), C.int(height), C.short(rate)
|
||||
|
||||
// if screen configuration already exists, just set it
|
||||
if status := C.XSetScreenConfiguration(c_width, c_height, &c_rate); status == C.RRSetConfigSuccess {
|
||||
return width, height, int16(c_rate), nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
|
||||
// create new screen configuration
|
||||
C.XCreateScreenMode(c_width, c_height, c_rate)
|
||||
|
||||
// screen configuration should exist now, set it
|
||||
if status := C.XSetScreenConfiguration(c_width, c_height, &c_rate); status == C.RRSetConfigSuccess {
|
||||
return width, height, int16(c_rate), nil
|
||||
}
|
||||
|
||||
return 0, 0, 0, fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
|
||||
}
|
||||
|
||||
func GetScreenSize() *types.ScreenSize {
|
||||
func GetScreenSize() types.ScreenSize {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
index := int(C.XGetScreenSize())
|
||||
rate := int16(C.XGetScreenRate())
|
||||
c_width, c_height, c_rate := C.int(0), C.int(0), C.short(0)
|
||||
C.XGetScreenConfiguration(&c_width, &c_height, &c_rate)
|
||||
|
||||
if conf, ok := ScreenConfigurations[index]; ok {
|
||||
return &types.ScreenSize{
|
||||
Width: conf.Width,
|
||||
Height: conf.Height,
|
||||
Rate: rate,
|
||||
return types.ScreenSize{
|
||||
Width: int(c_width),
|
||||
Height: int(c_height),
|
||||
Rate: int16(c_rate),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetKeyboardModifier(mod KbdMod, active bool) {
|
||||
@ -300,7 +312,7 @@ func GetScreenshotImage() *image.RGBA {
|
||||
|
||||
//export goCreateScreenSize
|
||||
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
||||
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
||||
ScreenConfigurations[int(index)] = ScreenConfiguration{
|
||||
Width: int(width),
|
||||
Height: int(height),
|
||||
Rates: make(map[int]int16),
|
||||
@ -309,12 +321,5 @@ func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mh
|
||||
|
||||
//export goSetScreenRates
|
||||
func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
|
||||
rate := int16(rateC)
|
||||
|
||||
// filter out all irrelevant rates
|
||||
if rate > 60 || (rate > 30 && rate%10 != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
ScreenConfigurations[int(index)].Rates[int(rate_index)] = rate
|
||||
ScreenConfigurations[int(index)].Rates[int(rate_index)] = int16(rateC)
|
||||
}
|
||||
|
@ -7,6 +7,11 @@
|
||||
#include <X11/extensions/XTest.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// for computing xrandr modelines at runtime
|
||||
#include <libxcvt/libxcvt.h>
|
||||
|
||||
extern void goCreateScreenSize(int index, int width, int height, int mwidth, int mheight);
|
||||
extern void goSetScreenRates(int index, int rate_index, short rate);
|
||||
@ -31,10 +36,11 @@ static KeyCode XKeyEntryGet(KeySym keysym);
|
||||
static KeyCode XkbKeysymToKeycode(Display *dpy, KeySym keysym);
|
||||
void XKey(KeySym keysym, int down);
|
||||
|
||||
Status XSetScreenConfiguration(int width, int height, short *rate);
|
||||
void XGetScreenConfiguration(int *width, int *height, short *rate);
|
||||
void XGetScreenConfigurations();
|
||||
void XSetScreenConfiguration(int index, short rate);
|
||||
int XGetScreenSize();
|
||||
short XGetScreenRate();
|
||||
void XCreateScreenMode(int width, int height, short rate);
|
||||
XRRModeInfo XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh);
|
||||
|
||||
void XSetKeyboardModifier(int mod, int on);
|
||||
char XGetKeyboardModifiers();
|
||||
|
316
runtime/xdummy-randr.patch
Normal file
316
runtime/xdummy-randr.patch
Normal file
@ -0,0 +1,316 @@
|
||||
diff --git a/src/dummy.h b/src/dummy.h
|
||||
index c3fdd6e..9c74f56 100644
|
||||
--- a/src/dummy.h
|
||||
+++ b/src/dummy.h
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include "compat-api.h"
|
||||
|
||||
+#define DUMMY_MAX_SCREENS 4
|
||||
+
|
||||
/* Supported chipsets */
|
||||
typedef enum {
|
||||
DUMMY_CHIP
|
||||
@@ -72,6 +74,12 @@ typedef struct dummyRec
|
||||
pointer* FBBase;
|
||||
Bool (*CreateWindow)() ; /* wrapped CreateWindow */
|
||||
Bool prop;
|
||||
+ /* XRANDR support begin */
|
||||
+ int num_screens;
|
||||
+ struct _xf86Crtc *paCrtcs[DUMMY_MAX_SCREENS];
|
||||
+ struct _xf86Output *paOutputs[DUMMY_MAX_SCREENS];
|
||||
+ int connected_outputs;
|
||||
+ /* XRANDR support end */
|
||||
} DUMMYRec, *DUMMYPtr;
|
||||
|
||||
/* The privates of the DUMMY driver */
|
||||
diff --git a/src/dummy_driver.c b/src/dummy_driver.c
|
||||
index 2656602..069e330 100644
|
||||
--- a/src/dummy_driver.c
|
||||
+++ b/src/dummy_driver.c
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <X11/extensions/Xv.h>
|
||||
#endif
|
||||
|
||||
+#include "xf86Crtc.h"
|
||||
+
|
||||
/*
|
||||
* Driver data structures.
|
||||
*/
|
||||
@@ -141,6 +143,219 @@ static XF86ModuleVersionInfo dummyVersRec =
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
+
|
||||
+/************************
|
||||
+ * XRANDR support begin *
|
||||
+ ************************/
|
||||
+
|
||||
+static Bool dummy_config_resize(ScrnInfoPtr pScrn, int cw, int ch);
|
||||
+static Bool DUMMYAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height);
|
||||
+
|
||||
+static const xf86CrtcConfigFuncsRec DUMMYCrtcConfigFuncs = {
|
||||
+ .resize = dummy_config_resize
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+dummy_crtc_dpms(xf86CrtcPtr crtc, int mode)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static Bool
|
||||
+dummy_crtc_lock (xf86CrtcPtr crtc)
|
||||
+{
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static Bool
|
||||
+dummy_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
|
||||
+ DisplayModePtr adjusted_mode)
|
||||
+{
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dummy_crtc_stub (xf86CrtcPtr crtc)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dummy_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
|
||||
+ CARD16 *green, CARD16 *blue, int size)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void *
|
||||
+dummy_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dummy_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
|
||||
+ DisplayModePtr adjusted_mode, int x, int y)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static const xf86CrtcFuncsRec DUMMYCrtcFuncs = {
|
||||
+ .dpms = dummy_crtc_dpms,
|
||||
+ .save = NULL, /* These two are never called by the server. */
|
||||
+ .restore = NULL,
|
||||
+ .lock = dummy_crtc_lock,
|
||||
+ .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
|
||||
+ .mode_fixup = dummy_crtc_mode_fixup,
|
||||
+ .prepare = dummy_crtc_stub,
|
||||
+ .mode_set = dummy_crtc_mode_set,
|
||||
+ .commit = dummy_crtc_stub,
|
||||
+ .gamma_set = dummy_crtc_gamma_set,
|
||||
+ .shadow_allocate = dummy_crtc_shadow_allocate,
|
||||
+ .shadow_create = NULL, /* These two should not be invoked if allocate
|
||||
+ returns NULL. */
|
||||
+ .shadow_destroy = NULL,
|
||||
+ .set_cursor_colors = NULL,
|
||||
+ .set_cursor_position = NULL,
|
||||
+ .show_cursor = NULL,
|
||||
+ .hide_cursor = NULL,
|
||||
+ .load_cursor_argb = NULL,
|
||||
+ .destroy = dummy_crtc_stub
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+dummy_output_stub (xf86OutputPtr output)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dummy_output_dpms (xf86OutputPtr output, int mode)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dummy_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
|
||||
+{
|
||||
+ return MODE_OK;
|
||||
+}
|
||||
+
|
||||
+static Bool
|
||||
+dummy_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
|
||||
+ DisplayModePtr adjusted_mode)
|
||||
+{
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dummy_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
|
||||
+ DisplayModePtr adjusted_mode)
|
||||
+{
|
||||
+ DUMMYPtr dPtr = DUMMYPTR(output->scrn);
|
||||
+ int index = (int64_t)output->driver_private;
|
||||
+
|
||||
+ /* set to connected at first mode set */
|
||||
+ dPtr->connected_outputs |= 1 << index;
|
||||
+}
|
||||
+
|
||||
+/* The first virtual monitor is always connected. Others only after setting its
|
||||
+ * mode */
|
||||
+static xf86OutputStatus
|
||||
+dummy_output_detect (xf86OutputPtr output)
|
||||
+{
|
||||
+ DUMMYPtr dPtr = DUMMYPTR(output->scrn);
|
||||
+ int index = (int64_t)output->driver_private;
|
||||
+
|
||||
+ if (dPtr->connected_outputs & (1 << index))
|
||||
+ return XF86OutputStatusConnected;
|
||||
+ else
|
||||
+ return XF86OutputStatusDisconnected;
|
||||
+}
|
||||
+
|
||||
+static DisplayModePtr
|
||||
+dummy_output_get_modes (xf86OutputPtr output)
|
||||
+{
|
||||
+ DisplayModePtr pModes = NULL, pMode, pModeSrc;
|
||||
+
|
||||
+ /* copy modes from config */
|
||||
+ for (pModeSrc = output->scrn->modes; pModeSrc; pModeSrc = pModeSrc->next)
|
||||
+ {
|
||||
+ pMode = xnfcalloc(1, sizeof(DisplayModeRec));
|
||||
+ memcpy(pMode, pModeSrc, sizeof(DisplayModeRec));
|
||||
+ pMode->next = NULL;
|
||||
+ pMode->prev = NULL;
|
||||
+ pMode->name = strdup(pModeSrc->name);
|
||||
+ pModes = xf86ModesAdd(pModes, pMode);
|
||||
+ if (pModeSrc->next == output->scrn->modes)
|
||||
+ break;
|
||||
+ }
|
||||
+ return pModes;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const xf86OutputFuncsRec DUMMYOutputFuncs = {
|
||||
+ .create_resources = dummy_output_stub,
|
||||
+ .dpms = dummy_output_dpms,
|
||||
+ .save = NULL, /* These two are never called by the server. */
|
||||
+ .restore = NULL,
|
||||
+ .mode_valid = dummy_output_mode_valid,
|
||||
+ .mode_fixup = dummy_output_mode_fixup,
|
||||
+ .prepare = dummy_output_stub,
|
||||
+ .commit = dummy_output_stub,
|
||||
+ .mode_set = dummy_output_mode_set,
|
||||
+ .detect = dummy_output_detect,
|
||||
+ .get_modes = dummy_output_get_modes,
|
||||
+#ifdef RANDR_12_INTERFACE
|
||||
+ .set_property = NULL,
|
||||
+#endif
|
||||
+ .destroy = dummy_output_stub
|
||||
+};
|
||||
+
|
||||
+static Bool
|
||||
+dummy_config_resize(ScrnInfoPtr pScrn, int cw, int ch)
|
||||
+{
|
||||
+ if (!pScrn->vtSema) {
|
||||
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
+ "We do not own the active VT, exiting.\n");
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ return DUMMYAdjustScreenPixmap(pScrn, cw, ch);
|
||||
+}
|
||||
+
|
||||
+Bool DUMMYAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height)
|
||||
+{
|
||||
+ ScreenPtr pScreen = pScrn->pScreen;
|
||||
+ PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen);
|
||||
+ DUMMYPtr dPtr = DUMMYPTR(pScrn);
|
||||
+ uint64_t cbLine = (width * xf86GetBppFromDepth(pScrn, pScrn->depth) / 8 + 3) & ~3;
|
||||
+ int displayWidth = cbLine * 8 / xf86GetBppFromDepth(pScrn, pScrn->depth);
|
||||
+
|
||||
+ if ( width == pScrn->virtualX
|
||||
+ && height == pScrn->virtualY
|
||||
+ && displayWidth == pScrn->displayWidth)
|
||||
+ return TRUE;
|
||||
+ if (!pPixmap) {
|
||||
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
+ "Failed to get the screen pixmap.\n");
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ if (cbLine > UINT32_MAX || cbLine * height >= pScrn->videoRam * 1024)
|
||||
+ {
|
||||
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
+ "Unable to set up a virtual screen size of %dx%d with %d Kb of video memory available. Please increase the video memory size.\n",
|
||||
+ width, height, pScrn->videoRam);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ pScreen->ModifyPixmapHeader(pPixmap, width, height,
|
||||
+ pScrn->depth, xf86GetBppFromDepth(pScrn, pScrn->depth), cbLine,
|
||||
+ pPixmap->devPrivate.ptr);
|
||||
+ pScrn->virtualX = width;
|
||||
+ pScrn->virtualY = height;
|
||||
+ pScrn->displayWidth = displayWidth;
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+/**********************
|
||||
+ * XRANDR support end *
|
||||
+ **********************/
|
||||
+
|
||||
/*
|
||||
* This is the module init data.
|
||||
* Its name has to be the driver name followed by ModuleData
|
||||
@@ -568,6 +783,56 @@ DUMMYScreenInit(SCREEN_INIT_ARGS_DECL)
|
||||
|
||||
xf86SetBlackWhitePixels(pScreen);
|
||||
|
||||
+ /* initialize XRANDR */
|
||||
+ xf86CrtcConfigInit(pScrn, &DUMMYCrtcConfigFuncs);
|
||||
+ /* FIXME */
|
||||
+ dPtr->num_screens = DUMMY_MAX_SCREENS;
|
||||
+
|
||||
+ for (int i=0; i < dPtr->num_screens; i++) {
|
||||
+ char szOutput[256];
|
||||
+
|
||||
+ dPtr->paCrtcs[i] = xf86CrtcCreate(pScrn, &DUMMYCrtcFuncs);
|
||||
+ dPtr->paCrtcs[i]->driver_private = (void *)(uintptr_t)i;
|
||||
+
|
||||
+ /* Set up our virtual outputs. */
|
||||
+ snprintf(szOutput, sizeof(szOutput), "DUMMY%u", i);
|
||||
+ dPtr->paOutputs[i] = xf86OutputCreate(pScrn, &DUMMYOutputFuncs,
|
||||
+ szOutput);
|
||||
+
|
||||
+
|
||||
+ xf86OutputUseScreenMonitor(dPtr->paOutputs[i], FALSE);
|
||||
+ dPtr->paOutputs[i]->possible_crtcs = 1 << i;
|
||||
+ dPtr->paOutputs[i]->possible_clones = 0;
|
||||
+ dPtr->paOutputs[i]->driver_private = (void *)(uintptr_t)i;
|
||||
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Created crtc (%p) and output %s (%p)\n",
|
||||
+ (void *)dPtr->paCrtcs[i], szOutput,
|
||||
+ (void *)dPtr->paOutputs[i]);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ /* bitmask */
|
||||
+ dPtr->connected_outputs = 1;
|
||||
+
|
||||
+ xf86CrtcSetSizeRange(pScrn, 64, 64, DUMMY_MAX_WIDTH, DUMMY_MAX_HEIGHT);
|
||||
+
|
||||
+
|
||||
+ /* Now create our initial CRTC/output configuration. */
|
||||
+ if (!xf86InitialConfiguration(pScrn, TRUE)) {
|
||||
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
|
||||
+ return (FALSE);
|
||||
+ }
|
||||
+
|
||||
+ /* Initialise randr 1.2 mode-setting functions and set first mode.
|
||||
+ * Note that the mode won't be usable until the server has resized the
|
||||
+ * framebuffer to something reasonable. */
|
||||
+ if (!xf86CrtcScreenInit(pScreen)) {
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ if (!xf86SetDesiredModes(pScrn)) {
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ /* XRANDR initialization end */
|
||||
+
|
||||
#ifdef USE_DGA
|
||||
DUMMYDGAInit(pScreen);
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user