Re-format using clang-format
parent
13c52175d2
commit
80b1f3cb4c
|
@ -28,19 +28,19 @@ struct draw {
|
||||||
struct nvnc_fb* fb;
|
struct nvnc_fb* fb;
|
||||||
};
|
};
|
||||||
|
|
||||||
void on_pointer_event(struct nvnc_client *client, uint16_t x, uint16_t y,
|
void on_pointer_event(struct nvnc_client* client, uint16_t x, uint16_t y,
|
||||||
enum nvnc_button_mask buttons)
|
enum nvnc_button_mask buttons)
|
||||||
{
|
{
|
||||||
if (!(buttons & NVNC_BUTTON_LEFT))
|
if (!(buttons & NVNC_BUTTON_LEFT))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct nvnc *server = nvnc_get_server(client);
|
struct nvnc* server = nvnc_get_server(client);
|
||||||
assert(server);
|
assert(server);
|
||||||
|
|
||||||
struct draw *draw = nvnc_get_userdata(server);
|
struct draw* draw = nvnc_get_userdata(server);
|
||||||
assert(draw);
|
assert(draw);
|
||||||
|
|
||||||
uint32_t *image = nvnc_fb_get_addr(draw->fb);
|
uint32_t* image = nvnc_fb_get_addr(draw->fb);
|
||||||
int width = nvnc_fb_get_width(draw->fb);
|
int width = nvnc_fb_get_width(draw->fb);
|
||||||
int height = nvnc_fb_get_height(draw->fb);
|
int height = nvnc_fb_get_height(draw->fb);
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ void on_pointer_event(struct nvnc_client *client, uint16_t x, uint16_t y,
|
||||||
pixman_region_fini(®ion);
|
pixman_region_fini(®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
struct draw draw;
|
struct draw draw;
|
||||||
|
|
||||||
int width = 500, height = 500;
|
int width = 500, height = 500;
|
||||||
uint32_t format = DRM_FORMAT_RGBX8888;
|
uint32_t format = DRM_FORMAT_RGBX8888;
|
||||||
|
@ -66,7 +66,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
memset(addr, 0xff, width * height * 4);
|
memset(addr, 0xff, width * height * 4);
|
||||||
|
|
||||||
struct nvnc *server = nvnc_open("127.0.0.1", 5900);
|
struct nvnc* server = nvnc_open("127.0.0.1", 5900);
|
||||||
|
|
||||||
nvnc_set_dimensions(server, width, height, format);
|
nvnc_set_dimensions(server, width, height, format);
|
||||||
nvnc_set_name(server, "Draw");
|
nvnc_set_name(server, "Draw");
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
struct nvnc_fb* read_png_file(const char *filename);
|
struct nvnc_fb* read_png_file(const char* filename);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const char *file = argv[1];
|
const char* file = argv[1];
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
printf("Missing argument\n");
|
printf("Missing argument\n");
|
||||||
|
@ -38,7 +38,7 @@ int main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nvnc *server = nvnc_open("127.0.0.1", 5900);
|
struct nvnc* server = nvnc_open("127.0.0.1", 5900);
|
||||||
|
|
||||||
int width = nvnc_fb_get_width(fb);
|
int width = nvnc_fb_get_width(fb);
|
||||||
int height = nvnc_fb_get_height(fb);
|
int height = nvnc_fb_get_height(fb);
|
||||||
|
@ -49,7 +49,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
struct pixman_region16 region;
|
struct pixman_region16 region;
|
||||||
pixman_region_init_rect(®ion, 0, 0, nvnc_fb_get_width(fb),
|
pixman_region_init_rect(®ion, 0, 0, nvnc_fb_get_width(fb),
|
||||||
nvnc_fb_get_height(fb));
|
nvnc_fb_get_height(fb));
|
||||||
nvnc_feed_frame(server, fb, ®ion);
|
nvnc_feed_frame(server, fb, ®ion);
|
||||||
pixman_region_fini(®ion);
|
pixman_region_fini(®ion);
|
||||||
|
|
||||||
|
|
15
include/fb.h
15
include/fb.h
|
@ -4,12 +4,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct nvnc_fb {
|
struct nvnc_fb {
|
||||||
int ref;
|
int ref;
|
||||||
void *addr;
|
void* addr;
|
||||||
size_t size;
|
size_t size;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
uint32_t fourcc_format;
|
uint32_t fourcc_format;
|
||||||
uint64_t fourcc_modifier;
|
uint64_t fourcc_modifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
|
||||||
|
|
|
@ -25,40 +25,41 @@ struct nvnc_fb;
|
||||||
struct pixman_region16;
|
struct pixman_region16;
|
||||||
|
|
||||||
enum nvnc_button_mask {
|
enum nvnc_button_mask {
|
||||||
NVNC_BUTTON_LEFT = 1 << 0,
|
NVNC_BUTTON_LEFT = 1 << 0,
|
||||||
NVNC_BUTTON_MIDDLE = 1 << 1,
|
NVNC_BUTTON_MIDDLE = 1 << 1,
|
||||||
NVNC_BUTTON_RIGHT = 1 << 2,
|
NVNC_BUTTON_RIGHT = 1 << 2,
|
||||||
NVNC_SCROLL_UP = 1 << 3,
|
NVNC_SCROLL_UP = 1 << 3,
|
||||||
NVNC_SCROLL_DOWN = 1 << 4,
|
NVNC_SCROLL_DOWN = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*nvnc_key_fn)(struct nvnc_client*, uint32_t keysym, bool is_pressed);
|
typedef void (*nvnc_key_fn)(struct nvnc_client*, uint32_t keysym,
|
||||||
|
bool is_pressed);
|
||||||
typedef void (*nvnc_pointer_fn)(struct nvnc_client*, uint16_t x, uint16_t y,
|
typedef void (*nvnc_pointer_fn)(struct nvnc_client*, uint16_t x, uint16_t y,
|
||||||
enum nvnc_button_mask);
|
enum nvnc_button_mask);
|
||||||
typedef void (*nvnc_fb_req_fn)(struct nvnc_client*, bool is_incremental,
|
typedef void (*nvnc_fb_req_fn)(struct nvnc_client*, bool is_incremental,
|
||||||
uint16_t x, uint16_t y,
|
uint16_t x, uint16_t y, uint16_t width,
|
||||||
uint16_t width, uint16_t height);
|
uint16_t height);
|
||||||
typedef void (*nvnc_client_fn)(struct nvnc_client*);
|
typedef void (*nvnc_client_fn)(struct nvnc_client*);
|
||||||
typedef void (*nvnc_damage_fn)(struct pixman_region16 *damage, void *userdata);
|
typedef void (*nvnc_damage_fn)(struct pixman_region16* damage, void* userdata);
|
||||||
|
|
||||||
struct nvnc *nvnc_open(const char *addr, uint16_t port);
|
struct nvnc* nvnc_open(const char* addr, uint16_t port);
|
||||||
void nvnc_close(struct nvnc *self);
|
void nvnc_close(struct nvnc* self);
|
||||||
|
|
||||||
void nvnc_set_userdata(void *self, void* userdata);
|
void nvnc_set_userdata(void* self, void* userdata);
|
||||||
void* nvnc_get_userdata(const void *self);
|
void* nvnc_get_userdata(const void* self);
|
||||||
|
|
||||||
struct nvnc *nvnc_get_server(const struct nvnc_client *client);
|
struct nvnc* nvnc_get_server(const struct nvnc_client* client);
|
||||||
|
|
||||||
void nvnc_set_dimensions(struct nvnc *self, uint16_t width, uint16_t height,
|
void nvnc_set_dimensions(struct nvnc* self, uint16_t width, uint16_t height,
|
||||||
uint32_t fourcc_format);
|
uint32_t fourcc_format);
|
||||||
|
|
||||||
void nvnc_set_name(struct nvnc *self, const char *name);
|
void nvnc_set_name(struct nvnc* self, const char* name);
|
||||||
|
|
||||||
void nvnc_set_key_fn(struct nvnc *self, nvnc_key_fn);
|
void nvnc_set_key_fn(struct nvnc* self, nvnc_key_fn);
|
||||||
void nvnc_set_pointer_fn(struct nvnc *self, nvnc_pointer_fn);
|
void nvnc_set_pointer_fn(struct nvnc* self, nvnc_pointer_fn);
|
||||||
void nvnc_set_fb_req_fn(struct nvnc *self, nvnc_fb_req_fn);
|
void nvnc_set_fb_req_fn(struct nvnc* self, nvnc_fb_req_fn);
|
||||||
void nvnc_set_new_client_fn(struct nvnc *self, nvnc_client_fn);
|
void nvnc_set_new_client_fn(struct nvnc* self, nvnc_client_fn);
|
||||||
void nvnc_set_client_cleanup_fn(struct nvnc_client *self, nvnc_client_fn fn);
|
void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn);
|
||||||
|
|
||||||
struct nvnc_fb* nvnc_fb_new(uint16_t width, uint16_t height,
|
struct nvnc_fb* nvnc_fb_new(uint16_t width, uint16_t height,
|
||||||
uint32_t fourcc_format);
|
uint32_t fourcc_format);
|
||||||
|
@ -75,7 +76,7 @@ uint32_t nvnc_fb_get_fourcc_format(const struct nvnc_fb* fb);
|
||||||
* Feed a new frame to the server. The damaged region is sent to clients
|
* Feed a new frame to the server. The damaged region is sent to clients
|
||||||
* immediately.
|
* immediately.
|
||||||
*/
|
*/
|
||||||
int nvnc_feed_frame(struct nvnc *self, struct nvnc_fb* fb,
|
int nvnc_feed_frame(struct nvnc* self, struct nvnc_fb* fb,
|
||||||
const struct pixman_region16* damage);
|
const struct pixman_region16* damage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -84,6 +85,6 @@ int nvnc_feed_frame(struct nvnc *self, struct nvnc_fb* fb,
|
||||||
*
|
*
|
||||||
* This is a utility function that may be used to reduce network traffic.
|
* This is a utility function that may be used to reduce network traffic.
|
||||||
*/
|
*/
|
||||||
int nvnc_check_damage(const struct nvnc_fb *fb0, const struct nvnc_fb *fb1,
|
int nvnc_check_damage(const struct nvnc_fb* fb0, const struct nvnc_fb* fb1,
|
||||||
int x_hint, int y_hint, int width_hint, int height_hint,
|
int x_hint, int y_hint, int width_hint, int height_hint,
|
||||||
nvnc_damage_fn on_check_done, void *userdata);
|
nvnc_damage_fn on_check_done, void* userdata);
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void pixel32_to_cpixel(uint8_t *restrict dst,
|
void pixel32_to_cpixel(uint8_t* restrict dst,
|
||||||
const struct rfb_pixel_format* dst_fmt,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
const uint32_t *restrict src,
|
const uint32_t* restrict src,
|
||||||
const struct rfb_pixel_format* src_fmt,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
size_t bytes_per_cpixel, size_t len);
|
size_t bytes_per_cpixel, size_t len);
|
||||||
|
|
|
@ -5,8 +5,7 @@ struct rfb_pixel_format;
|
||||||
struct pixman_region16;
|
struct pixman_region16;
|
||||||
struct vec;
|
struct vec;
|
||||||
|
|
||||||
int raw_encode_frame(struct vec *dst,
|
int raw_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct nvnc_fb* src,
|
||||||
const struct nvnc_fb *src,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
struct pixman_region16* region);
|
||||||
struct pixman_region16 *region);
|
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
#define RFB_PACKED __attribute__((packed))
|
#define RFB_PACKED __attribute__((packed))
|
||||||
|
|
||||||
enum rfb_security_type {
|
enum rfb_security_type {
|
||||||
RFB_SECURITY_TYPE_INVALID = 0,
|
RFB_SECURITY_TYPE_INVALID = 0,
|
||||||
RFB_SECURITY_TYPE_NONE = 1,
|
RFB_SECURITY_TYPE_NONE = 1,
|
||||||
RFB_SECURITY_TYPE_VNC_AUTH = 2,
|
RFB_SECURITY_TYPE_VNC_AUTH = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum rfb_security_handshake_result {
|
enum rfb_security_handshake_result {
|
||||||
|
@ -57,15 +57,15 @@ enum rfb_encodings {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum rfb_server_to_client_msg_type {
|
enum rfb_server_to_client_msg_type {
|
||||||
RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE = 0,
|
RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE = 0,
|
||||||
RFB_SERVER_TO_CLIENT_SET_COLOUR_MAP_ENTRIES = 1,
|
RFB_SERVER_TO_CLIENT_SET_COLOUR_MAP_ENTRIES = 1,
|
||||||
RFB_SERVER_TO_CLIENT_BELL = 2,
|
RFB_SERVER_TO_CLIENT_BELL = 2,
|
||||||
RFB_SERVER_TO_CLIENT_SERVER_CUT_TEXT = 3,
|
RFB_SERVER_TO_CLIENT_SERVER_CUT_TEXT = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rfb_security_types_msg {
|
struct rfb_security_types_msg {
|
||||||
uint8_t n;
|
uint8_t n;
|
||||||
uint8_t types[1];
|
uint8_t types[1];
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_error_reason {
|
struct rfb_error_reason {
|
||||||
|
@ -96,52 +96,52 @@ struct rfb_server_init_msg {
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_client_set_encodings_msg {
|
struct rfb_client_set_encodings_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t padding;
|
uint8_t padding;
|
||||||
uint16_t n_encodings;
|
uint16_t n_encodings;
|
||||||
int32_t encodings[0];
|
int32_t encodings[0];
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_client_fb_update_req_msg {
|
struct rfb_client_fb_update_req_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t incremental;
|
uint8_t incremental;
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_client_key_event_msg {
|
struct rfb_client_key_event_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t down_flag;
|
uint8_t down_flag;
|
||||||
uint16_t padding;
|
uint16_t padding;
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_client_pointer_event_msg {
|
struct rfb_client_pointer_event_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t button_mask;
|
uint8_t button_mask;
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_client_cut_text_msg {
|
struct rfb_client_cut_text_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t padding[3];
|
uint8_t padding[3];
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
char test[0];
|
char test[0];
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_server_fb_rect {
|
struct rfb_server_fb_rect {
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
int32_t encoding;
|
int32_t encoding;
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
||||||
struct rfb_server_fb_update_msg {
|
struct rfb_server_fb_update_msg {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t padding;
|
uint8_t padding;
|
||||||
uint16_t n_rects;
|
uint16_t n_rects;
|
||||||
} RFB_PACKED;
|
} RFB_PACKED;
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define container_of(ptr, type, member) \
|
#define container_of(ptr, type, member) \
|
||||||
({ \
|
({ \
|
||||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
const typeof(((type*)0)->member)* __mptr = (ptr); \
|
||||||
(type *)( (char *)__mptr - offsetof(type,member) ); \
|
(type*)((char*)__mptr - offsetof(type, member)); \
|
||||||
})
|
})
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct vnc_write_request {
|
||||||
uv_buf_t buffer;
|
uv_buf_t buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
int vnc__write(uv_stream_t *stream, const void *payload, size_t size,
|
int vnc__write(uv_stream_t* stream, const void* payload, size_t size,
|
||||||
uv_write_cb on_done);
|
uv_write_cb on_done);
|
||||||
|
|
||||||
int rfb_pixfmt_from_fourcc(struct rfb_pixel_format *dst, uint32_t src);
|
int rfb_pixfmt_from_fourcc(struct rfb_pixel_format* dst, uint32_t src);
|
||||||
|
|
|
@ -44,30 +44,30 @@ void* vec_append_zero(struct vec* vec, size_t size);
|
||||||
|
|
||||||
static inline void vec_fast_append_8(struct vec* vec, uint8_t value)
|
static inline void vec_fast_append_8(struct vec* vec, uint8_t value)
|
||||||
{
|
{
|
||||||
assert(vec->len < vec->cap);
|
assert(vec->len < vec->cap);
|
||||||
((uint8_t*)vec->data)[vec->len++] = value;
|
((uint8_t*)vec->data)[vec->len++] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void vec_fast_append_32(struct vec* vec, uint32_t value)
|
static inline void vec_fast_append_32(struct vec* vec, uint32_t value)
|
||||||
{
|
{
|
||||||
assert(vec->len + sizeof(value) <= vec->cap);
|
assert(vec->len + sizeof(value) <= vec->cap);
|
||||||
assert(vec->len % sizeof(value) == 0);
|
assert(vec->len % sizeof(value) == 0);
|
||||||
uint32_t* p = (uint32_t*)((uint8_t*)vec->data + vec->len);
|
uint32_t* p = (uint32_t*)((uint8_t*)vec->data + vec->len);
|
||||||
*p = value;
|
*p = value;
|
||||||
vec->len += sizeof(value);
|
vec->len += sizeof(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define vec_for(elem, vec) \
|
#define vec_for(elem, vec) \
|
||||||
for (elem = (vec)->data; \
|
for (elem = (vec)->data; \
|
||||||
((ptrdiff_t)elem - (ptrdiff_t)(vec)->data) < (ptrdiff_t)(vec)->len; \
|
((ptrdiff_t)elem - (ptrdiff_t)(vec)->data) < (ptrdiff_t)(vec)->len;\
|
||||||
++elem)
|
++elem)
|
||||||
|
|
||||||
#define vec_for_tail(elem, vec) \
|
#define vec_for_tail(elem, vec) \
|
||||||
for (elem = (vec)->data, ++elem; \
|
for (elem = (vec)->data, ++elem; \
|
||||||
((ptrdiff_t)elem - (ptrdiff_t)(vec)->data) < (ptrdiff_t)(vec)->len; \
|
((ptrdiff_t)elem - (ptrdiff_t)(vec)->data) < (ptrdiff_t)(vec)->len;\
|
||||||
++elem)
|
++elem)
|
||||||
|
|
||||||
#define vec_for_ptr(elem, vec) \
|
#define vec_for_ptr(elem, vec) \
|
||||||
__typeof__(elem)* ptr_; \
|
__typeof__(elem)* ptr_; \
|
||||||
vec_for(ptr_, vec) \
|
vec_for(ptr_, vec) \
|
||||||
if ((elem = *ptr_))
|
if ((elem = *ptr_))
|
||||||
|
|
|
@ -26,9 +26,8 @@ struct rfb_pixel_format;
|
||||||
struct pixman_region16;
|
struct pixman_region16;
|
||||||
struct vec;
|
struct vec;
|
||||||
|
|
||||||
int zrle_encode_frame(z_stream *zs,
|
int zrle_encode_frame(z_stream* zs, struct vec* dst,
|
||||||
struct vec *dst,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct nvnc_fb* src,
|
||||||
const struct nvnc_fb *src,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
struct pixman_region16* region);
|
||||||
struct pixman_region16 *region);
|
|
||||||
|
|
76
src/damage.c
76
src/damage.c
|
@ -16,27 +16,26 @@
|
||||||
|
|
||||||
struct damage_check {
|
struct damage_check {
|
||||||
uv_work_t work;
|
uv_work_t work;
|
||||||
const struct nvnc_fb *fb0;
|
const struct nvnc_fb* fb0;
|
||||||
const struct nvnc_fb *fb1;
|
const struct nvnc_fb* fb1;
|
||||||
int x_hint;
|
int x_hint;
|
||||||
int y_hint;
|
int y_hint;
|
||||||
int width_hint;
|
int width_hint;
|
||||||
int height_hint;
|
int height_hint;
|
||||||
nvnc_damage_fn on_done;
|
nvnc_damage_fn on_done;
|
||||||
struct pixman_region16 damage;
|
struct pixman_region16 damage;
|
||||||
void *userdata;
|
void* userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool fbs_are_compatible(const struct nvnc_fb *fb0,
|
static bool fbs_are_compatible(const struct nvnc_fb* fb0,
|
||||||
const struct nvnc_fb *fb1)
|
const struct nvnc_fb* fb1)
|
||||||
{
|
{
|
||||||
return fb0->fourcc_format == fb1->fourcc_format
|
return fb0->fourcc_format == fb1->fourcc_format &&
|
||||||
&& fb0->width == fb1->width
|
fb0->width == fb1->width && fb0->height == fb1->height;
|
||||||
&& fb0->height == fb1->height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool are_tiles_equal(const uint32_t* a, const uint32_t* b,
|
static inline bool are_tiles_equal(const uint32_t* a, const uint32_t* b,
|
||||||
int stride, int width, int height)
|
int stride, int width, int height)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < height; ++y)
|
for (int y = 0; y < height; ++y)
|
||||||
if (memcmp(a + y * stride, b + y * stride, width * 4) != 0)
|
if (memcmp(a + y * stride, b + y * stride, width * 4) != 0)
|
||||||
|
@ -46,12 +45,12 @@ static inline bool are_tiles_equal(const uint32_t* a, const uint32_t* b,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TILE_SIDE_LENGTH 32
|
#define TILE_SIDE_LENGTH 32
|
||||||
int check_damage_linear(struct pixman_region16 *damage,
|
int check_damage_linear(struct pixman_region16* damage,
|
||||||
const struct nvnc_fb *fb0, const struct nvnc_fb *fb1,
|
const struct nvnc_fb* fb0, const struct nvnc_fb* fb1,
|
||||||
int x_hint, int y_hint, int width_hint, int height_hint)
|
int x_hint, int y_hint, int width_hint, int height_hint)
|
||||||
{
|
{
|
||||||
uint32_t *b0 = fb0->addr;
|
uint32_t* b0 = fb0->addr;
|
||||||
uint32_t *b1 = fb1->addr;
|
uint32_t* b1 = fb1->addr;
|
||||||
|
|
||||||
int width = fb0->width;
|
int width = fb0->width;
|
||||||
int height = fb0->height;
|
int height = fb0->height;
|
||||||
|
@ -61,9 +60,8 @@ int check_damage_linear(struct pixman_region16 *damage,
|
||||||
|
|
||||||
int x_start = ALIGN_DOWN(x_hint, TILE_SIDE_LENGTH);
|
int x_start = ALIGN_DOWN(x_hint, TILE_SIDE_LENGTH);
|
||||||
int y_start = ALIGN_DOWN(y_hint, TILE_SIDE_LENGTH);
|
int y_start = ALIGN_DOWN(y_hint, TILE_SIDE_LENGTH);
|
||||||
|
|
||||||
for (int y = y_start; y < y_start + height_hint;
|
for (int y = y_start; y < y_start + height_hint; y += TILE_SIDE_LENGTH) {
|
||||||
y += TILE_SIDE_LENGTH) {
|
|
||||||
int tile_height = MIN(TILE_SIDE_LENGTH, height - y);
|
int tile_height = MIN(TILE_SIDE_LENGTH, height - y);
|
||||||
|
|
||||||
for (int x = x_start; x < x_start + width_hint;
|
for (int x = x_start; x < x_start + width_hint;
|
||||||
|
@ -72,12 +70,12 @@ int check_damage_linear(struct pixman_region16 *damage,
|
||||||
|
|
||||||
int offset = x + y * width;
|
int offset = x + y * width;
|
||||||
|
|
||||||
if (are_tiles_equal(b0 + offset, b1 + offset,
|
if (are_tiles_equal(b0 + offset, b1 + offset, width,
|
||||||
width, tile_width, tile_height))
|
tile_width, tile_height))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pixman_region_union_rect(damage, damage, x, y,
|
pixman_region_union_rect(damage, damage, x, y,
|
||||||
tile_width, tile_height);
|
tile_width, tile_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,20 +83,20 @@ int check_damage_linear(struct pixman_region16 *damage,
|
||||||
}
|
}
|
||||||
#undef TILE_SIDE_LENGTH
|
#undef TILE_SIDE_LENGTH
|
||||||
|
|
||||||
void do_damage_check_linear(uv_work_t *work)
|
void do_damage_check_linear(uv_work_t* work)
|
||||||
{
|
{
|
||||||
struct damage_check *check = (void*)work;
|
struct damage_check* check = (void*)work;
|
||||||
|
|
||||||
check_damage_linear(&check->damage, check->fb0, check->fb1,
|
check_damage_linear(&check->damage, check->fb0, check->fb1,
|
||||||
check->x_hint, check->y_hint,
|
check->x_hint, check->y_hint, check->width_hint,
|
||||||
check->width_hint, check->height_hint);
|
check->height_hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_damage_check_done_linear(uv_work_t *work, int status)
|
void on_damage_check_done_linear(uv_work_t* work, int status)
|
||||||
{
|
{
|
||||||
(void)status;
|
(void)status;
|
||||||
|
|
||||||
struct damage_check *check = (void*)work;
|
struct damage_check* check = (void*)work;
|
||||||
|
|
||||||
check->on_done(&check->damage, check->userdata);
|
check->on_done(&check->damage, check->userdata);
|
||||||
|
|
||||||
|
@ -106,14 +104,12 @@ void on_damage_check_done_linear(uv_work_t *work, int status)
|
||||||
free(check);
|
free(check);
|
||||||
}
|
}
|
||||||
|
|
||||||
int check_damage_linear_threaded(const struct nvnc_fb *fb0,
|
int check_damage_linear_threaded(const struct nvnc_fb* fb0,
|
||||||
const struct nvnc_fb *fb1,
|
const struct nvnc_fb* fb1, int x_hint,
|
||||||
int x_hint, int y_hint,
|
int y_hint, int width_hint, int height_hint,
|
||||||
int width_hint, int height_hint,
|
nvnc_damage_fn on_check_done, void* userdata)
|
||||||
nvnc_damage_fn on_check_done,
|
|
||||||
void *userdata)
|
|
||||||
{
|
{
|
||||||
struct damage_check *work = calloc(1, sizeof(*work));
|
struct damage_check* work = calloc(1, sizeof(*work));
|
||||||
if (!work)
|
if (!work)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -129,8 +125,8 @@ int check_damage_linear_threaded(const struct nvnc_fb *fb0,
|
||||||
|
|
||||||
/* TODO: Spread the work into more tasks */
|
/* TODO: Spread the work into more tasks */
|
||||||
int rc = uv_queue_work(uv_default_loop(), &work->work,
|
int rc = uv_queue_work(uv_default_loop(), &work->work,
|
||||||
do_damage_check_linear,
|
do_damage_check_linear,
|
||||||
on_damage_check_done_linear);
|
on_damage_check_done_linear);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
free(work);
|
free(work);
|
||||||
|
|
||||||
|
@ -138,9 +134,9 @@ int check_damage_linear_threaded(const struct nvnc_fb *fb0,
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
int nvnc_check_damage(const struct nvnc_fb *fb0, const struct nvnc_fb *fb1,
|
int nvnc_check_damage(const struct nvnc_fb* fb0, const struct nvnc_fb* fb1,
|
||||||
int x_hint, int y_hint, int width_hint, int height_hint,
|
int x_hint, int y_hint, int width_hint, int height_hint,
|
||||||
nvnc_damage_fn on_check_done, void *userdata)
|
nvnc_damage_fn on_check_done, void* userdata)
|
||||||
{
|
{
|
||||||
if (!fbs_are_compatible(fb0, fb1))
|
if (!fbs_are_compatible(fb0, fb1))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -148,8 +144,8 @@ int nvnc_check_damage(const struct nvnc_fb *fb0, const struct nvnc_fb *fb1,
|
||||||
switch (fb0->fourcc_modifier) {
|
switch (fb0->fourcc_modifier) {
|
||||||
case DRM_FORMAT_MOD_LINEAR:
|
case DRM_FORMAT_MOD_LINEAR:
|
||||||
return check_damage_linear_threaded(fb0, fb1, x_hint, y_hint,
|
return check_damage_linear_threaded(fb0, fb1, x_hint, y_hint,
|
||||||
width_hint, height_hint,
|
width_hint, height_hint,
|
||||||
on_check_done, userdata);
|
on_check_done, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
32
src/pixels.c
32
src/pixels.c
|
@ -18,13 +18,13 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define POPCOUNT(x) __builtin_popcount(x)
|
#define POPCOUNT(x) __builtin_popcount(x)
|
||||||
|
|
||||||
void pixel32_to_cpixel(uint8_t *restrict dst,
|
void pixel32_to_cpixel(uint8_t* restrict dst,
|
||||||
const struct rfb_pixel_format* dst_fmt,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
const uint32_t *restrict src,
|
const uint32_t* restrict src,
|
||||||
const struct rfb_pixel_format* src_fmt,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
size_t bytes_per_cpixel, size_t len)
|
size_t bytes_per_cpixel, size_t len)
|
||||||
{
|
{
|
||||||
assert(src_fmt->true_colour_flag);
|
assert(src_fmt->true_colour_flag);
|
||||||
assert(src_fmt->bits_per_pixel == 32);
|
assert(src_fmt->bits_per_pixel == 32);
|
||||||
|
@ -60,16 +60,16 @@ void pixel32_to_cpixel(uint8_t *restrict dst,
|
||||||
|
|
||||||
uint32_t dst_endian_correction;
|
uint32_t dst_endian_correction;
|
||||||
|
|
||||||
#define CONVERT_PIXELS(cpx, px) \
|
#define CONVERT_PIXELS(cpx, px) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t r, g, b; \
|
uint32_t r, g, b; \
|
||||||
r = ((px >> src_red_shift) & src_red_max) << dst_red_bits \
|
r = ((px >> src_red_shift) & src_red_max) << dst_red_bits \
|
||||||
>> src_red_bits << dst_red_shift; \
|
>> src_red_bits << dst_red_shift; \
|
||||||
g = ((px >> src_green_shift) & src_green_max) << dst_green_bits \
|
g = ((px >> src_green_shift) & src_green_max) << dst_green_bits\
|
||||||
>> src_green_bits << dst_green_shift; \
|
>> src_green_bits << dst_green_shift; \
|
||||||
b = ((px >> src_blue_shift) & src_blue_max) << dst_blue_bits \
|
b = ((px >> src_blue_shift) & src_blue_max) << dst_blue_bits \
|
||||||
>> src_blue_bits << dst_blue_shift; \
|
>> src_blue_bits << dst_blue_shift; \
|
||||||
cpx = r | g | b; \
|
cpx = r | g | b; \
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bytes_per_cpixel) {
|
switch (bytes_per_cpixel) {
|
||||||
|
|
41
src/pngfb.c
41
src/pngfb.c
|
@ -13,21 +13,26 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <libdrm/drm_fourcc.h>
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
struct nvnc_fb* read_png_file(const char *filename) {
|
struct nvnc_fb* read_png_file(const char* filename)
|
||||||
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
png_byte color_type;
|
png_byte color_type;
|
||||||
png_byte bit_depth;
|
png_byte bit_depth;
|
||||||
png_bytep *row_pointers = NULL;
|
png_bytep* row_pointers = NULL;
|
||||||
|
|
||||||
FILE *fp = fopen(filename, "rb");
|
FILE* fp = fopen(filename, "rb");
|
||||||
|
|
||||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
png_structp png =
|
||||||
if(!png) abort();
|
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!png)
|
||||||
|
abort();
|
||||||
|
|
||||||
png_infop info = png_create_info_struct(png);
|
png_infop info = png_create_info_struct(png);
|
||||||
if(!info) abort();
|
if (!info)
|
||||||
|
abort();
|
||||||
|
|
||||||
if(setjmp(png_jmpbuf(png))) abort();
|
if (setjmp(png_jmpbuf(png)))
|
||||||
|
abort();
|
||||||
|
|
||||||
png_init_io(png, fp);
|
png_init_io(png, fp);
|
||||||
|
|
||||||
|
@ -36,32 +41,32 @@ struct nvnc_fb* read_png_file(const char *filename) {
|
||||||
width = png_get_image_width(png, info);
|
width = png_get_image_width(png, info);
|
||||||
height = png_get_image_height(png, info);
|
height = png_get_image_height(png, info);
|
||||||
color_type = png_get_color_type(png, info);
|
color_type = png_get_color_type(png, info);
|
||||||
bit_depth = png_get_bit_depth(png, info);
|
bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
// Read any color_type into 8bit depth, RGBA format.
|
// Read any color_type into 8bit depth, RGBA format.
|
||||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||||
|
|
||||||
if(bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
png_set_strip_16(png);
|
png_set_strip_16(png);
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_PALETTE)
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
png_set_palette_to_rgb(png);
|
png_set_palette_to_rgb(png);
|
||||||
|
|
||||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||||
png_set_expand_gray_1_2_4_to_8(png);
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||||
png_set_tRNS_to_alpha(png);
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
// These color_type don't have an alpha channel then fill it with 0xff.
|
// These color_type don't have an alpha channel then fill it with 0xff.
|
||||||
if(color_type == PNG_COLOR_TYPE_RGB ||
|
if (color_type == PNG_COLOR_TYPE_RGB ||
|
||||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
png_set_gray_to_rgb(png);
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
png_read_update_info(png, info);
|
png_read_update_info(png, info);
|
||||||
|
@ -71,7 +76,7 @@ struct nvnc_fb* read_png_file(const char *filename) {
|
||||||
struct nvnc_fb* fb = nvnc_fb_new(width, height, DRM_FORMAT_ABGR8888);
|
struct nvnc_fb* fb = nvnc_fb_new(width, height, DRM_FORMAT_ABGR8888);
|
||||||
assert(fb);
|
assert(fb);
|
||||||
|
|
||||||
uint8_t *addr = nvnc_fb_get_addr(fb);
|
uint8_t* addr = nvnc_fb_get_addr(fb);
|
||||||
|
|
||||||
row_pointers = malloc(sizeof(png_bytep) * height);
|
row_pointers = malloc(sizeof(png_bytep) * height);
|
||||||
assert(row_pointers);
|
assert(row_pointers);
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
|
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
int raw_encode_box(struct vec *dst, const struct rfb_pixel_format *dst_fmt,
|
int raw_encode_box(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct nvnc_fb *fb,
|
const struct nvnc_fb* fb,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
const struct rfb_pixel_format* src_fmt, int x_start,
|
||||||
int x_start, int y_start, int stride, int width, int height)
|
int y_start, int stride, int width, int height)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
struct rfb_server_fb_rect rect = {
|
struct rfb_server_fb_rect rect = {
|
||||||
.encoding = htonl(RFB_ENCODING_RAW),
|
.encoding = htonl(RFB_ENCODING_RAW),
|
||||||
.x = htons(x_start),
|
.x = htons(x_start),
|
||||||
.y = htons(y_start),
|
.y = htons(y_start),
|
||||||
.width = htons(width),
|
.width = htons(width),
|
||||||
.height = htons(height),
|
.height = htons(height),
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = vec_append(dst, &rect, sizeof(rect));
|
rc = vec_append(dst, &rect, sizeof(rect));
|
||||||
|
@ -31,29 +31,28 @@ int raw_encode_box(struct vec *dst, const struct rfb_pixel_format *dst_fmt,
|
||||||
|
|
||||||
for (int y = y_start; y < y_start + height; ++y)
|
for (int y = y_start; y < y_start + height; ++y)
|
||||||
pixel32_to_cpixel(dst->data, dst_fmt, b + y * stride, src_fmt,
|
pixel32_to_cpixel(dst->data, dst_fmt, b + y * stride, src_fmt,
|
||||||
bytes_per_pixel, width);
|
bytes_per_pixel, width);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int raw_encode_frame(struct vec *dst,
|
int raw_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct nvnc_fb* src,
|
||||||
const struct nvnc_fb *src,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
struct pixman_region16* region)
|
||||||
struct pixman_region16 *region)
|
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
int n_rects = 0;
|
int n_rects = 0;
|
||||||
struct pixman_box16 *box = pixman_region_rectangles(region, &n_rects);
|
struct pixman_box16* box = pixman_region_rectangles(region, &n_rects);
|
||||||
if (n_rects > UINT16_MAX) {
|
if (n_rects > UINT16_MAX) {
|
||||||
box = pixman_region_extents(region);
|
box = pixman_region_extents(region);
|
||||||
n_rects = 1;
|
n_rects = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rfb_server_fb_update_msg head = {
|
struct rfb_server_fb_update_msg head = {
|
||||||
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
||||||
.n_rects = htons(n_rects),
|
.n_rects = htons(n_rects),
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = vec_reserve(dst, src->width * src->height * 4 + 256);
|
rc = vec_reserve(dst, src->width * src->height * 4 + 256);
|
||||||
|
@ -71,7 +70,7 @@ int raw_encode_frame(struct vec *dst,
|
||||||
int box_height = box[i].y2 - y;
|
int box_height = box[i].y2 - y;
|
||||||
|
|
||||||
rc = raw_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
rc = raw_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
||||||
src->width, box_width, box_height);
|
src->width, box_width, box_height);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
303
src/server.c
303
src/server.c
|
@ -66,7 +66,7 @@ struct nvnc_client {
|
||||||
struct nvnc_common common;
|
struct nvnc_common common;
|
||||||
int ref;
|
int ref;
|
||||||
uv_tcp_t stream_handle;
|
uv_tcp_t stream_handle;
|
||||||
struct nvnc *server;
|
struct nvnc* server;
|
||||||
enum nvnc_client_state state;
|
enum nvnc_client_state state;
|
||||||
uint32_t fourcc;
|
uint32_t fourcc;
|
||||||
struct rfb_pixel_format pixfmt;
|
struct rfb_pixel_format pixfmt;
|
||||||
|
@ -97,7 +97,7 @@ struct nvnc {
|
||||||
uv_tcp_t tcp_handle;
|
uv_tcp_t tcp_handle;
|
||||||
struct nvnc_client_list clients;
|
struct nvnc_client_list clients;
|
||||||
struct vnc_display display;
|
struct vnc_display display;
|
||||||
void *userdata;
|
void* userdata;
|
||||||
nvnc_key_fn key_fn;
|
nvnc_key_fn key_fn;
|
||||||
nvnc_pointer_fn pointer_fn;
|
nvnc_pointer_fn pointer_fn;
|
||||||
nvnc_fb_req_fn fb_req_fn;
|
nvnc_fb_req_fn fb_req_fn;
|
||||||
|
@ -107,21 +107,21 @@ struct nvnc {
|
||||||
|
|
||||||
struct fb_update_work {
|
struct fb_update_work {
|
||||||
uv_work_t work;
|
uv_work_t work;
|
||||||
struct nvnc_client *client;
|
struct nvnc_client* client;
|
||||||
struct pixman_region16 region;
|
struct pixman_region16 region;
|
||||||
struct rfb_pixel_format server_fmt;
|
struct rfb_pixel_format server_fmt;
|
||||||
struct vec frame;
|
struct vec frame;
|
||||||
struct nvnc_fb *fb;
|
struct nvnc_fb* fb;
|
||||||
};
|
};
|
||||||
|
|
||||||
int schedule_client_update_fb(struct nvnc_client *client);
|
int schedule_client_update_fb(struct nvnc_client* client);
|
||||||
|
|
||||||
static const char* fourcc_to_string(uint32_t fourcc)
|
static const char* fourcc_to_string(uint32_t fourcc)
|
||||||
{
|
{
|
||||||
static char buffer[5];
|
static char buffer[5];
|
||||||
|
|
||||||
buffer[0] = (fourcc >> 0) & 0xff;
|
buffer[0] = (fourcc >> 0) & 0xff;
|
||||||
buffer[1] = (fourcc >> 8) & 0xff;
|
buffer[1] = (fourcc >> 8) & 0xff;
|
||||||
buffer[2] = (fourcc >> 16) & 0xff;
|
buffer[2] = (fourcc >> 16) & 0xff;
|
||||||
buffer[3] = (fourcc >> 24) & 0xff;
|
buffer[3] = (fourcc >> 24) & 0xff;
|
||||||
buffer[4] = '\0';
|
buffer[4] = '\0';
|
||||||
|
@ -129,8 +129,8 @@ static const char* fourcc_to_string(uint32_t fourcc)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void allocate_read_buffer(uv_handle_t *handle, size_t suggested_size,
|
static void allocate_read_buffer(uv_handle_t* handle, size_t suggested_size,
|
||||||
uv_buf_t *buf)
|
uv_buf_t* buf)
|
||||||
{
|
{
|
||||||
(void)suggested_size;
|
(void)suggested_size;
|
||||||
|
|
||||||
|
@ -140,9 +140,8 @@ static void allocate_read_buffer(uv_handle_t *handle, size_t suggested_size,
|
||||||
|
|
||||||
static void cleanup_client(uv_handle_t* handle)
|
static void cleanup_client(uv_handle_t* handle)
|
||||||
{
|
{
|
||||||
struct nvnc_client *client =
|
struct nvnc_client* client = container_of(
|
||||||
container_of((uv_tcp_t*)handle, struct nvnc_client,
|
(uv_tcp_t*)handle, struct nvnc_client, stream_handle);
|
||||||
stream_handle);
|
|
||||||
|
|
||||||
nvnc_client_fn fn = client->cleanup_fn;
|
nvnc_client_fn fn = client->cleanup_fn;
|
||||||
if (fn)
|
if (fn)
|
||||||
|
@ -155,39 +154,37 @@ static void cleanup_client(uv_handle_t* handle)
|
||||||
free(client);
|
free(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void client_close(struct nvnc_client *client)
|
static inline void client_close(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&client->stream_handle, cleanup_client);
|
uv_close((uv_handle_t*)&client->stream_handle, cleanup_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void client_unref(struct nvnc_client *client)
|
static inline void client_unref(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (--client->ref == 0)
|
if (--client->ref == 0)
|
||||||
client_close(client);
|
client_close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void client_ref(struct nvnc_client *client)
|
static inline void client_ref(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
++client->ref;
|
++client->ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_after_write(uv_write_t *req, int status)
|
static void close_after_write(uv_write_t* req, int status)
|
||||||
{
|
{
|
||||||
struct nvnc_client* client =
|
struct nvnc_client* client = container_of(
|
||||||
container_of((uv_tcp_t*)req->handle, struct nvnc_client,
|
(uv_tcp_t*)req->handle, struct nvnc_client, stream_handle);
|
||||||
stream_handle);
|
|
||||||
|
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_unsupported_version(struct nvnc_client *client)
|
static int handle_unsupported_version(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
client->state = VNC_CLIENT_STATE_ERROR;
|
client->state = VNC_CLIENT_STATE_ERROR;
|
||||||
|
|
||||||
struct rfb_error_reason *reason =
|
struct rfb_error_reason* reason = (struct rfb_error_reason*)(buffer + 1);
|
||||||
(struct rfb_error_reason*)(buffer + 1);
|
|
||||||
|
|
||||||
static const char reason_string[] = "Unsupported version\n";
|
static const char reason_string[] = "Unsupported version\n";
|
||||||
|
|
||||||
|
@ -196,13 +193,13 @@ static int handle_unsupported_version(struct nvnc_client *client)
|
||||||
(void)strcmp(reason->message, reason_string);
|
(void)strcmp(reason->message, reason_string);
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, buffer,
|
vnc__write((uv_stream_t*)&client->stream_handle, buffer,
|
||||||
1 + sizeof(*reason) + strlen(reason_string),
|
1 + sizeof(*reason) + strlen(reason_string),
|
||||||
close_after_write);
|
close_after_write);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_version_message(struct nvnc_client *client)
|
static int on_version_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (client->buffer_len - client->buffer_index < 12)
|
if (client->buffer_len - client->buffer_index < 12)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -214,29 +211,32 @@ static int on_version_message(struct nvnc_client *client)
|
||||||
if (strcmp(RFB_VERSION_MESSAGE, version_string) != 0)
|
if (strcmp(RFB_VERSION_MESSAGE, version_string) != 0)
|
||||||
return handle_unsupported_version(client);
|
return handle_unsupported_version(client);
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
const static struct rfb_security_types_msg security = {
|
const static struct rfb_security_types_msg security = {
|
||||||
.n = 1,
|
.n = 1,
|
||||||
.types = {
|
.types = {
|
||||||
RFB_SECURITY_TYPE_NONE,
|
RFB_SECURITY_TYPE_NONE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, &security, sizeof(security), NULL);
|
vnc__write((uv_stream_t*)&client->stream_handle, &security,
|
||||||
|
sizeof(security), NULL);
|
||||||
|
|
||||||
client->state = VNC_CLIENT_STATE_WAITING_FOR_SECURITY;
|
client->state = VNC_CLIENT_STATE_WAITING_FOR_SECURITY;
|
||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_invalid_security_type(struct nvnc_client *client)
|
static int handle_invalid_security_type(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
client->state = VNC_CLIENT_STATE_ERROR;
|
client->state = VNC_CLIENT_STATE_ERROR;
|
||||||
|
|
||||||
uint8_t *result = (uint8_t*)buffer;
|
uint8_t* result = (uint8_t*)buffer;
|
||||||
|
|
||||||
struct rfb_error_reason *reason =
|
struct rfb_error_reason* reason =
|
||||||
(struct rfb_error_reason*)(buffer + sizeof(*result));
|
(struct rfb_error_reason*)(buffer + sizeof(*result));
|
||||||
|
|
||||||
static const char reason_string[] = "Unsupported version\n";
|
static const char reason_string[] = "Unsupported version\n";
|
||||||
|
|
||||||
|
@ -245,13 +245,13 @@ static int handle_invalid_security_type(struct nvnc_client *client)
|
||||||
(void)strcmp(reason->message, reason_string);
|
(void)strcmp(reason->message, reason_string);
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, buffer,
|
vnc__write((uv_stream_t*)&client->stream_handle, buffer,
|
||||||
sizeof(*result) + sizeof(*reason) + strlen(reason_string),
|
sizeof(*result) + sizeof(*reason) + strlen(reason_string),
|
||||||
close_after_write);
|
close_after_write);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_security_message(struct nvnc_client *client)
|
static int on_security_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (client->buffer_len - client->buffer_index < 1)
|
if (client->buffer_len - client->buffer_index < 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -261,23 +261,25 @@ static int on_security_message(struct nvnc_client *client)
|
||||||
if (type != RFB_SECURITY_TYPE_NONE)
|
if (type != RFB_SECURITY_TYPE_NONE)
|
||||||
return handle_invalid_security_type(client);
|
return handle_invalid_security_type(client);
|
||||||
|
|
||||||
enum rfb_security_handshake_result result
|
enum rfb_security_handshake_result result =
|
||||||
= htonl(RFB_SECURITY_HANDSHAKE_OK);
|
htonl(RFB_SECURITY_HANDSHAKE_OK);
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, &result, sizeof(result), NULL);
|
vnc__write((uv_stream_t*)&client->stream_handle, &result,
|
||||||
|
sizeof(result), NULL);
|
||||||
|
|
||||||
client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
|
client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
|
||||||
return sizeof(type);
|
return sizeof(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disconnect_all_other_clients(struct nvnc_client *client)
|
static void disconnect_all_other_clients(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc_client *node;
|
struct nvnc_client* node;
|
||||||
LIST_FOREACH(node, &client->server->clients, link)
|
LIST_FOREACH (node, &client->server->clients, link)
|
||||||
if (node != client)
|
if (node != client)
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
int rfb_pixfmt_from_fourcc(struct rfb_pixel_format *dst, uint32_t src) {
|
int rfb_pixfmt_from_fourcc(struct rfb_pixel_format *dst, uint32_t src) {
|
||||||
switch (src & ~DRM_FORMAT_BIG_ENDIAN) {
|
switch (src & ~DRM_FORMAT_BIG_ENDIAN) {
|
||||||
case DRM_FORMAT_RGBA8888:
|
case DRM_FORMAT_RGBA8888:
|
||||||
|
@ -396,6 +398,7 @@ static uint32_t shift_values_to_fourcc(int r, int g, int b, int bpp)
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
#undef RGBEQ
|
#undef RGBEQ
|
||||||
}
|
}
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
int get_fourcc_depth(uint32_t fourcc)
|
int get_fourcc_depth(uint32_t fourcc)
|
||||||
{
|
{
|
||||||
|
@ -409,20 +412,20 @@ int get_fourcc_depth(uint32_t fourcc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t rfb_pixfmt_to_fourcc(const struct rfb_pixel_format *fmt)
|
uint32_t rfb_pixfmt_to_fourcc(const struct rfb_pixel_format* fmt)
|
||||||
{
|
{
|
||||||
if (!fmt->true_colour_flag)
|
if (!fmt->true_colour_flag)
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
|
|
||||||
/* Note: The depth value given by the client is ignored */
|
/* Note: The depth value given by the client is ignored */
|
||||||
int depth = max_values_to_depth(fmt->red_max, fmt->green_max,
|
int depth =
|
||||||
fmt->blue_max);
|
max_values_to_depth(fmt->red_max, fmt->green_max, fmt->blue_max);
|
||||||
if (depth < 0)
|
if (depth < 0)
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
|
|
||||||
uint32_t fourcc =
|
uint32_t fourcc =
|
||||||
shift_values_to_fourcc(fmt->red_shift, fmt->green_shift,
|
shift_values_to_fourcc(fmt->red_shift, fmt->green_shift,
|
||||||
fmt->blue_shift, fmt->bits_per_pixel);
|
fmt->blue_shift, fmt->bits_per_pixel);
|
||||||
|
|
||||||
if (fourcc == DRM_FORMAT_INVALID)
|
if (fourcc == DRM_FORMAT_INVALID)
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
|
@ -435,23 +438,22 @@ uint32_t rfb_pixfmt_to_fourcc(const struct rfb_pixel_format *fmt)
|
||||||
return fourcc;
|
return fourcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_server_init_message(struct nvnc_client *client)
|
static void send_server_init_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc *server = client->server;
|
struct nvnc* server = client->server;
|
||||||
struct vnc_display *display = &server->display;
|
struct vnc_display* display = &server->display;
|
||||||
|
|
||||||
size_t name_len = strlen(display->name);
|
size_t name_len = strlen(display->name);
|
||||||
size_t size = sizeof(struct rfb_server_init_msg) + name_len;
|
size_t size = sizeof(struct rfb_server_init_msg) + name_len;
|
||||||
|
|
||||||
struct rfb_server_init_msg *msg = calloc(1, size);
|
struct rfb_server_init_msg* msg = calloc(1, size);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->width = htons(display->width),
|
msg->width = htons(display->width),
|
||||||
msg->height = htons(display->height),
|
msg->height = htons(display->height), msg->name_length = htonl(name_len),
|
||||||
msg->name_length = htonl(name_len),
|
|
||||||
memcpy(msg->name_string, display->name, name_len);
|
memcpy(msg->name_string, display->name, name_len);
|
||||||
|
|
||||||
int rc = rfb_pixfmt_from_fourcc(&msg->pixel_format, display->pixfmt);
|
int rc = rfb_pixfmt_from_fourcc(&msg->pixel_format, display->pixfmt);
|
||||||
|
@ -469,7 +471,7 @@ static void send_server_init_message(struct nvnc_client *client)
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_init_message(struct nvnc_client *client)
|
static int on_init_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (client->buffer_len - client->buffer_index < 1)
|
if (client->buffer_len - client->buffer_index < 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -488,15 +490,15 @@ static int on_init_message(struct nvnc_client *client)
|
||||||
return sizeof(shared_flag);
|
return sizeof(shared_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_set_pixel_format(struct nvnc_client *client)
|
static int on_client_set_pixel_format(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (client->buffer_len - client->buffer_index
|
if (client->buffer_len - client->buffer_index <
|
||||||
< 4 + sizeof(struct rfb_pixel_format))
|
4 + sizeof(struct rfb_pixel_format))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct rfb_pixel_format *fmt =
|
struct rfb_pixel_format* fmt =
|
||||||
(struct rfb_pixel_format*)(client->msg_buffer +
|
(struct rfb_pixel_format*)(client->msg_buffer +
|
||||||
client->buffer_index + 4);
|
client->buffer_index + 4);
|
||||||
|
|
||||||
if (!fmt->true_colour_flag) {
|
if (!fmt->true_colour_flag) {
|
||||||
/* We don't really know what to do with color maps right now */
|
/* We don't really know what to do with color maps right now */
|
||||||
|
@ -515,11 +517,11 @@ static int on_client_set_pixel_format(struct nvnc_client *client)
|
||||||
return 4 + sizeof(struct rfb_pixel_format);
|
return 4 + sizeof(struct rfb_pixel_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_set_encodings(struct nvnc_client *client)
|
static int on_client_set_encodings(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct rfb_client_set_encodings_msg *msg =
|
struct rfb_client_set_encodings_msg* msg =
|
||||||
(struct rfb_client_set_encodings_msg*)(client->msg_buffer +
|
(struct rfb_client_set_encodings_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int n_encodings = MIN(MAX_ENCODINGS, ntohs(msg->n_encodings));
|
int n_encodings = MIN(MAX_ENCODINGS, ntohs(msg->n_encodings));
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -545,7 +547,7 @@ static int on_client_set_encodings(struct nvnc_client *client)
|
||||||
return sizeof(*msg) + 4 * n_encodings;
|
return sizeof(*msg) + 4 * n_encodings;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_fb_update_requests(struct nvnc_client *client)
|
static void process_fb_update_requests(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (!client->server->frame)
|
if (!client->server->frame)
|
||||||
return;
|
return;
|
||||||
|
@ -564,13 +566,13 @@ static void process_fb_update_requests(struct nvnc_client *client)
|
||||||
schedule_client_update_fb(client);
|
schedule_client_update_fb(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_fb_update_request(struct nvnc_client *client)
|
static int on_client_fb_update_request(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc *server = client->server;
|
struct nvnc* server = client->server;
|
||||||
|
|
||||||
struct rfb_client_fb_update_req_msg *msg =
|
struct rfb_client_fb_update_req_msg* msg =
|
||||||
(struct rfb_client_fb_update_req_msg*)(client->msg_buffer +
|
(struct rfb_client_fb_update_req_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int incremental = msg->incremental;
|
int incremental = msg->incremental;
|
||||||
int x = ntohs(msg->x);
|
int x = ntohs(msg->x);
|
||||||
|
@ -584,8 +586,8 @@ static int on_client_fb_update_request(struct nvnc_client *client)
|
||||||
* updates. This avoids superfluous complexity.
|
* updates. This avoids superfluous complexity.
|
||||||
*/
|
*/
|
||||||
if (!incremental)
|
if (!incremental)
|
||||||
pixman_region_union_rect(&client->damage, &client->damage,
|
pixman_region_union_rect(&client->damage, &client->damage, x, y,
|
||||||
x, y, width, height);
|
width, height);
|
||||||
|
|
||||||
nvnc_fb_req_fn fn = server->fb_req_fn;
|
nvnc_fb_req_fn fn = server->fb_req_fn;
|
||||||
if (fn)
|
if (fn)
|
||||||
|
@ -596,13 +598,13 @@ static int on_client_fb_update_request(struct nvnc_client *client)
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_key_event(struct nvnc_client *client)
|
static int on_client_key_event(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc *server = client->server;
|
struct nvnc* server = client->server;
|
||||||
|
|
||||||
struct rfb_client_key_event_msg *msg =
|
struct rfb_client_key_event_msg* msg =
|
||||||
(struct rfb_client_key_event_msg*)(client->msg_buffer +
|
(struct rfb_client_key_event_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int down_flag = msg->down_flag;
|
int down_flag = msg->down_flag;
|
||||||
uint32_t keysym = ntohl(msg->key);
|
uint32_t keysym = ntohl(msg->key);
|
||||||
|
@ -614,13 +616,13 @@ static int on_client_key_event(struct nvnc_client *client)
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_pointer_event(struct nvnc_client *client)
|
static int on_client_pointer_event(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc *server = client->server;
|
struct nvnc* server = client->server;
|
||||||
|
|
||||||
struct rfb_client_pointer_event_msg *msg =
|
struct rfb_client_pointer_event_msg* msg =
|
||||||
(struct rfb_client_pointer_event_msg*)(client->msg_buffer +
|
(struct rfb_client_pointer_event_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int button_mask = msg->button_mask;
|
int button_mask = msg->button_mask;
|
||||||
uint16_t x = ntohs(msg->x);
|
uint16_t x = ntohs(msg->x);
|
||||||
|
@ -633,11 +635,11 @@ static int on_client_pointer_event(struct nvnc_client *client)
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_cut_text(struct nvnc_client *client)
|
static int on_client_cut_text(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct rfb_client_cut_text_msg *msg =
|
struct rfb_client_cut_text_msg* msg =
|
||||||
(struct rfb_client_cut_text_msg*)(client->msg_buffer +
|
(struct rfb_client_cut_text_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
uint32_t length = ntohl(msg->length);
|
uint32_t length = ntohl(msg->length);
|
||||||
|
|
||||||
|
@ -646,13 +648,13 @@ static int on_client_cut_text(struct nvnc_client *client)
|
||||||
return sizeof(*msg) + length;
|
return sizeof(*msg) + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_message(struct nvnc_client *client)
|
static int on_client_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
if (client->buffer_len - client->buffer_index < 1)
|
if (client->buffer_len - client->buffer_index < 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
enum rfb_client_to_server_msg_type type =
|
enum rfb_client_to_server_msg_type type =
|
||||||
client->msg_buffer[client->buffer_index];
|
client->msg_buffer[client->buffer_index];
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RFB_CLIENT_TO_SERVER_SET_PIXEL_FORMAT:
|
case RFB_CLIENT_TO_SERVER_SET_PIXEL_FORMAT:
|
||||||
|
@ -673,7 +675,7 @@ static int on_client_message(struct nvnc_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_read_client_message(struct nvnc_client *client)
|
static int try_read_client_message(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
switch (client->state) {
|
switch (client->state) {
|
||||||
case VNC_CLIENT_STATE_ERROR:
|
case VNC_CLIENT_STATE_ERROR:
|
||||||
|
@ -693,12 +695,11 @@ static int try_read_client_message(struct nvnc_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_client_read(uv_stream_t *stream, ssize_t n_read,
|
static void on_client_read(uv_stream_t* stream, ssize_t n_read,
|
||||||
const uv_buf_t *buf)
|
const uv_buf_t* buf)
|
||||||
{
|
{
|
||||||
struct nvnc_client *client =
|
struct nvnc_client* client = container_of(
|
||||||
container_of((uv_tcp_t*)stream, struct nvnc_client,
|
(uv_tcp_t*)stream, struct nvnc_client, stream_handle);
|
||||||
stream_handle);
|
|
||||||
|
|
||||||
if (n_read == UV_EOF) {
|
if (n_read == UV_EOF) {
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
|
@ -731,17 +732,17 @@ static void on_client_read(uv_stream_t *stream, ssize_t n_read,
|
||||||
assert(client->buffer_index <= client->buffer_len);
|
assert(client->buffer_index <= client->buffer_len);
|
||||||
|
|
||||||
memmove(client->msg_buffer, client->msg_buffer + client->buffer_index,
|
memmove(client->msg_buffer, client->msg_buffer + client->buffer_index,
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
client->buffer_len -= client->buffer_index;
|
client->buffer_len -= client->buffer_index;
|
||||||
client->buffer_index = 0;
|
client->buffer_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_connection(uv_stream_t *server_stream, int status)
|
static void on_connection(uv_stream_t* server_stream, int status)
|
||||||
{
|
{
|
||||||
struct nvnc *server = container_of((uv_tcp_t*)server_stream,
|
struct nvnc* server =
|
||||||
struct nvnc, tcp_handle);
|
container_of((uv_tcp_t*)server_stream, struct nvnc, tcp_handle);
|
||||||
|
|
||||||
struct nvnc_client *client = calloc(1, sizeof(*client));
|
struct nvnc_client* client = calloc(1, sizeof(*client));
|
||||||
if (!client)
|
if (!client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -749,11 +750,11 @@ static void on_connection(uv_stream_t *server_stream, int status)
|
||||||
client->server = server;
|
client->server = server;
|
||||||
|
|
||||||
int rc = deflateInit2(&client->z_stream,
|
int rc = deflateInit2(&client->z_stream,
|
||||||
/* compression level: */ 1,
|
/* compression level: */ 1,
|
||||||
/* method: */ Z_DEFLATED,
|
/* method: */ Z_DEFLATED,
|
||||||
/* window bits: */ 15,
|
/* window bits: */ 15,
|
||||||
/* mem level: */ 9,
|
/* mem level: */ 9,
|
||||||
/* strategy: */ Z_DEFAULT_STRATEGY);
|
/* strategy: */ Z_DEFAULT_STRATEGY);
|
||||||
|
|
||||||
if (rc != Z_OK) {
|
if (rc != Z_OK) {
|
||||||
free(client);
|
free(client);
|
||||||
|
@ -765,26 +766,26 @@ static void on_connection(uv_stream_t *server_stream, int status)
|
||||||
uv_tcp_init(uv_default_loop(), &client->stream_handle);
|
uv_tcp_init(uv_default_loop(), &client->stream_handle);
|
||||||
|
|
||||||
uv_accept((uv_stream_t*)&server->tcp_handle,
|
uv_accept((uv_stream_t*)&server->tcp_handle,
|
||||||
(uv_stream_t*)&client->stream_handle);
|
(uv_stream_t*)&client->stream_handle);
|
||||||
|
|
||||||
uv_read_start((uv_stream_t*)&client->stream_handle,
|
uv_read_start((uv_stream_t*)&client->stream_handle,
|
||||||
allocate_read_buffer, on_client_read);
|
allocate_read_buffer, on_client_read);
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, RFB_VERSION_MESSAGE,
|
vnc__write((uv_stream_t*)&client->stream_handle, RFB_VERSION_MESSAGE,
|
||||||
strlen(RFB_VERSION_MESSAGE), NULL);
|
strlen(RFB_VERSION_MESSAGE), NULL);
|
||||||
|
|
||||||
LIST_INSERT_HEAD(&server->clients, client, link);
|
LIST_INSERT_HEAD(&server->clients, client, link);
|
||||||
|
|
||||||
client->state = VNC_CLIENT_STATE_WAITING_FOR_VERSION;
|
client->state = VNC_CLIENT_STATE_WAITING_FOR_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vnc_server_init(struct nvnc *self, const char* address, int port)
|
int vnc_server_init(struct nvnc* self, const char* address, int port)
|
||||||
{
|
{
|
||||||
LIST_INIT(&self->clients);
|
LIST_INIT(&self->clients);
|
||||||
|
|
||||||
uv_tcp_init(uv_default_loop(), &self->tcp_handle);
|
uv_tcp_init(uv_default_loop(), &self->tcp_handle);
|
||||||
|
|
||||||
struct sockaddr_in addr = { 0 };
|
struct sockaddr_in addr = {0};
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.s_addr = inet_addr(address);
|
addr.sin_addr.s_addr = inet_addr(address);
|
||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
|
@ -803,9 +804,9 @@ failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
struct nvnc *nvnc_open(const char *address, uint16_t port)
|
struct nvnc* nvnc_open(const char* address, uint16_t port)
|
||||||
{
|
{
|
||||||
struct nvnc *self = calloc(1, sizeof(*self));
|
struct nvnc* self = calloc(1, sizeof(*self));
|
||||||
if (!self)
|
if (!self)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -815,7 +816,7 @@ struct nvnc *nvnc_open(const char *address, uint16_t port)
|
||||||
|
|
||||||
uv_tcp_init(uv_default_loop(), &self->tcp_handle);
|
uv_tcp_init(uv_default_loop(), &self->tcp_handle);
|
||||||
|
|
||||||
struct sockaddr_in addr = { 0 };
|
struct sockaddr_in addr = {0};
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.s_addr = inet_addr(address);
|
addr.sin_addr.s_addr = inet_addr(address);
|
||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
|
@ -833,27 +834,27 @@ failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_close(struct nvnc *self)
|
void nvnc_close(struct nvnc* self)
|
||||||
{
|
{
|
||||||
struct nvnc_client *client;
|
struct nvnc_client* client;
|
||||||
|
|
||||||
if (self->frame)
|
if (self->frame)
|
||||||
nvnc_fb_unref(self->frame);
|
nvnc_fb_unref(self->frame);
|
||||||
|
|
||||||
LIST_FOREACH(client, &self->clients, link)
|
LIST_FOREACH (client, &self->clients, link)
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
|
|
||||||
uv_unref((uv_handle_t*)&self->tcp_handle);
|
uv_unref((uv_handle_t*)&self->tcp_handle);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_write_buffer(uv_write_t *req, int status)
|
static void free_write_buffer(uv_write_t* req, int status)
|
||||||
{
|
{
|
||||||
struct vnc_write_request *rq = (struct vnc_write_request*)req;
|
struct vnc_write_request* rq = (struct vnc_write_request*)req;
|
||||||
free(rq->buffer.base);
|
free(rq->buffer.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum rfb_encodings choose_frame_encoding(struct nvnc_client *client)
|
enum rfb_encodings choose_frame_encoding(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < client->n_encodings; ++i)
|
for (int i = 0; i < client->n_encodings; ++i)
|
||||||
switch (client->encodings[i]) {
|
switch (client->encodings[i]) {
|
||||||
|
@ -867,11 +868,11 @@ enum rfb_encodings choose_frame_encoding(struct nvnc_client *client)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_client_update_fb(uv_work_t *work)
|
void do_client_update_fb(uv_work_t* work)
|
||||||
{
|
{
|
||||||
struct fb_update_work *update = (void*)work;
|
struct fb_update_work* update = (void*)work;
|
||||||
struct nvnc_client *client = update->client;
|
struct nvnc_client* client = update->client;
|
||||||
const struct nvnc_fb *fb = update->fb;
|
const struct nvnc_fb* fb = update->fb;
|
||||||
|
|
||||||
enum rfb_encodings encoding = choose_frame_encoding(client);
|
enum rfb_encodings encoding = choose_frame_encoding(client);
|
||||||
assert(encoding != -1);
|
assert(encoding != -1);
|
||||||
|
@ -879,30 +880,30 @@ void do_client_update_fb(uv_work_t *work)
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case RFB_ENCODING_RAW:
|
case RFB_ENCODING_RAW:
|
||||||
raw_encode_frame(&update->frame, &client->pixfmt, fb,
|
raw_encode_frame(&update->frame, &client->pixfmt, fb,
|
||||||
&update->server_fmt, &update->region);
|
&update->server_fmt, &update->region);
|
||||||
break;
|
break;
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
zrle_encode_frame(&client->z_stream, &update->frame,
|
zrle_encode_frame(&client->z_stream, &update->frame,
|
||||||
&client->pixfmt, fb, &update->server_fmt,
|
&client->pixfmt, fb, &update->server_fmt,
|
||||||
&update->region);
|
&update->region);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_client_update_fb_done(uv_work_t *work, int status)
|
void on_client_update_fb_done(uv_work_t* work, int status)
|
||||||
{
|
{
|
||||||
(void)status;
|
(void)status;
|
||||||
|
|
||||||
struct fb_update_work *update = (void*)work;
|
struct fb_update_work* update = (void*)work;
|
||||||
struct nvnc_client *client = update->client;
|
struct nvnc_client* client = update->client;
|
||||||
struct nvnc *server = client->server;
|
struct nvnc* server = client->server;
|
||||||
struct vec *frame = &update->frame;
|
struct vec* frame = &update->frame;
|
||||||
|
|
||||||
if (!uv_is_closing((uv_handle_t*)&client->stream_handle))
|
if (!uv_is_closing((uv_handle_t*)&client->stream_handle))
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle,
|
vnc__write((uv_stream_t*)&client->stream_handle, frame->data,
|
||||||
frame->data, frame->len, free_write_buffer);
|
frame->len, free_write_buffer);
|
||||||
|
|
||||||
client->is_updating = false;
|
client->is_updating = false;
|
||||||
client->n_pending_requests--;
|
client->n_pending_requests--;
|
||||||
|
@ -911,12 +912,12 @@ void on_client_update_fb_done(uv_work_t *work, int status)
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
int schedule_client_update_fb(struct nvnc_client *client)
|
int schedule_client_update_fb(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc_fb* fb = client->server->frame;
|
struct nvnc_fb* fb = client->server->frame;
|
||||||
assert(fb);
|
assert(fb);
|
||||||
|
|
||||||
struct fb_update_work *work = calloc(1, sizeof(*work));
|
struct fb_update_work* work = calloc(1, sizeof(*work));
|
||||||
if (!work)
|
if (!work)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -938,7 +939,7 @@ int schedule_client_update_fb(struct nvnc_client *client)
|
||||||
nvnc_fb_ref(fb);
|
nvnc_fb_ref(fb);
|
||||||
|
|
||||||
rc = uv_queue_work(uv_default_loop(), &work->work, do_client_update_fb,
|
rc = uv_queue_work(uv_default_loop(), &work->work, do_client_update_fb,
|
||||||
on_client_update_fb_done);
|
on_client_update_fb_done);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto queue_failure;
|
goto queue_failure;
|
||||||
|
|
||||||
|
@ -955,10 +956,10 @@ pixfmt_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
int nvnc_feed_frame(struct nvnc *self, struct nvnc_fb *fb,
|
int nvnc_feed_frame(struct nvnc* self, struct nvnc_fb* fb,
|
||||||
const struct pixman_region16 *damage)
|
const struct pixman_region16* damage)
|
||||||
{
|
{
|
||||||
struct nvnc_client *client;
|
struct nvnc_client* client;
|
||||||
|
|
||||||
if (self->frame)
|
if (self->frame)
|
||||||
nvnc_fb_unref(self->frame);
|
nvnc_fb_unref(self->frame);
|
||||||
|
@ -966,14 +967,14 @@ int nvnc_feed_frame(struct nvnc *self, struct nvnc_fb *fb,
|
||||||
self->frame = fb;
|
self->frame = fb;
|
||||||
nvnc_fb_ref(self->frame);
|
nvnc_fb_ref(self->frame);
|
||||||
|
|
||||||
LIST_FOREACH(client, &self->clients, link) {
|
LIST_FOREACH (client, &self->clients, link) {
|
||||||
if (uv_is_closing((uv_handle_t*)&client->stream_handle))
|
if (uv_is_closing((uv_handle_t*)&client->stream_handle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pixman_region_union(&client->damage, &client->damage,
|
pixman_region_union(&client->damage, &client->damage,
|
||||||
(struct pixman_region16*)damage);
|
(struct pixman_region16*)damage);
|
||||||
pixman_region_intersect_rect(&client->damage, &client->damage,
|
pixman_region_intersect_rect(&client->damage, &client->damage,
|
||||||
0, 0, fb->width, fb->height);
|
0, 0, fb->width, fb->height);
|
||||||
|
|
||||||
process_fb_update_requests(client);
|
process_fb_update_requests(client);
|
||||||
}
|
}
|
||||||
|
@ -982,52 +983,52 @@ int nvnc_feed_frame(struct nvnc *self, struct nvnc_fb *fb,
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_userdata(void *self, void *userdata)
|
void nvnc_set_userdata(void* self, void* userdata)
|
||||||
{
|
{
|
||||||
struct nvnc_common *common = self;
|
struct nvnc_common* common = self;
|
||||||
common->userdata = userdata;
|
common->userdata = userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void* nvnc_get_userdata(const void *self)
|
void* nvnc_get_userdata(const void* self)
|
||||||
{
|
{
|
||||||
const struct nvnc_common *common = self;
|
const struct nvnc_common* common = self;
|
||||||
return common->userdata;
|
return common->userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_key_fn(struct nvnc *self, nvnc_key_fn fn)
|
void nvnc_set_key_fn(struct nvnc* self, nvnc_key_fn fn)
|
||||||
{
|
{
|
||||||
self->key_fn = fn;
|
self->key_fn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_pointer_fn(struct nvnc *self, nvnc_pointer_fn fn)
|
void nvnc_set_pointer_fn(struct nvnc* self, nvnc_pointer_fn fn)
|
||||||
{
|
{
|
||||||
self->pointer_fn = fn;
|
self->pointer_fn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_fb_req_fn(struct nvnc *self, nvnc_fb_req_fn fn)
|
void nvnc_set_fb_req_fn(struct nvnc* self, nvnc_fb_req_fn fn)
|
||||||
{
|
{
|
||||||
self->fb_req_fn = fn;
|
self->fb_req_fn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_new_client_fn(struct nvnc *self, nvnc_client_fn fn)
|
void nvnc_set_new_client_fn(struct nvnc* self, nvnc_client_fn fn)
|
||||||
{
|
{
|
||||||
self->new_client_fn = fn;
|
self->new_client_fn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_client_cleanup_fn(struct nvnc_client *self, nvnc_client_fn fn)
|
void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn)
|
||||||
{
|
{
|
||||||
self->cleanup_fn = fn;
|
self->cleanup_fn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_dimensions(struct nvnc *self, uint16_t width, uint16_t height,
|
void nvnc_set_dimensions(struct nvnc* self, uint16_t width, uint16_t height,
|
||||||
uint32_t fourcc_format)
|
uint32_t fourcc_format)
|
||||||
{
|
{
|
||||||
self->display.width = width;
|
self->display.width = width;
|
||||||
self->display.height = height;
|
self->display.height = height;
|
||||||
|
@ -1035,13 +1036,13 @@ void nvnc_set_dimensions(struct nvnc *self, uint16_t width, uint16_t height,
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
struct nvnc *nvnc_get_server(const struct nvnc_client *client)
|
struct nvnc* nvnc_get_server(const struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
return client->server;
|
return client->server;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
void nvnc_set_name(struct nvnc *self, const char *name)
|
void nvnc_set_name(struct nvnc* self, const char* name)
|
||||||
{
|
{
|
||||||
strncpy(self->display.name, name, sizeof(self->display.name));
|
strncpy(self->display.name, name, sizeof(self->display.name));
|
||||||
self->display.name[sizeof(self->display.name) - 1] = '\0';
|
self->display.name[sizeof(self->display.name) - 1] = '\0';
|
||||||
|
|
12
src/util.c
12
src/util.c
|
@ -20,18 +20,18 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static void on_write_req_done(uv_write_t *req, int status)
|
static void on_write_req_done(uv_write_t* req, int status)
|
||||||
{
|
{
|
||||||
struct vnc_write_request *self = (struct vnc_write_request*)req;
|
struct vnc_write_request* self = (struct vnc_write_request*)req;
|
||||||
if (self->on_done)
|
if (self->on_done)
|
||||||
self->on_done(req, status);
|
self->on_done(req, status);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vnc__write(uv_stream_t *stream, const void *payload, size_t size,
|
int vnc__write(uv_stream_t* stream, const void* payload, size_t size,
|
||||||
uv_write_cb on_done)
|
uv_write_cb on_done)
|
||||||
{
|
{
|
||||||
struct vnc_write_request *req = calloc(1, sizeof(*req));
|
struct vnc_write_request* req = calloc(1, sizeof(*req));
|
||||||
if (!req)
|
if (!req)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -40,5 +40,5 @@ int vnc__write(uv_stream_t *stream, const void *payload, size_t size,
|
||||||
req->on_done = on_done;
|
req->on_done = on_done;
|
||||||
|
|
||||||
return uv_write(&req->request, stream, &req->buffer, 1,
|
return uv_write(&req->request, stream, &req->buffer, 1,
|
||||||
on_write_req_done);
|
on_write_req_done);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ static int vec__grow(struct vec* vec, size_t size)
|
||||||
{
|
{
|
||||||
if (likely(vec->len + size < vec->cap))
|
if (likely(vec->len + size < vec->cap))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return vec_reserve(vec, 2 * (vec->len + size));
|
return vec_reserve(vec, 2 * (vec->len + size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
112
src/zrle.c
112
src/zrle.c
|
@ -36,8 +36,8 @@
|
||||||
|
|
||||||
#define UDIV_UP(a, b) (((a) + (b) - 1) / (b))
|
#define UDIV_UP(a, b) (((a) + (b) - 1) / (b))
|
||||||
|
|
||||||
static inline int find_colour_in_palette(uint32_t *palette, int len,
|
static inline int find_colour_in_palette(uint32_t* palette, int len,
|
||||||
uint32_t colour)
|
uint32_t colour)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; ++i)
|
for (int i = 0; i < len; ++i)
|
||||||
if (palette[i] == colour)
|
if (palette[i] == colour)
|
||||||
|
@ -46,7 +46,7 @@ static inline int find_colour_in_palette(uint32_t *palette, int len,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zrle_get_tile_palette(uint32_t *palette, const uint32_t *src, size_t length)
|
int zrle_get_tile_palette(uint32_t* palette, const uint32_t* src, size_t length)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
|
@ -67,22 +67,22 @@ int zrle_get_tile_palette(uint32_t *palette, const uint32_t *src, size_t length)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zrle_encode_unichrome_tile(struct vec *dst,
|
void zrle_encode_unichrome_tile(struct vec* dst,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
uint32_t colour,
|
uint32_t colour,
|
||||||
const struct rfb_pixel_format *src_fmt)
|
const struct rfb_pixel_format* src_fmt)
|
||||||
{
|
{
|
||||||
int bytes_per_cpixel = dst_fmt->depth / 8;
|
int bytes_per_cpixel = dst_fmt->depth / 8;
|
||||||
|
|
||||||
vec_fast_append_8(dst, 1);
|
vec_fast_append_8(dst, 1);
|
||||||
|
|
||||||
pixel32_to_cpixel(((uint8_t*)dst->data) + 1, dst_fmt, &colour, src_fmt,
|
pixel32_to_cpixel(((uint8_t*)dst->data) + 1, dst_fmt, &colour, src_fmt,
|
||||||
bytes_per_cpixel, 1);
|
bytes_per_cpixel, 1);
|
||||||
|
|
||||||
dst->len += bytes_per_cpixel;
|
dst->len += bytes_per_cpixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void encode_run_length(struct vec *dst, uint8_t index, int run_length)
|
void encode_run_length(struct vec* dst, uint8_t index, int run_length)
|
||||||
{
|
{
|
||||||
if (run_length == 1) {
|
if (run_length == 1) {
|
||||||
vec_fast_append_8(dst, index);
|
vec_fast_append_8(dst, index);
|
||||||
|
@ -99,18 +99,17 @@ void encode_run_length(struct vec *dst, uint8_t index, int run_length)
|
||||||
vec_fast_append_8(dst, run_length - 1);
|
vec_fast_append_8(dst, run_length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zrle_encode_packed_tile(struct vec *dst,
|
void zrle_encode_packed_tile(struct vec* dst,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
const uint32_t *src,
|
const uint32_t* src,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
size_t length,
|
size_t length, uint32_t* palette, int palette_size)
|
||||||
uint32_t *palette, int palette_size)
|
|
||||||
{
|
{
|
||||||
int bytes_per_cpixel = dst_fmt->depth / 8;
|
int bytes_per_cpixel = dst_fmt->depth / 8;
|
||||||
|
|
||||||
uint8_t cpalette[16 * 3];
|
uint8_t cpalette[16 * 3];
|
||||||
pixel32_to_cpixel((uint8_t*)cpalette, dst_fmt, palette,
|
pixel32_to_cpixel((uint8_t*)cpalette, dst_fmt, palette, src_fmt,
|
||||||
src_fmt, bytes_per_cpixel, palette_size);
|
bytes_per_cpixel, palette_size);
|
||||||
|
|
||||||
vec_fast_append_8(dst, 128 | palette_size);
|
vec_fast_append_8(dst, 128 | palette_size);
|
||||||
|
|
||||||
|
@ -125,30 +124,28 @@ void zrle_encode_packed_tile(struct vec *dst,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = find_colour_in_palette(palette, palette_size,
|
index = find_colour_in_palette(palette, palette_size, src[i - 1]);
|
||||||
src[i - 1]);
|
|
||||||
encode_run_length(dst, index, run_length);
|
encode_run_length(dst, index, run_length);
|
||||||
run_length = 1;
|
run_length = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run_length > 0) {
|
if (run_length > 0) {
|
||||||
index = find_colour_in_palette(palette, palette_size,
|
index = find_colour_in_palette(palette, palette_size,
|
||||||
src[length - 1]);
|
src[length - 1]);
|
||||||
encode_run_length(dst, index, run_length);
|
encode_run_length(dst, index, run_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void zrle_copy_tile(uint32_t *dst, const uint32_t *src, int stride,
|
void zrle_copy_tile(uint32_t* dst, const uint32_t* src, int stride, int width,
|
||||||
int width, int height)
|
int height)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < height; ++y)
|
for (int y = 0; y < height; ++y)
|
||||||
memcpy(dst + y * width, src + y * stride, width * 4);
|
memcpy(dst + y * width, src + y * stride, width * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zrle_encode_tile(struct vec *dst, const struct rfb_pixel_format *dst_fmt,
|
void zrle_encode_tile(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
const uint32_t *src,
|
const uint32_t* src,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
const struct rfb_pixel_format* src_fmt, size_t length)
|
||||||
size_t length)
|
|
||||||
{
|
{
|
||||||
int bytes_per_cpixel = dst_fmt->depth / 8;
|
int bytes_per_cpixel = dst_fmt->depth / 8;
|
||||||
|
|
||||||
|
@ -164,20 +161,19 @@ void zrle_encode_tile(struct vec *dst, const struct rfb_pixel_format *dst_fmt,
|
||||||
|
|
||||||
if (palette_size > 1) {
|
if (palette_size > 1) {
|
||||||
zrle_encode_packed_tile(dst, dst_fmt, src, src_fmt, length,
|
zrle_encode_packed_tile(dst, dst_fmt, src, src_fmt, length,
|
||||||
palette, palette_size);
|
palette, palette_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_fast_append_8(dst, 0);
|
vec_fast_append_8(dst, 0);
|
||||||
|
|
||||||
pixel32_to_cpixel(((uint8_t*)dst->data) + 1, dst_fmt, src, src_fmt,
|
pixel32_to_cpixel(((uint8_t*)dst->data) + 1, dst_fmt, src, src_fmt,
|
||||||
bytes_per_cpixel, length);
|
bytes_per_cpixel, length);
|
||||||
|
|
||||||
dst->len += bytes_per_cpixel * length;
|
dst->len += bytes_per_cpixel * length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zrle_deflate(struct vec* dst, const struct vec* src, z_stream* zs,
|
int zrle_deflate(struct vec* dst, const struct vec* src, z_stream* zs, bool flush)
|
||||||
bool flush)
|
|
||||||
{
|
{
|
||||||
int r = Z_STREAM_ERROR;
|
int r = Z_STREAM_ERROR;
|
||||||
|
|
||||||
|
@ -202,18 +198,17 @@ int zrle_deflate(struct vec* dst, const struct vec* src, z_stream* zs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zrle_encode_box(struct vec* out, const struct rfb_pixel_format *dst_fmt,
|
int zrle_encode_box(struct vec* out, const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct nvnc_fb *fb,
|
const struct nvnc_fb* fb,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
const struct rfb_pixel_format* src_fmt, int x, int y,
|
||||||
int x, int y, int stride, int width, int height,
|
int stride, int width, int height, z_stream* zs)
|
||||||
z_stream* zs)
|
|
||||||
{
|
{
|
||||||
int r = -1;
|
int r = -1;
|
||||||
int bytes_per_cpixel = dst_fmt->depth / 8;
|
int bytes_per_cpixel = dst_fmt->depth / 8;
|
||||||
int chunk_size = 1 + bytes_per_cpixel * TILE_LENGTH * TILE_LENGTH;
|
int chunk_size = 1 + bytes_per_cpixel * TILE_LENGTH * TILE_LENGTH;
|
||||||
struct vec in;
|
struct vec in;
|
||||||
|
|
||||||
uint32_t *tile = malloc(TILE_LENGTH * TILE_LENGTH * 4);
|
uint32_t* tile = malloc(TILE_LENGTH * TILE_LENGTH * 4);
|
||||||
if (!tile)
|
if (!tile)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
@ -221,11 +216,11 @@ int zrle_encode_box(struct vec* out, const struct rfb_pixel_format *dst_fmt,
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
struct rfb_server_fb_rect rect = {
|
struct rfb_server_fb_rect rect = {
|
||||||
.encoding = htonl(RFB_ENCODING_ZRLE),
|
.encoding = htonl(RFB_ENCODING_ZRLE),
|
||||||
.x = htons(x),
|
.x = htons(x),
|
||||||
.y = htons(y),
|
.y = htons(y),
|
||||||
.width = htons(width),
|
.width = htons(width),
|
||||||
.height = htons(height),
|
.height = htons(height),
|
||||||
};
|
};
|
||||||
|
|
||||||
r = vec_append(out, &rect, sizeof(rect));
|
r = vec_append(out, &rect, sizeof(rect));
|
||||||
|
@ -236,24 +231,26 @@ int zrle_encode_box(struct vec* out, const struct rfb_pixel_format *dst_fmt,
|
||||||
size_t size_index = out->len;
|
size_t size_index = out->len;
|
||||||
vec_append_zero(out, 4);
|
vec_append_zero(out, 4);
|
||||||
|
|
||||||
int n_tiles =
|
int n_tiles = UDIV_UP(width, TILE_LENGTH) * UDIV_UP(height, TILE_LENGTH);
|
||||||
UDIV_UP(width, TILE_LENGTH) * UDIV_UP(height, TILE_LENGTH);
|
|
||||||
|
|
||||||
for (int i = 0; i < n_tiles; ++i) {
|
for (int i = 0; i < n_tiles; ++i) {
|
||||||
int tile_x = (i % UDIV_UP(width, TILE_LENGTH)) * TILE_LENGTH;
|
int tile_x = (i % UDIV_UP(width, TILE_LENGTH)) * TILE_LENGTH;
|
||||||
int tile_y = (i / UDIV_UP(width, TILE_LENGTH)) * TILE_LENGTH;
|
int tile_y = (i / UDIV_UP(width, TILE_LENGTH)) * TILE_LENGTH;
|
||||||
|
|
||||||
int tile_width = width - tile_x >= TILE_LENGTH ? TILE_LENGTH : width - tile_x;
|
int tile_width = width - tile_x >= TILE_LENGTH ? TILE_LENGTH
|
||||||
int tile_height = height - tile_y >= TILE_LENGTH ? TILE_LENGTH : height - tile_y;
|
: width - tile_x;
|
||||||
|
int tile_height = height - tile_y >= TILE_LENGTH
|
||||||
|
? TILE_LENGTH
|
||||||
|
: height - tile_y;
|
||||||
|
|
||||||
int y_off = y + tile_y;
|
int y_off = y + tile_y;
|
||||||
|
|
||||||
zrle_copy_tile(tile,
|
zrle_copy_tile(tile,
|
||||||
((uint32_t*)fb->addr) + x + tile_x + y_off * stride,
|
((uint32_t*)fb->addr) + x + tile_x + y_off * stride,
|
||||||
stride, tile_width, tile_height);
|
stride, tile_width, tile_height);
|
||||||
|
|
||||||
zrle_encode_tile(&in, dst_fmt, tile, src_fmt,
|
zrle_encode_tile(&in, dst_fmt, tile, src_fmt,
|
||||||
tile_width * tile_height);
|
tile_width * tile_height);
|
||||||
|
|
||||||
r = zrle_deflate(out, &in, zs, i == n_tiles - 1);
|
r = zrle_deflate(out, &in, zs, i == n_tiles - 1);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -270,25 +267,24 @@ failure:
|
||||||
#undef CHUNK
|
#undef CHUNK
|
||||||
}
|
}
|
||||||
|
|
||||||
int zrle_encode_frame(z_stream *zs,
|
int zrle_encode_frame(z_stream* zs, struct vec* dst,
|
||||||
struct vec* dst,
|
const struct rfb_pixel_format* dst_fmt,
|
||||||
const struct rfb_pixel_format *dst_fmt,
|
const struct nvnc_fb* src,
|
||||||
const struct nvnc_fb *src,
|
const struct rfb_pixel_format* src_fmt,
|
||||||
const struct rfb_pixel_format *src_fmt,
|
struct pixman_region16* region)
|
||||||
struct pixman_region16 *region)
|
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
int n_rects = 0;
|
int n_rects = 0;
|
||||||
struct pixman_box16 *box = pixman_region_rectangles(region, &n_rects);
|
struct pixman_box16* box = pixman_region_rectangles(region, &n_rects);
|
||||||
if (n_rects > UINT16_MAX) {
|
if (n_rects > UINT16_MAX) {
|
||||||
box = pixman_region_extents(region);
|
box = pixman_region_extents(region);
|
||||||
n_rects = 1;
|
n_rects = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rfb_server_fb_update_msg head = {
|
struct rfb_server_fb_update_msg head = {
|
||||||
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
||||||
.n_rects = htons(n_rects),
|
.n_rects = htons(n_rects),
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = vec_append(dst, &head, sizeof(head));
|
rc = vec_append(dst, &head, sizeof(head));
|
||||||
|
@ -302,7 +298,7 @@ int zrle_encode_frame(z_stream *zs,
|
||||||
int box_height = box[i].y2 - y;
|
int box_height = box[i].y2 - y;
|
||||||
|
|
||||||
rc = zrle_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
rc = zrle_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
||||||
src->width, box_width, box_height, zs);
|
src->width, box_width, box_height, zs);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue