u
This commit is contained in:
parent
a5fbfa7a59
commit
87c91c0c5a
1 changed files with 131 additions and 92 deletions
191
server.c
191
server.c
|
@ -9,6 +9,7 @@
|
|||
#include <libdrm/amdgpu_drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -55,28 +56,91 @@ static void convert_bgrx_to_rgb(const char* in, int width, int height, char* buf
|
|||
}
|
||||
}
|
||||
|
||||
#define XSTRIPE 16
|
||||
#define YSTRIPE 128
|
||||
char *nv_stripe_buf = NULL;
|
||||
static void convert_nv_stripe(const char* in, int width, int height, char* buff) {
|
||||
char *kms_convert_buf = NULL;
|
||||
size_t kms_convert_buf_len = 0;
|
||||
static inline void convert_kmsbuf(const int XSTRIPE, const int YSTRIPE, const char* in, int width, int height, char* buff) {
|
||||
if (width % XSTRIPE) {
|
||||
return;
|
||||
}
|
||||
if (!nv_stripe_buf) nv_stripe_buf = malloc(width * height * 4);
|
||||
convert_bgrx_to_rgb(in, width, height, nv_stripe_buf);
|
||||
for (int i = 0; i < height*width; i++)
|
||||
if (kms_convert_buf_len < width * height * 4) {
|
||||
if (kms_convert_buf) free(kms_convert_buf);
|
||||
kms_convert_buf = malloc(width * height * 4);
|
||||
kms_convert_buf_len = width * height * 4;
|
||||
}
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int sno = i / (XSTRIPE * YSTRIPE);
|
||||
int ord = i % (XSTRIPE * YSTRIPE);
|
||||
int base_x = sno % (width / XSTRIPE) * XSTRIPE;
|
||||
int base_y = sno / (width / XSTRIPE) * YSTRIPE;
|
||||
int sx = ord % XSTRIPE + base_x;
|
||||
int sy = ord / XSTRIPE + base_y;
|
||||
int offset = sy * width + sx;
|
||||
int sno = (x / XSTRIPE) + (y / YSTRIPE) * (width / XSTRIPE);
|
||||
int ord = (x % XSTRIPE) + (y % YSTRIPE) * XSTRIPE;
|
||||
int offset = sno * XSTRIPE * YSTRIPE + ord;
|
||||
if (offset < height*width) {
|
||||
memcpy(buff + offset*4, nv_stripe_buf + i*4, 4);
|
||||
memcpy(kms_convert_buf + (x+y*width)*4, in + offset*4, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
convert_bgrx_to_rgb(kms_convert_buf, width, height, buff);
|
||||
}
|
||||
|
||||
static size_t get_extra_mmap_bytes(const int XSTRIPE, const int YSTRIPE, int width, int height) {
|
||||
if (height % YSTRIPE) {
|
||||
int offset_max = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int sno = (x / XSTRIPE) + (y / YSTRIPE) * (width / XSTRIPE);
|
||||
int ord = (x % XSTRIPE) + (y % YSTRIPE) * XSTRIPE;
|
||||
int offset = sno * XSTRIPE * YSTRIPE + ord;
|
||||
if (offset > offset_max) {
|
||||
offset_max = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset_max * 4 - height*width * 4;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#define XSTRIPE_INTEL 128
|
||||
#define YSTRIPE_INTEL 8
|
||||
#define XSTRIPE_NVIDIA 16
|
||||
#define YSTRIPE_NVIDIA 128
|
||||
#define XSTRIPE_INTEL 16
|
||||
#define YSTRIPE_INTEL 128
|
||||
static size_t get_nvidia_extra_mmap_bytes(int width, int height) {
|
||||
return get_extra_mmap_bytes(XSTRIPE_NVIDIA, YSTRIPE_NVIDIA, width, height);
|
||||
}
|
||||
static size_t get_intel_extra_mmap_bytes(int width, int height) {
|
||||
return get_extra_mmap_bytes(XSTRIPE_NVIDIA, YSTRIPE_NVIDIA, width, height);
|
||||
}
|
||||
static void convert_nvidia_kmsbuf(const char* in, int width, int height, char* buff) {
|
||||
convert_kmsbuf(XSTRIPE_INTEL, YSTRIPE_INTEL, in, width, height, buff);
|
||||
}
|
||||
static void convert_intel_kmsbuf(const char* in, int width, int height, char* buff) {
|
||||
convert_kmsbuf(XSTRIPE_INTEL, YSTRIPE_INTEL, in, width, height, buff);
|
||||
}
|
||||
|
||||
struct vnc_drm_attr {
|
||||
void (*sync_start)(int);
|
||||
void (*sync_end)(int);
|
||||
void (*convert)(const char*, int, int, char*);
|
||||
};
|
||||
|
||||
static inline void drm_sync(int drmfd, uint64_t flags) {
|
||||
int ioctl_err;
|
||||
struct dma_buf_sync sync = {
|
||||
.flags = flags,
|
||||
};
|
||||
if (ioctl_err = ioctl(drmfd, DMA_BUF_IOCTL_SYNC, &sync))
|
||||
fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__);
|
||||
}
|
||||
static void drm_sync_start(int drmfd) {
|
||||
drm_sync(drmfd, DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
|
||||
}
|
||||
static void drm_sync_end(int drmfd) {
|
||||
drm_sync(drmfd, DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
|
||||
}
|
||||
static void drm_sync_noop(int drmfd) {
|
||||
}
|
||||
|
||||
struct vnc_xkb {
|
||||
|
@ -282,18 +346,6 @@ static void rfb_ptr_hook(int mask, int screen_x, int screen_y, rfbClientPtr cl)
|
|||
}
|
||||
|
||||
|
||||
static void drm_wait_vblank_noop(int x) {
|
||||
}
|
||||
static void drm_wait_vblank(int drmfd) {
|
||||
int ioctl_err;
|
||||
union drm_wait_vblank vbl;
|
||||
memset(&vbl, 0, sizeof(vbl));
|
||||
vbl.request.type = DRM_VBLANK_RELATIVE;
|
||||
vbl.request.sequence = 1;
|
||||
if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_WAIT_VBLANK, &vbl))
|
||||
fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
|
@ -305,6 +357,7 @@ int main(int argc, const char **argv)
|
|||
|
||||
const char *card = argv[1];
|
||||
const int drmfd = open(card, O_RDONLY);
|
||||
int primefd = -1;
|
||||
if (drmfd < 0) {
|
||||
fprintf(stderr, "card %s open failed: %s\n", card, strerror(errno));
|
||||
return 1;
|
||||
|
@ -383,6 +436,29 @@ int main(int argc, const char **argv)
|
|||
}
|
||||
|
||||
int ioctl_err = 0;
|
||||
|
||||
printf("drm driver is %s\n", drm_ver->name);
|
||||
char *mapped = NULL;
|
||||
struct vnc_drm_attr funcs = {
|
||||
.sync_start = &drm_sync_start,
|
||||
.sync_end = &drm_sync_end,
|
||||
.convert = &convert_bgrx_to_rgb,
|
||||
};
|
||||
err = drmPrimeHandleToFD(drmfd, fb->handle, O_RDWR, &primefd);
|
||||
if (err < 0 || primefd < 0) {
|
||||
perror("Failed to get PRIME fd from framebuffer handle");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int mmap_fd = primefd;
|
||||
size_t mmap_size = fb->width * fb->height * 32 / 8;
|
||||
off_t mmap_offset = 0;
|
||||
|
||||
if (strcmp(drm_ver->name, "i915") == 0) {
|
||||
funcs.convert = &convert_intel_kmsbuf;
|
||||
mmap_size += get_intel_extra_mmap_bytes(fb->width, fb->height);
|
||||
}
|
||||
else if (strcmp(drm_ver->name, "amdgpu") == 0) {
|
||||
struct drm_gem_flink flink;
|
||||
flink.handle = fb->handle;
|
||||
if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_GEM_FLINK, &flink)) {
|
||||
|
@ -391,27 +467,11 @@ int main(int argc, const char **argv)
|
|||
}
|
||||
struct drm_gem_open open_arg;
|
||||
open_arg.name = flink.name;
|
||||
printf("global name = %d\n", flink.name);
|
||||
if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_GEM_OPEN, &open_arg)) {
|
||||
fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__);
|
||||
goto cleanup;
|
||||
}
|
||||
off_t mmap_offset = 0;
|
||||
size_t mmap_size = 0;
|
||||
printf("drm driver is %s\n", drm_ver->name);
|
||||
char *mapped = NULL;
|
||||
void (*convert_func)(const char*, int, int, char*) = &convert_bgrx_to_rgb;
|
||||
void (*vblank_func)(int) = &drm_wait_vblank;
|
||||
if (strcmp(drm_ver->name, "i915") == 0) {
|
||||
struct drm_i915_gem_mmap_gtt mmap_arg;
|
||||
mmap_arg.handle = open_arg.handle;
|
||||
if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg)) {
|
||||
fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__);
|
||||
goto cleanup;
|
||||
}
|
||||
mmap_size = open_arg.size;
|
||||
mmap_offset = mmap_arg.offset;
|
||||
}
|
||||
else if (strcmp(drm_ver->name, "amdgpu") == 0) {
|
||||
union drm_amdgpu_gem_mmap mmap_arg;
|
||||
memset(&mmap_arg, 0, sizeof(mmap_arg));
|
||||
mmap_arg.in.handle = open_arg.handle;
|
||||
|
@ -422,33 +482,23 @@ int main(int argc, const char **argv)
|
|||
mmap_size = open_arg.size;
|
||||
mmap_offset = mmap_arg.out.addr_ptr;
|
||||
}
|
||||
else {
|
||||
if (strcmp(drm_ver->name, "nvidia-drm") == 0) {
|
||||
else if (strcmp(drm_ver->name, "nvidia-drm") == 0) {
|
||||
// quirky and slow
|
||||
convert_func = &convert_nv_stripe;
|
||||
vblank_func = &drm_wait_vblank_noop;
|
||||
funcs.convert = &convert_nvidia_kmsbuf;
|
||||
mmap_size += get_nvidia_extra_mmap_bytes(fb->width, fb->height);
|
||||
}
|
||||
else if (strcmp(drm_ver->name, "vmwgfx") == 0 || strcmp(drm_ver->name, "vboxvideo") == 0 || strcmp(drm_ver->name, "virtio_gpu") == 0) {
|
||||
// virgl does not work
|
||||
vblank_func = &drm_wait_vblank_noop;
|
||||
//funcs.sync_start = &drm_sync_noop;
|
||||
//funcs.sync_end = &drm_sync_noop;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Untested drm driver, use at your own risk!\n");
|
||||
}
|
||||
|
||||
struct drm_mode_map_dumb mreq;
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.handle = open_arg.handle;
|
||||
if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) {
|
||||
fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__);
|
||||
goto cleanup;
|
||||
}
|
||||
mmap_size = open_arg.size;
|
||||
mmap_offset = mreq.offset;
|
||||
}
|
||||
if (!mapped) {
|
||||
printf("mapping with size = %d, offset = %d, drmfd = %d\n", mmap_size, mmap_offset, drmfd);
|
||||
mapped = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, drmfd, mmap_offset);
|
||||
printf("mapping with size = %d, offset = %d, fd = %d\n", mmap_size, mmap_offset, mmap_fd);
|
||||
mapped = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, mmap_fd, mmap_offset);
|
||||
if (mapped == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
goto cleanup;
|
||||
|
@ -458,8 +508,6 @@ int main(int argc, const char **argv)
|
|||
size_t buflen = fb->width * fb->height * 32 / 8;
|
||||
char *buf = malloc(buflen);
|
||||
memset(buf, 0, buflen);
|
||||
char *buf2 = malloc(buflen);
|
||||
memset(buf2, 0, buflen);
|
||||
|
||||
resolution.x = fb->width;
|
||||
resolution.y = fb->height;
|
||||
|
@ -479,23 +527,13 @@ int main(int argc, const char **argv)
|
|||
rfbRunEventLoop(server,-1,TRUE);
|
||||
while (rfbIsActive(server)) {
|
||||
if (server->clientHead && TimeToTakePicture()) {
|
||||
vblank_func(drmfd);
|
||||
// still tearing
|
||||
memcpy(buf2, mapped, buflen);
|
||||
convert_func(buf2, fb->width, fb->height, buf);
|
||||
funcs.sync_start(primefd);
|
||||
funcs.convert(mapped, fb->width, fb->height, buf);
|
||||
funcs.sync_end(primefd);
|
||||
rfbMarkRectAsModified(server, 0, 0, fb->width, fb->height);
|
||||
}
|
||||
}
|
||||
|
||||
if (drm_ver != NULL) drmFreeVersion(drm_ver);
|
||||
if (fb != NULL) drmModeFreeFB(fb);
|
||||
if (uinput_fd > 0) {
|
||||
ioctl(uinput_fd, UI_DEV_DESTROY);
|
||||
close(uinput_fd);
|
||||
}
|
||||
close(drmfd);
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (drm_ver != NULL) drmFreeVersion(drm_ver);
|
||||
if (fb != NULL) drmModeFreeFB(fb);
|
||||
|
@ -503,6 +541,7 @@ int main(int argc, const char **argv)
|
|||
ioctl(uinput_fd, UI_DEV_DESTROY);
|
||||
close(uinput_fd);
|
||||
}
|
||||
if (primefd > 0) close(primefd);
|
||||
close(drmfd);
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue