VNC: Add some rectangle queuing logic

This commit is contained in:
Gregory Nutt 2016-04-17 16:48:30 -06:00
parent e7f4a02e45
commit df297ec8fc
5 changed files with 188 additions and 16 deletions

View File

@ -71,6 +71,26 @@ config VNCSERVER_SCREENHEIGHT
int "Framebuffer height (rows)"
default 240
config VNCSERVER_NUPDATES
int "Number of pre-allocate update structures"
default 48
---help---
This setting provides the number of pre-allocated update structures
that will be used. Dynamic memory allocations are never made. In
the likely event that we run out of update structures, the graphics
subsystem will pause and wait for the next structures to be released.
Overhead is 12-bytes per update structure.
config VNCSERVER_UPDATE_BUFSIZE
int "Max update buffer size (bytes)"
default 4096
---help---
A single buffer is pre-allocated for rendering updates. This
setting specifies the maximum in bytes of that update buffer. For
example, an update buffers of 32 pixels at 32-bits per pixel and
32-rows would yield a buffer size of 4096.
config VNCSERVER_KBDENCODE
bool "Encode keyboard input"
default n
@ -79,8 +99,8 @@ config VNCSERVER_KBDENCODE
Use a special encoding of keyboard characters as defined in
include/nuttx/input/kbd_coded.h.
config VNCSERVER_IOBUFFER_SIZE
int "I/O buffer size
config VNCSERVER_INBUFFER_SIZE
int "Input buffer size
default 80
endif # VNCSERVER

View File

@ -274,7 +274,7 @@ int vnc_negotiate(FAR struct vnc_session_s *session)
*/
(void)psock_recv(&session->connect, session->inbuf,
CONFIG_VNCSERVER_IOBUFFER_SIZE, 0);
CONFIG_VNCSERVER_INBUFFER_SIZE, 0);
session->state = VNCSERVER_CONFIGURED;
return OK;

View File

@ -41,7 +41,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
#include <queue.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
@ -50,6 +52,7 @@
#include <netinet/in.h>
#include <nuttx/kmalloc.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include "vnc_server.h"
@ -91,6 +94,10 @@ static FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS];
static void vnc_reset_session(FAR struct vnc_session_s *session,
FAR uint8_t *fb)
{
FAR struct vnc_fbupdate_s *curr;
FAR struct vnc_fbupdate_s *next;
int i;
/* Close any open sockets */
if (session->state >= VNCSERVER_CONNECTED)
@ -99,12 +106,29 @@ static void vnc_reset_session(FAR struct vnc_session_s *session,
psock_close(&session->listen);
}
/* [Re-]nitialize the session. Set all values to 0 == NULL == false. */
/* [Re-]initialize the session. */
/* Put all of the pre-allocated update structures into the freelist */
memset(session, 0, sizeof(struct vnc_session_s));
sq_init(&session->updqueue);
/* Then initialize only non-zero values */
session->updfree.head =
(FAR sq_entry_t *)&session->updpool[0];
session->updfree.tail =
(FAR sq_entry_t *)&session->updpool[CONFIG_VNCSERVER_NUPDATES-1];
next = &session->updpool[0];
for (i = 1; i < CONFIG_VNCSERVER_NUPDATES-1; i++)
{
curr = next;
next = &session->updpool[i];
curr->flink = next;
}
next->flink = NULL;
/* Set the INITIALIZED state */
sem_reset(&session->updsem, CONFIG_VNCSERVER_NUPDATES);
session->fb = fb;
session->state = VNCSERVER_INITIALIZED;
}
@ -242,6 +266,7 @@ int vnc_server(int argc, FAR char *argv[])
}
g_vnc_sessions[display] = session;
sem_init(&session->updsem, 0, CONFIG_VNCSERVER_NUPDATES);
/* Loop... handling each each VNC client connection to this display. Only
* a single client is allowed for each display.

View File

@ -43,9 +43,12 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <semaphore.h>
#include <pthread.h>
#include <queue.h>
#include <nuttx/video/fb.h>
#include <nuttx/video/rfb.h>
#include <nuttx/nx/nxglib.h>
#include <nuttx/nx/nx.h>
#include <nuttx/net/net.h>
@ -126,10 +129,21 @@
# define CONFIG_VNCSERVER_UPDATER_STACKSIZE 2048
#endif
#ifndef CONFIG_VNCSERVER_IOBUFFER_SIZE
# define CONFIG_VNCSERVER_IOBUFFER_SIZE 80
#ifndef CONFIG_VNCSERVER_INBUFFER_SIZE
# define CONFIG_VNCSERVER_INBUFFER_SIZE 80
#endif
#ifndef CONFIG_VNCSERVER_NUPDATES
# define CONFIG_VNCSERVER_NUPDATES 48
#endif
#ifndef CONFIG_VNCSERVER_UPDATE_BUFSIZE
# define CONFIG_VNCSERVER_UPDATE_BUFSIZE 4096
#endif
#define VNCSERVER_UPDATE_BUFSIZE \
(CONFIG_VNCSERVER_UPDATE_BUFSIZE + SIZEOF_RFB_FRAMEBUFFERUPDATE_S(0))
/* Local framebuffer characteristics in bytes */
#define RFB_BYTESPERPIXEL ((RFB_BITSPERPIXEL + 7) >> 8)
@ -168,6 +182,16 @@ enum vnc_server_e
VNCSERVER_STOPPING /* The server has been asked to stop */
};
/* This structure is used to queue FrameBufferUpdate event. It includes a
* pointer to support singly linked list.
*/
struct vnc_fbupdate_s
{
FAR struct vnc_fbupdate_s *flink;
struct nxgl_rect_s rect; /* The enqueued update rectangle */
};
struct vnc_session_s
{
/* NX graphics system */
@ -185,15 +209,23 @@ struct vnc_session_s
uint8_t colorfmt; /* Remote color format (See include/nuttx/fb.h) */
uint8_t bpp; /* Remote bits per pixel */
FAR uint8_t *fb; /* Allocated local frame buffer */
/* Updater information */
pthread_t updater; /* Updater thread ID */
/* Update list information */
struct vnc_fbupdate_s updpool[CONFIG_VNCSERVER_NUPDATES];
sq_queue_t updfree;
sq_queue_t updqueue;
sem_t exclsem;
sem_t updsem;
/* I/O buffers for misc network send/receive */
uint8_t inbuf[CONFIG_VNCSERVER_IOBUFFER_SIZE];
uint8_t outbuf[CONFIG_VNCSERVER_IOBUFFER_SIZE];
uint8_t inbuf[CONFIG_VNCSERVER_INBUFFER_SIZE];
uint8_t outbuf[VNCSERVER_UPDATE_BUFSIZE];
};
/****************************************************************************

View File

@ -39,8 +39,11 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <sched.h>
#include <string.h>
#include <pthread.h>
#include <queue.h>
#include <assert.h>
#include <errno.h>
@ -50,6 +53,81 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_alloc_update
*
* Description:
* Allocate one update structure by taking it from the freelist.
*
* Input Parameters:
* session - A reference to the VNC session structure.
*
* Returned Value:
* A non-NULL structure pointer should always be returned. This function
* will wait if no structure is available.
*
****************************************************************************/
static FAR struct vnc_fbupdate_s *
vnc_alloc_update(FAR struct vnc_session_s *session)
{
FAR struct vnc_fbupdate_s *update;
/* Reserve one element from the free list. Lock the scheduler to assure
* that the sq_remfirst() and the successful return for sem_wait are
* atomic. Of course, the scheduler will be unlocked while we wait.
*/
sched_lock();
while (sem_wait(&session->updsem) < 0)
{
DEBUGASSERT(get_errno() == EINTR);
}
/* It is reserved.. go get it */
update = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updfree);
sched_unlock();
DEBUGASSERT(update != NULL);
return update;
}
/****************************************************************************
* Name: vnc_free_update
*
* Description:
* Free one update structure by returning it from the freelist.
*
* Input Parameters:
* Standard pthread arguments.
*
* Returned Value:
* NULL is always returned.
*
****************************************************************************/
static void vnc_free_update(FAR struct vnc_session_s *session,
FAR struct vnc_fbupdate_s *update)
{
/* Reserve one element from the free list. Lock the scheduler to assure
* that the sq_addlast() and the sem_post() are atomic.
*/
sched_lock();
/* Put the entry into the free list */
sq_addlast((FAR sq_entry_t *)update, &session->updfree);
/* Post the semaphore to indicate the availability of one more update */
sem_post(&session->updsem);
DEBUGASSERT(session->updsem.semcount <= CONFIG_VNCSERVER_NUPDATES);
sched_unlock();
}
/****************************************************************************
* Name: vnc_updater
*
@ -189,12 +267,29 @@ int vnc_stop_updater(FAR struct vnc_session_s *session)
int vnc_update_rectangle(FAR struct vnc_session_s *session,
FAR const struct nxgl_rect_s *rect)
{
/* Make sure that the rectangle has a area */
FAR struct vnc_fbupdate_s *update;
if (!nxgl_nullrect(rect))
{
#warning Missing logic
}
/* Make sure that the rectangle has a area */
if (!nxgl_nullrect(rect))
{
/* Allocate an update structure... waiting if necessary */
update = vnc_alloc_update(session);
DEBUGASSERT(update != NULL);
/* Copy the rectangle into the update structure */
memcpy(&update->rect, rect, sizeof(struct nxgl_rect_s));
/* Add the upate to the end of the update queue. Lock the scheduler
* to assure that the sq_addlast() is atomic.
*/
sched_lock();
sq_addlast((FAR sq_entry_t *)update, &session->updqueue);
sched_unlock();
}
return -ENOSYS;
}