diff --git a/server.c b/server.c index 0ad2c92..39e0247 100644 --- a/server.c +++ b/server.c @@ -13,6 +13,17 @@ #include +struct drm_nvidia_gem_map_offset_params { + uint32_t handle; /* IN Handle to gem object */ + uint32_t __pad; + + uint64_t offset; /* OUT Fake offset */ +}; +#define DRM_NVIDIA_GEM_MAP_OFFSET 0x0a +#define DRM_IOCTL_NVIDIA_GEM_MAP_OFFSET \ + DRM_IOWR((DRM_COMMAND_BASE + DRM_NVIDIA_GEM_MAP_OFFSET), \ + struct drm_nvidia_gem_map_offset_params) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) /* 10 frames per second (if we can) */ #define PICTURE_TIMEOUT (1.0/10.0) @@ -55,6 +66,30 @@ 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) { + 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++) + { + 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; + if (offset < height*width) { + memcpy(buff + offset*4, nv_stripe_buf + i*4, 4); + } + } +} + struct vnc_xkb { struct xkb_context *ctx; struct xkb_keymap *map; @@ -258,6 +293,8 @@ 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; @@ -373,6 +410,8 @@ int main(int argc, const char **argv) 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; @@ -394,16 +433,18 @@ 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, "nothing") == 0) { - 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)) { + else if (strcmp(drm_ver->name, "nvidia-drm") == 0) { + convert_func = &convert_nv_stripe; + vblank_func = &drm_wait_vblank_noop; + struct drm_nvidia_gem_map_offset_params mmap_arg; + memset(&mmap_arg, 0, sizeof(mmap_arg)); + mmap_arg.handle = open_arg.handle; + if (ioctl_err = drmIoctl(drmfd, DRM_IOCTL_NVIDIA_GEM_MAP_OFFSET, &mmap_arg)) { fprintf(stderr, "DRM ioctl error %d on line %d\n", ioctl_err, __LINE__); goto cleanup; } mmap_size = open_arg.size; - mmap_offset = mreq.offset; + mmap_offset = mmap_arg.offset; } else { fprintf(stderr, "Unimplemented drm driver\n"); @@ -442,10 +483,10 @@ int main(int argc, const char **argv) long usec; while (rfbIsActive(server)) { if (server->clientHead && TimeToTakePicture()) { - drm_wait_vblank(drmfd); + vblank_func(drmfd); // still tearing memcpy(buf2, mapped, buflen); - convert_bgrx_to_rgb(buf2, fb->width, fb->height, buf); + convert_func(buf2, fb->width, fb->height, buf); rfbMarkRectAsModified(server, 0, 0, fb->width, fb->height); } usec = server->deferUpdateTime*1000;