diff --git a/graphics/vnc/server/Make.defs b/graphics/vnc/server/Make.defs index 263be54df6..c1b9390ca0 100644 --- a/graphics/vnc/server/Make.defs +++ b/graphics/vnc/server/Make.defs @@ -35,7 +35,8 @@ ifeq ($(CONFIG_VNCSERVER),y) -CSRCS += vnc_server.c vnc_negotiate.c vnc_updater.c vnc_receiver.c vnc_fbdev.c +CSRCS += vnc_server.c vnc_negotiate.c vnc_updater.c vnc_receiver.c +CSRCS += vnc_raw.c vnc_color.c vnc_fbdev.c ifeq ($(CONFIG_NX_KBD),y) CSRCS += vnc_keymap.c diff --git a/graphics/vnc/server/vnc_color.c b/graphics/vnc/server/vnc_color.c new file mode 100644 index 0000000000..eba85ba744 --- /dev/null +++ b/graphics/vnc/server/vnc_color.c @@ -0,0 +1,197 @@ +/**************************************************************************** + * graphics/vnc/vnc_color.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "vnc_server.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vnc_convert_rgbNN + * + * Description: + * Convert the native framebuffer color format (either RGB16 5:6:5 or RGB32 + * 8:8:8) to the remote framebuffer color format (either RGB16 5:6:5, + * RGB16 5:5:5, or RGB32 8:8:) + * + * Input Parameters: + * pixel - The src color in local framebuffer format. + * + * Returned Value: + * The pixel in the remote framebuffer color format. + * + ****************************************************************************/ + +#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) + +uint8_t vnc_convert_rgb8_222(lfb_color_t rgb) +{ + /* 111111 + * 54321098 76543210 + * ----------------- + * RRRRRGGG GGGBBBBB + * ..RRGGBB + */ + + return (uint8_t)(((rgb >> 10) & 0x0030) | + ((rgb >> 7) & 0x000c) | + ((rgb >> 3) & 0x0003)); +} + +uint8_t vnc_convert_rgb8_332(lfb_color_t rgb) +{ + /* 111111 + * 54321098 76543210 + * ----------------- + * RRRRRGGG GGGBBBBB + * RRRGGGBB + */ + + return (uint8_t)(((rgb >> 8) & 0x0070) | + ((rgb >> 6) & 0x001c) | + ((rgb >> 3) & 0x0003)); +} + +uint16_t vnc_convert_rgb16_555(lfb_color_t rgb) +{ + /* 111111 + * 54321098 76543210 + * ----------------- + * RRRRRGGG GGGBBBBB + * .RRRRRGG GGGBBBBB + */ + + return (((rgb >> 1) & ~0x1f) | (rgb & 0x1f)); +} + +uint16_t vnc_convert_rgb16_565(lfb_color_t rgb) +{ + /* Identity mapping */ + + return rgb; +} + +uint32_t vnc_convert_rgb32_888(lfb_color_t rgb) +{ + /* 33222222 22221111 111111 + * 10987654 32109876 54321098 76543210 + * ---------------------------------- + * RRRRRGGG GGGBBBBB + * RRRRR... GGGGGG.. BBBBB... + */ + + return (((uint32_t)rgb << 8) & 0x00f80000) | + (((uint32_t)rgb << 6) & 0x0000fc00) | + (((uint32_t)rgb << 3) & 0x000000f8); +} + +#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) + +uint8_t vnc_convert_rgb8_222(lfb_color_t rgb) +{ + /* 33222222 22221111 111111 + * 10987654 32109876 54321098 76543210 + * ----------------------------------- + * RRRRRRRR GGGGGGGG BBBBBBBB + * ..RRGGBB + */ + + return (uint8_t)(((rgb >> 18) & 0x0030) | + ((rgb >> 12) & 0x000c) | + (rgb >> 6) & 0x0003)); +} + +uint8_t vnc_convert_rgb8_332(lfb_color_t rgb) +{ + /* 33222222 22221111 111111 + * 10987654 32109876 54321098 76543210 + * ----------------------------------- + * RRRRRRRR GGGGGGGG BBBBBBBB + * RRRGGGBB + */ + + return (uint8_t)(((rgb >> 16) & 0x0070) | + ((rgb >> 11) & 0x001c) | + (rgb >> 6) & 0x0003)); +} + +uint16_t vnc_convert_rgb16_555(lfb_color_t rgb) +{ + /* 33222222 22221111 111111 + * 10987654 32109876 54321098 76543210 + * ----------------------------------- + * RRRRRRRR GGGGGGGG BBBBBBBB + * .RRRRRGG GGGBBBBB + */ + + return (uint16_t) + (((rgb >> 9) & 0x00007c00) | + ((rgb >> 6) & 0x000003e0) | + ((rgb >> 3) & 0x0000001f)); +} + +uint16_t vnc_convert_rgb16_565(lfb_color_t rgb) +{ + /* 33222222 22221111 111111 + * 10987654 32109876 54321098 76543210 + * ----------------------------------- + * RRRRRRRR GGGGGGGG BBBBBBBB + * RRRRRGGG GGGBBBBB + */ + + return (uint16_t) + (((rgb >> 8) & 0x0000f800) | + ((rgb >> 5) & 0x000007e0) | + ((rgb >> 3) & 0x0000001f)); +} + +uint32_t vnc_convert_rgb32_888(lfb_color_t rgb) +{ + /* Identity mapping */ + + return rgb; +} +#else +# error Unspecified/unsupported color format +#endif diff --git a/graphics/vnc/server/vnc_raw.c b/graphics/vnc/server/vnc_raw.c new file mode 100644 index 0000000000..ef833f2f90 --- /dev/null +++ b/graphics/vnc/server/vnc_raw.c @@ -0,0 +1,462 @@ +/**************************************************************************** + * graphics/vnc/vnc_raw.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "vnc_server.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vnc_copy8 + * + * Description: + * Copy a 16/32-bit pixels from the source rectangle to a 8-bit pixel + * destination rectangle. + * + * Input Parameters: + * session - A reference to the VNC session structure. + * row,col - The upper left X/Y (pixel/row) position of the rectangle + * width,height - The width (pixels) and height (rows of the rectangle) + * convert - The function to use to convert from the local framebuffer + * color format to the remote framebuffer color format. + * + * Returned Value: + * The size of the transfer in bytes. + * + ****************************************************************************/ + +static size_t vnc_copy8(FAR struct vnc_session_s *session, + nxgl_coord_t row, nxgl_coord_t col, + nxgl_coord_t height, nxgl_coord_t width, + vnc_convert8_t convert) +{ + FAR struct rfb_framebufferupdate_s *update; + FAR const uint16_t *srcleft; + FAR const lfb_color_t *src; + FAR uint8_t *dest; + nxgl_coord_t x; + nxgl_coord_t y; + + /* Destination rectangle start address */ + + update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; + dest = (FAR uint8_t *)update->rect[0].data; + + /* Source rectangle start address (left/top)*/ + + srcleft = (FAR lfb_color_t *) + (session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); + + /* Transfer each row from the source buffer into the update buffer */ + + for (y = 0; y < height; y++) + { + src = srcleft; + for (x = 0; x < width; x++) + { + *dest++ = convert(*src); + src++; + } + + srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE); + } + + return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); +} + +/**************************************************************************** + * Name: vnc_copy16 + * + * Description: + * Copy a 16/32-bit pixels from the source rectangle to a 16-bit pixel + * destination rectangle. + * + * Input Parameters: + * session - A reference to the VNC session structure. + * row,col - The upper left X/Y (pixel/row) position of the rectangle + * width,height - The width (pixels) and height (rows of the rectangle) + * convert - The function to use to convert from the local framebuffer + * color format to the remote framebuffer color format. + * + * Returned Value: + * The size of the transfer in bytes. + * + ****************************************************************************/ + +static size_t vnc_copy16(FAR struct vnc_session_s *session, + nxgl_coord_t row, nxgl_coord_t col, + nxgl_coord_t height, nxgl_coord_t width, + vnc_convert16_t convert) +{ + FAR struct rfb_framebufferupdate_s *update; + FAR const uint16_t *srcleft; + FAR const lfb_color_t *src; + FAR uint16_t *dest; + nxgl_coord_t x; + nxgl_coord_t y; + + /* Destination rectangle start address */ + + update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; + dest = (FAR lfb_color_t *)update->rect[0].data; + + /* Source rectangle start address (left/top)*/ + + srcleft = (FAR uint16_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); + + /* Transfer each row from the source buffer into the update buffer */ + + for (y = 0; y < height; y++) + { + src = srcleft; + for (x = 0; x < width; x++) + { + *dest++ = convert(*src); + src++; + } + + srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE); + } + + return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); +} + +/**************************************************************************** + * Name: vnc_copy32 + * + * Description: + * Copy a 16/32-bit pixels from the source rectangle to a 32-bit pixel + * destination rectangle. + * + * Input Parameters: + * session - A reference to the VNC session structure. + * row,col - The upper left X/Y (pixel/row) position of the rectangle + * width,height - The width (pixels) and height (rows of the rectangle) + * convert - The function to use to convert from the local framebuffer + * color format to the remote framebuffer color format. + * + * Returned Value: + * The size of the transfer in bytes. + * + ****************************************************************************/ + +static size_t vnc_copy32(FAR struct vnc_session_s *session, + nxgl_coord_t row, nxgl_coord_t col, + nxgl_coord_t height, nxgl_coord_t width, + vnc_convert32_t convert) +{ + FAR struct rfb_framebufferupdate_s *update; + FAR const uint16_t *srcleft; + FAR const lfb_color_t *src; + FAR uint32_t *dest; + nxgl_coord_t x; + nxgl_coord_t y; + + /* Destination rectangle start address */ + + update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; + dest = (FAR uint32_t *)update->rect[0].data; + + /* Source rectangle start address (left/top)*/ + + srcleft = (FAR lfb_color_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); + + /* Transfer each row from the source buffer into the update buffer */ + + for (y = 0; y < height; y++) + { + src = srcleft; + for (x = 0; x < width; x++) + { + *dest++ = convert(*src); + src++; + } + + srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE); + } + + return (size_t)((uintptr_t)srcleft - (uintptr_t)update->rect[0].data); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vnc_raw + * + * Description: + * As a fallback, send the framebuffer update using the RAW encoding which + * must be supported by all VNC clients. + * + * Input Parameters: + * pixel - The src color in local framebuffer format. + * rect - Describes the rectangle in the local framebuffer. + * + * Returned Value: + * Zero (OK) on success; A negated errno value is returned on failure that + * indicates the the natture of the failure. A failure is only returned + * in cases of a network failure and unexpected internal failures. + * + ****************************************************************************/ + +int vnc_raw(FAR struct vnc_session_s *session, FAR struct nxgl_rect_s *rect) +{ + FAR struct rfb_framebufferupdate_s *update; + FAR const uint8_t *src; + nxgl_coord_t srcwidth; + nxgl_coord_t srcheight; + nxgl_coord_t destwidth; + nxgl_coord_t destheight; + nxgl_coord_t deststride; + nxgl_coord_t updwidth; + nxgl_coord_t updheight; + nxgl_coord_t width; + nxgl_coord_t x; + nxgl_coord_t y; + unsigned int bytesperpixel; + unsigned int maxwidth; + size_t size; + ssize_t nsent; + uint8_t colorfmt; + + union + { + vnc_convert8_t bpp8; + vnc_convert16_t bpp16; + vnc_convert32_t bpp32; + } convert; + + /* Set up characteristics of the client pixel format to use on this + * update. These can change at any time if a SetPixelFormat is + * received asynchronously. + */ + + bytesperpixel = (session->bpp + 7) >> 3; + maxwidth = CONFIG_VNCSERVER_UPDATE_BUFSIZE / bytesperpixel; + + /* Set up the color conversion */ + + colorfmt = session->colorfmt; + switch (colorfmt) + { + case FB_FMT_RGB8_222: + convert.bpp8 = vnc_convert_rgb8_222; + break; + + case FB_FMT_RGB8_332: + convert.bpp8 = vnc_convert_rgb8_332; + break; + + case FB_FMT_RGB16_555: + convert.bpp16 = vnc_convert_rgb16_555; + break; + + case FB_FMT_RGB16_565: + convert.bpp16 = vnc_convert_rgb16_565; + break; + + case FB_FMT_RGB32: + convert.bpp32 = vnc_convert_rgb32_888; + break; + + default: + gdbg("ERROR: Unrecognized color format: %d\n", session->colorfmt); + return -EINVAL; + } + + /* Get with width and height of the source and destination rectangles. + * The source rectangle many be larger than the destination rectangle. + * In that case, we will have to emit multiple rectangles. + */ + + DEBUGASSERT(rect->pt1.x <= rect->pt2.x); + srcwidth = rect->pt2.x - rect->pt1.x + 1; + + DEBUGASSERT(rect->pt1.y <= rect->pt2.y); + srcheight = rect->pt2.y - rect->pt1.y + 1; + + deststride = srcwidth * bytesperpixel; + if (deststride > maxwidth) + { + deststride = maxwidth; + } + + destwidth = deststride / bytesperpixel; + destheight = CONFIG_VNCSERVER_UPDATE_BUFSIZE / deststride; + + if (destheight > srcheight) + { + destheight = srcheight; + } + + /* Format the rectangle header. We may have to send several update + * messages if the pre-allocated outbuf is smaller than the rectangle. + * Each update contains a small "sub-rectangle" of the origin update. + * + * Loop until all sub-rectangles have been output. Start with the + * top row and transfer rectangles horizontally across each swath. + * The height of the swath is destwidth (the last may be shorter). + * + * NOTE that the loop also terminates of the color format changes + * asynchronously. + */ + + for (y = rect->pt1.y; + srcheight > 0 && colorfmt == session->colorfmt; + srcheight -= updheight, y += updheight) + { + /* updheight = Height to update on this pass through the loop. + * This will be destheight unless fewer than that number of rows + * remain. + */ + + updheight = destheight; + if (updheight > srcheight) + { + updheight = srcheight; + } + + /* Loop until this horizontal swath has sent to the VNC client. + * Start with the leftmost pixel and transfer rectangles + * horizontally with width of destwidth until all srcwidth + * columns have been transferred (the last rectangle may be + * narrower). + * + * NOTE that the loop also terminates of the color format + * changes asynchronously. + */ + + for (width = srcwidth, x = rect->pt1.x; + width > 0 && colorfmt == session->colorfmt; + width -= updwidth, x += updwidth) + { + /* updwidth = Width to update on this pass through the loop. + * This will be destwidth unless fewer than that number of + * columns remain. + */ + + updwidth = destwidth; + if (updwidth > width) + { + updwidth = width; + } + + /* Transfer the frame buffer data into the rectangle, + * performing the necessary color conversions. + */ + + if (bytesperpixel == 1) + { + size = vnc_copy8(session, y, x, updheight, updwidth, + convert.bpp8); + } + else if (bytesperpixel == 2) + { + size = vnc_copy16(session, y, x, updheight, updwidth, + convert.bpp16); + } + else /* bytesperpixel == 4 */ + { + size = vnc_copy32(session, y, x, updheight, updwidth, + convert.bpp32); + } + + /* Format the FramebufferUpdate message */ + + update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; + update->msgtype = RFB_FBUPDATE_MSG; + update->padding = 0; + rfb_putbe16(update->nrect, 1); + + rfb_putbe16(update->rect[0].xpos, x); + rfb_putbe16(update->rect[0].ypos, y); + rfb_putbe16(update->rect[0].width, updwidth); + rfb_putbe16(update->rect[0].height, updheight); + rfb_putbe32(update->rect[0].encoding, RFB_ENCODING_RAW); + + DEBUGASSERT(size <= CONFIG_VNCSERVER_UPDATE_BUFSIZE); + + /* We are ready to send the update packet to the VNC client */ + + size += SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0)); + src = session->outbuf; + + /* At the very last most, make certain that the color format + * has not changed asynchronously. + */ + + if (colorfmt == session->colorfmt) + { + /* Okay send until all of the bytes are out. This may + * loop for the case where TCP write buffering is enabled + * and there are a limited number of IOBs available. + */ + + do + { + nsent = psock_send(&session->connect, src, size, 0); + if (nsent < 0) + { + int errcode = get_errno(); + gdbg("ERROR: Send FrameBufferUpdate failed: %d\n", + errcode); + DEBUGASSERT(errcode > 0); + return -errcode; + } + + DEBUGASSERT(nsent <= size); + src += nsent; + size -= nsent; + } + while (size > 0); + } + } + } + + return OK; +} \ No newline at end of file diff --git a/graphics/vnc/server/vnc_server.h b/graphics/vnc/server/vnc_server.h index e45b5563e2..e26ee7601d 100644 --- a/graphics/vnc/server/vnc_server.h +++ b/graphics/vnc/server/vnc_server.h @@ -240,6 +240,22 @@ struct fb_startup_s int16_t result; /* OK: successfully initialized */ }; +/* The size of the color type in the local framebuffer */ + +#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) +typedef uint16_t lfb_color_t; +#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) +typedef uint32_t lfb_color_t; +#else +# error Unspecified/unsupported color format +#endif + +/* Color conversion function pointer types */ + +typedef CODE uint8_t (*vnc_convert8_t) (lfb_color_t rgb); +typedef CODE uint16_t (*vnc_convert16_t)(lfb_color_t rgb); +typedef CODE uint32_t (*vnc_convert32_t)(lfb_color_t rgb); + /**************************************************************************** * Public Data ****************************************************************************/ @@ -388,6 +404,26 @@ int vnc_update_rectangle(FAR struct vnc_session_s *session, int vnc_receiver(FAR struct vnc_session_s *session); +/**************************************************************************** + * Name: vnc_raw + * + * Description: + * As a fallback, send the framebuffer update using the RAW encoding which + * must be supported by all VNC clients. + * + * Input Parameters: + * pixel - The src color in local framebuffer format. + * rect - Describes the rectangle in the local framebuffer. + * + * Returned Value: + * Zero (OK) on success; A negated errno value is returned on failure that + * indicates the the natture of the failure. A failure is only returned + * in cases of a network failure and unexpected internal failures. + * + ****************************************************************************/ + +int vnc_raw(FAR struct vnc_session_s *session, FAR struct nxgl_rect_s *rect); + /**************************************************************************** * Name: vnc_key_map * @@ -428,6 +464,28 @@ void vnc_key_map(FAR struct vnc_session_s *session, uint16_t keysym, FAR struct vnc_session_s *vnc_find_session(int display); +/**************************************************************************** + * Name: vnc_convert_rgbNN + * + * Description: + * Convert the native framebuffer color format (either RGB16 5:6:5 or RGB32 + * 8:8:8) to the remote framebuffer color format (either RGB16 5:6:5, + * RGB16 5:5:5, or RGB32 8:8:) + * + * Input Parameters: + * rgb - The RGB src color in local framebuffer color format. + * + * Returned Value: + * The pixel in the remote framebuffer color format. + * + ****************************************************************************/ + +uint8_t vnc_convert_rgb8_222(lfb_color_t rgb); +uint8_t vnc_convert_rgb8_332(lfb_color_t rgb); +uint16_t vnc_convert_rgb16_555(lfb_color_t rgb); +uint16_t vnc_convert_rgb16_565(lfb_color_t rgb); +uint32_t vnc_convert_rgb32_888(lfb_color_t rgb); + #undef EXTERN #ifdef __cplusplus } diff --git a/graphics/vnc/server/vnc_updater.c b/graphics/vnc/server/vnc_updater.c index ab2fb20083..6a9d1f0e19 100644 --- a/graphics/vnc/server/vnc_updater.c +++ b/graphics/vnc/server/vnc_updater.c @@ -39,16 +39,14 @@ #include +#include #include #include -#include #include #include #include #include -#include - #include "vnc_server.h" /**************************************************************************** @@ -57,24 +55,6 @@ #undef VNCSERVER_SEM_DEBUG -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Color conversion functions */ - -#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) -typedef CODE uint8_t(*vnc_convert8_t)(uint16_t rgb); -typedef CODE uint16_t(*vnc_convert16_t)(uint16_t rgb); -typedef CODE uint32_t(*vnc_convert32_t)(uint16_t rgb); -#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) -typedef CODE uint8_t(*vnc_convert8_t)(uint32_t rgb); -typedef CODE uint16_t(*vnc_convert16_t)(uint32_t rgb); -typedef CODE uint32_t(*vnc_convert32_t)(uint32_t rgb); -#else -# error Unspecified/unsupported color format -#endif - /**************************************************************************** * Private Data ****************************************************************************/ @@ -306,424 +286,6 @@ static void vnc_add_queue(FAR struct vnc_session_s *session, sched_unlock(); } -/**************************************************************************** - * Name: vnc_convert_rgbNN - * - * Description: - * Convert the native framebuffer color format (either RGB16 5:6:5 or RGB32 - * 8:8:8) to the remote framebuffer color format (either RGB16 5:6:5, - * RGB16 5:5:5, or RGB32 8:8:) - * - * Input Parameters: - * pixel - The src color in local framebuffer format. - * - * Returned Value: - * The pixel in the remote framebuffer color format. - * - ****************************************************************************/ - -#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) - -uint8_t vnc_convert_rgb8_222(uint16_t rgb) -{ - /* 111111 - * 54321098 76543210 - * ----------------- - * RRRRRGGG GGGBBBBB - * ..RRGGBB - */ - - return (uint8_t)(((rgb >> 10) & 0x0030) | - ((rgb >> 7) & 0x000c) | - ((rgb >> 3) & 0x0003)); -} - -uint8_t vnc_convert_rgb8_332(uint16_t rgb) -{ - /* 111111 - * 54321098 76543210 - * ----------------- - * RRRRRGGG GGGBBBBB - * RRRGGGBB - */ - - return (uint8_t)(((rgb >> 8) & 0x0070) | - ((rgb >> 6) & 0x001c) | - ((rgb >> 3) & 0x0003)); -} - -uint16_t vnc_convert_rgb16_555(uint16_t rgb) -{ - /* 111111 - * 54321098 76543210 - * ----------------- - * RRRRRGGG GGGBBBBB - * .RRRRRGG GGGBBBBB - */ - - return (((rgb >> 1) & ~0x1f) | (rgb & 0x1f)); -} - -uint16_t vnc_convert_rgb16_565(uint16_t rgb) -{ - /* Identity mapping */ - - return rgb; -} - -uint32_t vnc_convert_rgb32_888(uint16_t rgb) -{ - /* 33222222 22221111 111111 - * 10987654 32109876 54321098 76543210 - * ---------------------------------- - * RRRRRGGG GGGBBBBB - * RRRRR... GGGGGG.. BBBBB... - */ - - return (((uint32_t)rgb << 8) & 0x00f80000) | - (((uint32_t)rgb << 6) & 0x0000fc00) | - (((uint32_t)rgb << 3) & 0x000000f8); -} - -#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) -uint8_t vnc_convert_rgb8_222(uint16_t rgb) -{ - /* 33222222 22221111 111111 - * 10987654 32109876 54321098 76543210 - * ----------------------------------- - * RRRRRRRR GGGGGGGG BBBBBBBB - * ..RRGGBB - */ - - return (uint8_t)(((rgb >> 18) & 0x0030) | - ((rgb >> 12) & 0x000c) | - (rgb >> 6) & 0x0003)); -} - -uint8_t vnc_convert_rgb8_332(uint16_t rgb) -{ - /* 33222222 22221111 111111 - * 10987654 32109876 54321098 76543210 - * ----------------------------------- - * RRRRRRRR GGGGGGGG BBBBBBBB - * RRRGGGBB - */ - - return (uint8_t)(((rgb >> 16) & 0x0070) | - ((rgb >> 11) & 0x001c) | - (rgb >> 6) & 0x0003)); -} - -uint16_t vnc_convert_rgb16_555(uint32_t rgb) -{ - /* 33222222 22221111 111111 - * 10987654 32109876 54321098 76543210 - * ----------------------------------- - * RRRRRRRR GGGGGGGG BBBBBBBB - * .RRRRRGG GGGBBBBB - */ - - return (uint16_t) - (((rgb >> 9) & 0x00007c00) | - ((rgb >> 6) & 0x000003e0) | - ((rgb >> 3) & 0x0000001f)); -} - -uint16_t vnc_convert_rgb16_565(uint32_t rgb) -{ - /* 33222222 22221111 111111 - * 10987654 32109876 54321098 76543210 - * ----------------------------------- - * RRRRRRRR GGGGGGGG BBBBBBBB - * RRRRRGGG GGGBBBBB - */ - - return (uint16_t) - (((rgb >> 8) & 0x0000f800) | - ((rgb >> 5) & 0x000007e0) | - ((rgb >> 3) & 0x0000001f)); -} - -uint32_t vnc_convert_rgb32_888(uint32_t rgb) -{ - /* Identity mapping */ - - return rgb; -} -#else -# error Unspecified/unsupported color format -#endif - -/**************************************************************************** - * Name: vnc_copy8 - * - * Description: - * Copy a 16/32-bit pixels from the source rectangle to a 8-bit pixel - * destination rectangle. - * - * Input Parameters: - * session - A reference to the VNC session structure. - * row,col - The upper left X/Y (pixel/row) position of the rectangle - * width,height - The width (pixels) and height (rows of the rectangle) - * convert - The function to use to convert from the local framebuffer - * color format to the remote framebuffer color format. - * - * Returned Value: - * The size of the transfer in bytes. - * - ****************************************************************************/ - -static size_t vnc_copy8(FAR struct vnc_session_s *session, - nxgl_coord_t row, nxgl_coord_t col, - nxgl_coord_t height, nxgl_coord_t width, - vnc_convert8_t convert) -{ -#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint16_t *srcleft; - FAR const uint16_t *src; - FAR uint8_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint8_t *)update->rect[0].data; - - /* Source rectangle start address (left/top)*/ - - srcleft = (FAR uint16_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - /* Transfer each row from the source buffer into the update buffer */ - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint16_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); - -#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint32_t *srcleft; - FAR const uint32_t *src; - FAR uint8_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint8_t *)update->rect[0].data; - - /* Source rectangle start address */ - - srcleft = (FAR uint32_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint32_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); -#endif -} - -/**************************************************************************** - * Name: vnc_copy16 - * - * Description: - * Copy a 16/32-bit pixels from the source rectangle to a 16-bit pixel - * destination rectangle. - * - * Input Parameters: - * session - A reference to the VNC session structure. - * row,col - The upper left X/Y (pixel/row) position of the rectangle - * width,height - The width (pixels) and height (rows of the rectangle) - * convert - The function to use to convert from the local framebuffer - * color format to the remote framebuffer color format. - * - * Returned Value: - * The size of the transfer in bytes. - * - ****************************************************************************/ - -static size_t vnc_copy16(FAR struct vnc_session_s *session, - nxgl_coord_t row, nxgl_coord_t col, - nxgl_coord_t height, nxgl_coord_t width, - vnc_convert16_t convert) -{ -#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint16_t *srcleft; - FAR const uint16_t *src; - FAR uint16_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint16_t *)update->rect[0].data; - - /* Source rectangle start address (left/top)*/ - - srcleft = (FAR uint16_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - /* Transfer each row from the source buffer into the update buffer */ - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint16_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); - -#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint32_t *srcleft; - FAR const uint32_t *src; - FAR uint16_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint16_t *)update->rect[0].data; - - /* Source rectangle start address */ - - srcleft = (FAR uint32_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint32_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data); -#endif -} - -/**************************************************************************** - * Name: vnc_copy32 - * - * Description: - * Copy a 16/32-bit pixels from the source rectangle to a 32-bit pixel - * destination rectangle. - * - * Input Parameters: - * session - A reference to the VNC session structure. - * row,col - The upper left X/Y (pixel/row) position of the rectangle - * width,height - The width (pixels) and height (rows of the rectangle) - * convert - The function to use to convert from the local framebuffer - * color format to the remote framebuffer color format. - * - * Returned Value: - * The size of the transfer in bytes. - * - ****************************************************************************/ - -static size_t vnc_copy32(FAR struct vnc_session_s *session, - nxgl_coord_t row, nxgl_coord_t col, - nxgl_coord_t height, nxgl_coord_t width, - vnc_convert32_t convert) -{ -#if defined(CONFIG_VNCSERVER_COLORFMT_RGB16) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint16_t *srcleft; - FAR const uint16_t *src; - FAR uint32_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint32_t *)update->rect[0].data; - - /* Source rectangle start address (left/top)*/ - - srcleft = (FAR uint16_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - /* Transfer each row from the source buffer into the update buffer */ - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint16_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)srcleft - (uintptr_t)update->rect[0].data); - -#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32) - FAR struct rfb_framebufferupdate_s *update; - FAR const uint32_t *srcleft; - FAR const uint32_t *src; - FAR uint32_t *dest; - nxgl_coord_t x; - nxgl_coord_t y; - - /* Destination rectangle start address */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - dest = (FAR uint32_t *)update->rect[0].data; - - /* Source rectangle start address */ - - srcleft = (FAR uint32_t *)(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col); - - for (y = 0; y < height; y++) - { - src = srcleft; - for (x = 0; x < width; x++) - { - *dest++ = convert(*src); - src++; - } - - srcleft = (FAR uint32_t *)((uintptr_t)srcleft + RFB_STRIDE); - } - - return (size_t)((uintptr_t)srcleft - (uintptr_t)update->rect[0].data); -#endif -} - /**************************************************************************** * Name: vnc_updater * @@ -742,31 +304,8 @@ static size_t vnc_copy32(FAR struct vnc_session_s *session, static FAR void *vnc_updater(FAR void *arg) { FAR struct vnc_session_s *session = (FAR struct vnc_session_s *)arg; - FAR struct rfb_framebufferupdate_s *update; FAR struct vnc_fbupdate_s *srcrect; - FAR const uint8_t *src; - nxgl_coord_t srcwidth; - nxgl_coord_t srcheight; - nxgl_coord_t destwidth; - nxgl_coord_t destheight; - nxgl_coord_t deststride; - nxgl_coord_t updwidth; - nxgl_coord_t updheight; - nxgl_coord_t width; - nxgl_coord_t x; - nxgl_coord_t y; - unsigned int bytesperpixel; - unsigned int maxwidth; - size_t size; - ssize_t nsent; - uint8_t colorfmt; - - union - { - vnc_convert8_t bpp8; - vnc_convert16_t bpp16; - vnc_convert32_t bpp32; - } convert; + int ret; DEBUGASSERT(session != NULL); gvdbg("Updater running for Display %d\n", session->display); @@ -786,195 +325,23 @@ static FAR void *vnc_updater(FAR void *arg) srcrect = vnc_remove_queue(session); DEBUGASSERT(srcrect != NULL); - /* Set up characteristics of the client pixel format to use on this - * update. These can change at any time if a SetPixelFormat is - * received asynchronously. - */ + /* Perform the framebuffer update using the RAW encoding */ - bytesperpixel = (session->bpp + 7) >> 3; - maxwidth = CONFIG_VNCSERVER_UPDATE_BUFSIZE / bytesperpixel; + ret = vnc_raw(session, &srcrect->rect); - /* Set up the color conversion */ - - colorfmt = session->colorfmt; - switch (colorfmt) - { - case FB_FMT_RGB8_222: - convert.bpp8 = vnc_convert_rgb8_222; - break; - - case FB_FMT_RGB8_332: - convert.bpp8 = vnc_convert_rgb8_332; - break; - - case FB_FMT_RGB16_555: - convert.bpp16 = vnc_convert_rgb16_555; - break; - - case FB_FMT_RGB16_565: - convert.bpp16 = vnc_convert_rgb16_565; - break; - - case FB_FMT_RGB32: - convert.bpp32 = vnc_convert_rgb32_888; - break; - - default: - gdbg("ERROR: Unrecognized color format: %d\n", session->colorfmt); - goto errout; - } - - /* Get with width and height of the source and destination rectangles. - * The source rectangle many be larger than the destination rectangle. - * In that case, we will have to emit multiple rectangles. - */ - - DEBUGASSERT(srcrect->rect.pt1.x <= srcrect->rect.pt2.x); - srcwidth = srcrect->rect.pt2.x - srcrect->rect.pt1.x + 1; - - DEBUGASSERT(srcrect->rect.pt1.y <= srcrect->rect.pt2.y); - srcheight = srcrect->rect.pt2.y - srcrect->rect.pt1.y + 1; - - deststride = srcwidth * bytesperpixel; - if (deststride > maxwidth) - { - deststride = maxwidth; - } - - destwidth = deststride / bytesperpixel; - destheight = CONFIG_VNCSERVER_UPDATE_BUFSIZE / deststride; - - if (destheight > srcheight) - { - destheight = srcheight; - } - - /* Format the rectangle header. We may have to send several update - * messages if the pre-allocated outbuf is smaller than the rectangle. - * Each update contains a small "sub-rectangle" of the origin update. - * - * Loop until all sub-rectangles have been output. Start with the - * top row and transfer rectangles horizontally across each swath. - * The height of the swath is destwidth (the last may be shorter). - * - * NOTE that the loop also terminates of the color format changes - * asynchronously. - */ - - for (y = srcrect->rect.pt1.y; - srcheight > 0 && colorfmt == session->colorfmt; - srcheight -= updheight, y += updheight) - { - /* updheight = Height to update on this pass through the loop. - * This will be destheight unless fewer than that number of rows - * remain. - */ - - updheight = destheight; - if (updheight > srcheight) - { - updheight = srcheight; - } - - /* Loop until this horizontal swath has sent to the VNC client. - * Start with the leftmost pixel and transfer rectangles - * horizontally with width of destwidth until all srcwidth - * columns have been transferred (the last rectangle may be - * narrower). - * - * NOTE that the loop also terminates of the color format - * changes asynchronously. - */ - - for (width = srcwidth, x = srcrect->rect.pt1.x; - width > 0 && colorfmt == session->colorfmt; - width -= updwidth, x += updwidth) - { - /* updwidth = Width to update on this pass through the loop. - * This will be destwidth unless fewer than that number of - * columns remain. - */ - - updwidth = destwidth; - if (updwidth > width) - { - updwidth = width; - } - - /* Transfer the frame buffer data into the rectangle, - * performing the necessary color conversions. - */ - - if (bytesperpixel == 1) - { - size = vnc_copy8(session, y, x, updheight, updwidth, - convert.bpp8); - } - else if (bytesperpixel == 2) - { - size = vnc_copy16(session, y, x, updheight, updwidth, - convert.bpp16); - } - else /* bytesperpixel == 4 */ - { - size = vnc_copy32(session, y, x, updheight, updwidth, - convert.bpp32); - } - - /* Format the FramebufferUpdate message */ - - update = (FAR struct rfb_framebufferupdate_s *)session->outbuf; - update->msgtype = RFB_FBUPDATE_MSG; - update->padding = 0; - rfb_putbe16(update->nrect, 1); - - rfb_putbe16(update->rect[0].xpos, x); - rfb_putbe16(update->rect[0].ypos, y); - rfb_putbe16(update->rect[0].width, updwidth); - rfb_putbe16(update->rect[0].height, updheight); - rfb_putbe32(update->rect[0].encoding, RFB_ENCODING_RAW); - - DEBUGASSERT(size <= CONFIG_VNCSERVER_UPDATE_BUFSIZE); - - /* We are ready to send the update packet to the VNC client */ - - size += SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0)); - src = session->outbuf; - - /* At the very last most, make certain that the color format - * has not changed asynchronously. - */ - - if (colorfmt == session->colorfmt) - { - /* Okay send until all of the bytes are out. This may - * loop for the case where TCP write buffering is enabled - * and there are a limited number of IOBs available. - */ - - do - { - nsent = psock_send(&session->connect, src, size, 0); - if (nsent < 0) - { - gdbg("ERROR: Send FrameBufferUpdate failed: %d\n", - get_errno()); - goto errout; - } - - DEBUGASSERT(nsent <= size); - src += nsent; - size -= nsent; - } - while (size > 0); - } - } - } + /* Release the update structure */ vnc_free_update(session, srcrect); + + /* Break out and terminate the server if the encoding failed */ + + if (ret < 0) + { + gdbg("ERROR: Encoding failed: %d\n", ret); + break; + } } -errout: session->state = VNCSERVER_STOPPED; return NULL; }