Skip to content

Commit

Permalink
Move server/cursor properties to shared memory for interprocess rende…
Browse files Browse the repository at this point in the history
…rer access.

This change is needed to move renderer from X server process to activity's JVM process.
  • Loading branch information
twaik committed Dec 22, 2024
1 parent 5c5b151 commit e3c26f7
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 24 deletions.
114 changes: 94 additions & 20 deletions app/src/main/cpp/lorie/InitOutput.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ from The Open Group.
#include <dri3.h>
#include <sys/mman.h>
#include <busfault.h>
#include <linux/ashmem.h>
#include "scrnintstr.h"
#include "servermd.h"
#include "fb.h"
Expand Down Expand Up @@ -98,8 +99,9 @@ typedef struct {
OsTimerPtr fpsTimer;

Bool cursorMoved;
int eventFd;
int eventFd, stateFd;

struct lorie_shared_server_state* state;
struct {
AHardwareBuffer* buffer;
Bool locked;
Expand All @@ -111,13 +113,60 @@ typedef struct {
JavaVM* vm;
JNIEnv* env;
Bool dri3;
} lorieScreenInfo, *lorieScreenInfoPtr;
} lorieScreenInfo;

ScreenPtr pScreenPtr;
static lorieScreenInfo lorieScreen = { .root.width = 1280, .root.height = 1024, .dri3 = TRUE };
static lorieScreenInfoPtr pvfb = &lorieScreen;
static lorieScreenInfo lorieScreen = { .root.width = 1280, .root.height = 1024, .dri3 = TRUE }, *pvfb = &lorieScreen;
static char *xstartup = NULL;

#pragma clang diagnostic push
#pragma ide diagnostic ignored "UnreachableCallsOfFunction"
static int create_shmem_region(char const* name, size_t size)
{
int fd = memfd_create("Xlorie", MFD_CLOEXEC|MFD_ALLOW_SEALING);
if (fd) {
ftruncate (fd, size);
return fd;
}

fd = open("/dev/ashmem", O_RDWR);
if (fd < 0)
return fd;

char name_buffer[ASHMEM_NAME_LEN] = {0};
strncpy(name_buffer, name, sizeof(name_buffer));
name_buffer[sizeof(name_buffer)-1] = 0;

int ret = ioctl(fd, ASHMEM_SET_NAME, name_buffer);
if (ret < 0) goto error;

ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0) goto error;

return fd;
error:
close(fd);
return ret;
}
#pragma clang diagnostic pop

__attribute((constructor())) static void initSharedServerState() {
pthread_mutexattr_t mutex_attr;
if (-1 == (lorieScreen.stateFd = create_shmem_region("xserver", sizeof(*lorieScreen.state)))) {
dprintf(2, "FATAL: Failed to allocate server state.\n");
_exit(1);
}

if (!(lorieScreen.state = mmap(NULL, sizeof(*lorieScreen.state), PROT_READ|PROT_WRITE, MAP_SHARED, lorieScreen.stateFd, 0))) {
dprintf(2, "FATAL: Failed to map server state.\n");
_exit(1);
}

pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&lorieScreen.state->lock, &mutex_attr);
}

static Bool TrueNoop() { return TRUE; }
static Bool FalseNoop() { return FALSE; }
static void VoidNoop() {}
Expand Down Expand Up @@ -261,12 +310,23 @@ static RRModePtr lorieCvt(int width, int height, int framerate) {
return mode;
}

static Bool resetRootCursor(unused ClientPtr pClient, unused void *closure) {
CursorVisible = TRUE;
pScreenPtr->DisplayCursor(lorieMouse, pScreenPtr, NullCursor);
pScreenPtr->DisplayCursor(lorieMouse, pScreenPtr, rootCursor);
return TRUE;
}

static void lorieMoveCursor(unused DeviceIntPtr pDev, unused ScreenPtr pScr, int x, int y) {
pthread_mutex_lock(&pvfb->state->lock);
pvfb->state->cursor.x = x;
pvfb->state->cursor.y = y;
renderer_set_cursor_coordinates(x, y);
pvfb->cursorMoved = TRUE;
pthread_mutex_unlock(&pvfb->state->lock);
}

static void lorieConvertCursor(CursorPtr pCurs, CARD32 *data) {
static void lorieConvertCursor(CursorPtr pCurs, uint32_t *data) {
CursorBitsPtr bits = pCurs->bits;
if (bits->argb) {
for (int i = 0; i < bits->width * bits->height; i++) {
Expand All @@ -275,7 +335,7 @@ static void lorieConvertCursor(CursorPtr pCurs, CARD32 *data) {
data[i] = (p & 0xFF000000) | ((p & 0x00FF0000) >> 16) | (p & 0x0000FF00) | ((p & 0x000000FF) << 16);
}
} else {
CARD32 d, fg, bg, *p;
uint32_t d, fg, bg, *p;
int x, y, stride, i, bit;

p = data;
Expand All @@ -295,13 +355,27 @@ static void lorieConvertCursor(CursorPtr pCurs, CARD32 *data) {

static void lorieSetCursor(unused DeviceIntPtr pDev, unused ScreenPtr pScr, CursorPtr pCurs, int x0, int y0) {
CursorBitsPtr bits = pCurs ? pCurs->bits : NULL;
if (pCurs && bits) {
CARD32 data[bits->width * bits->height * 4];
if (pCurs && (pCurs->bits->width >= 512 || pCurs->bits->height >= 512)) {
// We do not have enough memory allocated for such a big cursor, let's display default "X" cursor
QueueWorkProc(resetRootCursor, NULL, NULL);
return;
}

lorieConvertCursor(pCurs, data);
renderer_update_cursor(bits->width, bits->height, bits->xhot, bits->yhot, data);
} else
pthread_mutex_lock(&pvfb->state->lock);
if (pCurs && bits) {
pvfb->state->cursor.xhot = bits->xhot;
pvfb->state->cursor.yhot = bits->yhot;
pvfb->state->cursor.width = bits->width;
pvfb->state->cursor.height = bits->height;
lorieConvertCursor(pCurs, pvfb->state->cursor.bits);
renderer_update_cursor(bits->width, bits->height, bits->xhot, bits->yhot, pvfb->state->cursor.bits);
} else {
pvfb->state->cursor.xhot = pvfb->state->cursor.yhot = 0;
pvfb->state->cursor.width = pvfb->state->cursor.height = 0;
renderer_update_cursor(0, 0, 0, 0, NULL);
}
pvfb->state->cursor.updated = true;
pthread_mutex_unlock(&pvfb->state->lock);

if (x0 >= 0 && y0 >= 0)
lorieMoveCursor(NULL, NULL, x0, y0);
Expand Down Expand Up @@ -437,7 +511,7 @@ static inline Bool loriePixmapLock(PixmapPtr pixmap) {

static Bool lorieRedraw(__unused ClientPtr pClient, __unused void *closure) {
if (renderer_should_redraw() && RegionNotEmpty(DamageRegion(pvfb->damage))) {
int redrawn = FALSE;;
int redrawn = FALSE;

loriePixmapUnlock(pScreenPtr->devPrivate);
redrawn = renderer_redraw(pvfb->env, pvfb->root.flip);
Expand Down Expand Up @@ -471,7 +545,11 @@ static Bool lorieCreateScreenResources(ScreenPtr pScreen) {

DamageRegister(&(*pScreen->GetScreenPixmap)(pScreen)->drawable, pvfb->damage);
pvfb->fpsTimer = TimerSet(NULL, 0, 5000, lorieFramecounter, pScreen);

pthread_mutex_lock(&pvfb->state->lock);
lorieUpdateBuffer();
pthread_mutex_unlock(&pvfb->state->lock);

pvfb->ready = true;

return TRUE;
Expand All @@ -493,7 +571,10 @@ lorieRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, unused CARD
pvfb->root.height = pScreen->height = height;
pScreen->mmWidth = ((double) (width)) * 25.4 / monitorResolution;
pScreen->mmHeight = ((double) (height)) * 25.4 / monitorResolution;

pthread_mutex_lock(&pvfb->state->lock);
lorieUpdateBuffer();
pthread_mutex_unlock(&pvfb->state->lock);

pScreen->ResizeWindow(pScreen->root, 0, 0, width, height, NULL);
DamageEmpty(pvfb->damage);
Expand All @@ -509,7 +590,7 @@ lorieRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, unused CARD
static Bool
lorieRRCrtcSet(unused ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y,
Rotation rotation, int numOutput, RROutputPtr *outputs) {
return (crtc && mode) ? RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs) : FALSE;
return (crtc && mode) ? RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs) : FALSE;
}

static Bool
Expand Down Expand Up @@ -552,13 +633,6 @@ lorieRandRInit(ScreenPtr pScreen) {
return TRUE;
}

static Bool resetRootCursor(unused ClientPtr pClient, unused void *closure) {
CursorVisible = TRUE;
pScreenPtr->DisplayCursor(lorieMouse, pScreenPtr, NullCursor);
pScreenPtr->DisplayCursor(lorieMouse, pScreenPtr, rootCursor);
return TRUE;
}

void lorieTriggerWorkingQueue(void) {
eventfd_write(pvfb->eventFd, 1);
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/cpp/lorie/activity.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/ioctl.h>
Expand Down Expand Up @@ -303,7 +304,6 @@ static void* stderrToLogcatThread(__unused void* cookie) {

__attribute__((constructor)) static void init(void) {
pthread_t t;
if (!strcmp("com.termux.x11", __progname))
pthread_create(&t, NULL, stderrToLogcatThread, NULL);
pthread_create(&t, NULL, stderrToLogcatThread, NULL);
}
#endif
70 changes: 70 additions & 0 deletions app/src/main/cpp/lorie/lorie.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <X11/keysymdef.h>
#include <jni.h>
#include <screenint.h>
#include <sys/socket.h>
#include "linux/input-event-codes.h"

void lorieSetVM(JavaVM* vm);
Expand Down Expand Up @@ -83,6 +84,15 @@ typedef union {
} clipboardSend;
} lorieEvent;

struct lorie_shared_server_state {
pthread_mutex_t lock; // initialized at X server side.
struct {
uint32_t x, y, xhot, yhot, width, height;
uint32_t bits[512*512]; // 1 megabyte should be enough for any cursor up to 512x512
uint8_t updated;
} cursor;
};

static int android_to_linux_keycode[304] = {
[ 4 /* ANDROID_KEYCODE_BACK */] = KEY_ESC,
[ 7 /* ANDROID_KEYCODE_0 */] = KEY_0,
Expand Down Expand Up @@ -227,3 +237,63 @@ static int android_to_linux_keycode[304] = {
[ 208 /* ANDROID_KEYCODE_CALENDAR */] = KEY_CALENDAR,
[ 210 /* ANDROID_KEYCODE_CALCULATOR */] = KEY_CALC,
};

__always_inline static inline int ancil_send_fd(int sock, int fd)
{
char nothing = '!';
struct iovec nothing_ptr = { .iov_base = &nothing, .iov_len = 1 };

struct {
struct cmsghdr align;
int fd[1];
} ancillary_data_buffer;

struct msghdr message_header = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &nothing_ptr,
.msg_iovlen = 1,
.msg_flags = 0,
.msg_control = &ancillary_data_buffer,
.msg_controllen = sizeof(struct cmsghdr) + sizeof(int)
};

struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message_header);
cmsg->cmsg_len = message_header.msg_controllen; // sizeof(int);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
((int*) CMSG_DATA(cmsg))[0] = fd;

return sendmsg(sock, &message_header, 0) >= 0 ? 0 : -1;
}

__always_inline static inline int ancil_recv_fd(int sock)
{
char nothing = '!';
struct iovec nothing_ptr = { .iov_base = &nothing, .iov_len = 1 };

struct {
struct cmsghdr align;
int fd[1];
} ancillary_data_buffer;

struct msghdr message_header = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &nothing_ptr,
.msg_iovlen = 1,
.msg_flags = 0,
.msg_control = &ancillary_data_buffer,
.msg_controllen = sizeof(struct cmsghdr) + sizeof(int)
};

struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message_header);
cmsg->cmsg_len = message_header.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
((int*) CMSG_DATA(cmsg))[0] = -1;

if (recvmsg(sock, &message_header, 0) < 0) return -1;

return ((int*) CMSG_DATA(cmsg))[0];
}
6 changes: 5 additions & 1 deletion app/src/main/cpp/recipes/xserver.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ add_library(Xlorie SHARED
"libxcvt/lib/libxcvt.c"
"lorie/shm/shmem.c"
"lorie/cmdentrypoint.c"
"lorie/activity.c"
"lorie/clipboard.c"
"lorie/dri3.c"
"lorie/InitOutput.c"
Expand All @@ -279,3 +278,8 @@ target_link_libraries(Xlorie "-Wl,--whole-archive" ${XSERVER_LIBS} "-Wl,--no-who
target_compile_options(Xlorie PRIVATE ${compile_options})
target_apply_patch(Xlorie "${CMAKE_CURRENT_SOURCE_DIR}/xserver" "${CMAKE_CURRENT_SOURCE_DIR}/patches/xserver.patch")
target_apply_patch(Xlorie "${CMAKE_CURRENT_SOURCE_DIR}/libepoxy" "${CMAKE_CURRENT_SOURCE_DIR}/patches/libepoxy.patch")

add_library(lorie SHARED "lorie/activity.c")
target_include_directories(lorie PRIVATE ${inc})
target_link_options(lorie PRIVATE "-Wl,--as-needed" "-Wl,--no-undefined" "-fvisibility=hidden")
target_link_libraries(lorie android log EGL GLESv2)
2 changes: 1 addition & 1 deletion app/src/main/java/com/termux/x11/LorieView.java
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,6 @@ public boolean commitText(CharSequence text, int newCursorPosition) {
public native void sendTextEvent(byte[] text);

static {
System.loadLibrary("Xlorie");
System.loadLibrary("lorie");
}
}

0 comments on commit e3c26f7

Please sign in to comment.