diff options
Diffstat (limited to 'apps/graphics/traveler/src/trv_graphics.c')
-rwxr-xr-x | apps/graphics/traveler/src/trv_graphics.c | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/apps/graphics/traveler/src/trv_graphics.c b/apps/graphics/traveler/src/trv_graphics.c new file mode 100755 index 000000000..6742147aa --- /dev/null +++ b/apps/graphics/traveler/src/trv_graphics.c @@ -0,0 +1,572 @@ +/**************************************************************************** + * apps/graphics/traveler/src/trv_graphics.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 "trv_types.h" +#include "trv_main.h" +#include "trv_mem.h" +#include "trv_color.h" +#include "trv_debug.h" +#include "trv_graphics.h" + +#include <string.h> +#ifdef CONFIG_NX_MULTIUSER +# include <semaphore.h> +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_NX +FAR const struct nx_callback_s *g_trv_nxcallback; +sem_t g_trv_nxevent = SEM_INITIZIALIZER(0); +bool g_trv_nxresolution = false; +#ifdef CONFIG_NX_MULTIUSER +bool g_trv_nxrconnected = false; +#endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trv_get_fbdev + * + * Description: + * Get the system framebuffer device + * + ****************************************************************************/ + +#ifndef CONFIG_NX_MULTIUSER +static FAR struct fb_vtable_s *trv_get_fbdev(void) +{ + FAR struct fb_vtable_s *fbdev; + int ret; + + /* Initialize the frame buffer device */ + + ret = up_fbinitialize(); + if (ret < 0) + { + trv_abort("up_fbinitialize failed: %d\n", -ret); + } + + /* Set up to use video plane 0. There is no support for anything but + * video plane 0. + */ + + fbdev = up_fbgetvplane(0); + if (!fbdev) + { + trv_abort("up_fbgetvplane(0) failed\n"); + } + + return fbdev; +} +#endif + +/**************************************************************************** + * Name: trv_fb_initialize + * + * Description: + * Get the system framebuffer device + * + ****************************************************************************/ + +#if !defined(CONFIG_NX_MULTIUSER) && !defined(CONFIG_NX) +static void trv_fb_initialize(FAR struct trv_graphics_info_s *ginfo) +{ + struct fb_videoinfo_s vinfo; + struct fb_planeinfo_s pinfo; + FAR struct fb_vtable_s *fbdev; + int ret; + + /* Get the framebuffer device */ + + fbdev = trv_get_fbdev(); + + /* Get information about video plane 0 */ + + ret = fbdev->getvideoinfo(fbdev, &vinfo); + if (ret < 0) + { + trv_abort("getvideoinfo() failed\n"); + } + + ginfo->hwwidth = vinfo.xres; + ginfo->hwheight = vinfo.yres; + + ret = fbdev->getplaneinfo(fbdev, 0, &pinfo); + if (ret < 0) + { + trv_abort("getplaneinfo() failed\n"); + } + + ginfo->stride = pinfo.stride; + ginfo->hwbuffer = pinfo.fbmem; + + if (vinfo.fmt != TRV_COLOR_FMT || pinfo.bpp != TRV_BPP) + { + trv_abort("Bad color format(%d)/bpp(%b)\n", vinfo.fmt, pinfo.bpp); + } +} +#endif + +/**************************************************************************** + * Name: trv_use_bgwindow + * + * Description: + * Get the NX background window + * + ****************************************************************************/ + +#ifdef CONFIG_NX +static void trv_use_bgwindow(FAR struct trv_graphics_info_s *ginfo) +{ + /* Get the background window */ + + ret = nx_requestbkgd(g_hnx, &g_trv_nxcallback, ginfo); + if (ret < 0) + { + trv_abort("nx_requestbkgd failed: %d\n", errno); + } + + /* Wait until we have the screen resolution. We'll have this immediately + * unless we are dealing with the NX server. + */ + + while (!g_trv_nxresolution) + { + (void)sem_wait(&g_trv_nxevent); + } +} +#endif + +/**************************************************************************** + * Name: trv_nxsu_initialize + ****************************************************************************/ + +#if defined(CONFIG_NX) && !defined(CONFIG_NX_MULTIUSER) +static inline int trv_nxsu_initialize(FAR struct trv_graphics_info_s *ginfo) +{ + FAR struct fb_vtable_s *fbdev; + int ret; + + /* Get the framebuffer device */ + + fbdev = trv_get_fbdev(); + + /* Open NX */ + + ginfo->hnx = nx_open(fbdev); + if (!ginfo->hnx) + { + trv_abort("trv_nxsu_initialize: nx_open failed: %d\n", errno); + } + + /* And use the background window */ + + trv_use_bgwindow(ginfo); +} +#endif + +/**************************************************************************** + * Name: trv_servertask + ****************************************************************************/ + +#ifdef CONFIG_NX_MULTIUSER +int trv_servertask(int argc, char *argv[]) +{ + FAR struct fb_vtable_s *fbdev; + int ret; + + /* Get the framebuffer device */ + + fbdev = trv_get_fbdev(); + + /* Then start the server */ + + ret = nx_run(dev); + trv_abort("nx_run returned: %d\n", errno); +} +#endif + +/**************************************************************************** + * Name: trv_nxmu_initialize + ****************************************************************************/ + +#ifdef CONFIG_NX_MULTIUSER +static inline int trv_nxmu_initialize(FAR struct trv_graphics_info_s *ginfo) +{ + struct sched_param param; + pthread_t thread; + pid_t servrid; + int ret; + + /* Set the client task priority */ + + param.sched_priority = CONFIG_EXAMPLES_NX_CLIENTPRIO; + ret = sched_setparam(0, ¶m); + if (ret < 0) + { + printf("nxeg_initialize: sched_setparam failed: %d\n" , ret); + g_exitcode = NXEXIT_SCHEDSETPARAM; + return ERROR; + } + + /* Start the server task */ + + printf("nxeg_initialize: Starting trv_servertask task\n"); + servrid = task_create("NX Server", CONFIG_EXAMPLES_NX_SERVERPRIO, + CONFIG_EXAMPLES_NX_STACKSIZE, trv_servertask, NULL); + if (servrid < 0) + { + printf("nxeg_initialize: Failed to create trv_servertask task: %d\n", errno); + g_exitcode = NXEXIT_TASKCREATE; + return ERROR; + } + + /* Wait a bit to let the server get started */ + + sleep(1); + + /* Connect to the server */ + + ginfo->hnx = nx_connect(); + if (ginfo->hnx) + { + pthread_attr_t attr; + + /* Start a separate thread to listen for server events. This is probably + * the least efficient way to do this, but it makes this example flow more + * smoothly. + */ + + (void)pthread_attr_init(&attr); + param.sched_priority = CONFIG_EXAMPLES_NX_LISTENERPRIO; + (void)pthread_attr_setschedparam(&attr, ¶m); + (void)pthread_attr_setstacksize(&attr, CONFIG_EXAMPLES_NX_STACKSIZE); + + ret = pthread_create(&thread, &attr, trv_nxlistener, NULL); + if (ret != 0) + { + printf("nxeg_initialize: pthread_create failed: %d\n", ret); + g_exitcode = NXEXIT_PTHREADCREATE; + return ERROR; + } + + /* Don't return until we are connected to the server */ + + while (!g_trv_nxrconnected) + { + /* Wait for the listener thread to wake us up when we really + * are connected. + */ + + (void)sem_wait(&g_trv_nxevent); + } + } + else + { + printf("nxeg_initialize: nx_connect failed: %d\n", errno); + g_exitcode = NXEXIT_NXCONNECT; + return ERROR; + } + + /* And use the background window */ + + trv_use_bgwindow(ginfo); +} +#endif + +/**************************************************************************** + * Name: trv_row_update + * + * Description: + * Expand one one either directly into the frame buffer or else into an + * intermediate line buffer. + * + ****************************************************************************/ + +void trv_row_update(struct trv_graphics_info_s *ginfo, + FAR const trv_pixel_t *src, + FAR dev_pixel_t *dest) +{ + trv_coord_t hexpand; + dev_pixel_t pixel; + trv_coord_t srccol; + int i; + + /* Loop for each column in the src render buffer */ + + hexpand = (1 << ginfo->hscale); + + for (srccol = 0; srccol < ginfo->swwidth; srccol++) + { + /* Map the source pixel */ + + pixel = ginfo->palette.lut[*src++]; + + /* Copy it to the destination, expanding as necessary */ + + for (i = 0; i < hexpand; i++) + { + *dest++ = pixel; + } + } +} + +/**************************************************************************** + * Name: trv_row_tranfer + * + * Description: + * Transfer one line from the line buffer to the NX window. + * + ****************************************************************************/ + +#ifdef CONFIG_NX +void trv_display_update(struct trv_graphics_info_s *ginfo, + FAR dev_pixel_t *dest, trv_coord_t destrow) +{ + /* Transfer the row buffer to the NX window */ +#warning Missing logic + +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trv_graphics_initialize + * + * Description: + ****************************************************************************/ + +int trv_graphics_initialize(FAR struct trv_graphics_info_s *ginfo) +{ + int swwidth; + int swheight; + int scale; + int ret; + + /* Initialize the graphics device and get information about the display */ + +#if !defined(CONFIG_NX) + trv_fb_initialize(ginfo); +#elif defined(CONFIG_NX_MULTIUSER) + trv_nxmu_initialize(ginfo); +#else + trv_nxsu_initialize(ginfo); +#endif + + /* Check if we need to scale the image */ + + swwidth = ginfo->hwwidth; + scale = 0; + + while (swwidth > MAX_REND_WIDTH) + { + swwidth >>= 1; + scale++; + } + + ginfo->swwidth = swwidth; + ginfo->hscale = scale; + + swheight = ginfo->hwheight; + scale = 0; + + while (swheight > MAX_REND_WIDTH) + { + swheight >>= 1; + scale++; + } + + ginfo->swheight = swheight; + ginfo->vscale = scale; + + /* Allocate buffers + * + * ginfo->swbuffer - Software renders into this buffer using an 8-bit + * encoding and perhaps at a different resolution that the final + * image. + */ + + ginfo->swbuffer = (trv_pixel_t*) + trv_malloc(swwidth * swheight * sizeof(trv_pixel_t)); + if (!ginfo->swbuffer) + { + trv_abort("ERROR: Failed to allocate render buffer\n"); + } + + /* Using the framebuffer driver: + * ginfo->hwbuffer - This address of the final, expanded frame image. + * This address is determined by hardware and is neither allocated + * nor freed. + * + * Using NX + * ginfo->hwbuffer - This address of one line of the final expanded + * image that must transferred to the window. + */ + +#ifdef CONFIG_NX + ginfo->hwbuffer = (trv_pixel_t*) + trv_malloc(ginfo->hwwidth * sizeof(dev_pixel_t)); + if (!ginfo->hwbuffer) + { + trv_abort("ERROR: Failed to allocate hardware line buffer\n"); + } +#endif + + /* Allocate color mapping information */ + + ret = trv_color_allocate(&ginfo->palette); + if (ret < 0) + { + trv_abort("ERROR trv_color_allocate failed: %d"); + } + + trv_vdebug("%d colors allocated\n", ginfo->palette.ncolors); + return OK; +} + +/**************************************************************************** + * Name: trv_graphics_terminate + * + * Description: + ****************************************************************************/ + +void trv_graphics_terminate(FAR struct trv_graphics_info_s *ginfo) +{ + /* Free palette */ + + trv_color_free(&ginfo->palette); + + /* Free image buffers */ + + if (ginfo->swbuffer) + { + trv_free(ginfo->swbuffer); + ginfo->swbuffer = NULL; + } + +#ifdef CONFIG_NX + if (ginfo->hwbuffer) + { + trv_free(ginfo->hwbuffer); + ginfo->hwbuffer = NULL; + } + + /* Close/disconnect NX */ +#warning "Missing Logic" +#endif +} + +/**************************************************************************** + * Name: trv_display_update + * + * Description: + ****************************************************************************/ + +void trv_display_update(struct trv_graphics_info_s *ginfo) +{ + FAR const uint8_t *src = (FAR const uint8_t *)ginfo->swbuffer; + FAR uint8_t *dest = (FAR uint8_t *)ginfo->hwbuffer; + trv_coord_t srcrow; +#ifdef CONFIG_NX + trv_coord_t destrow; +#else + FAR uint8_t *first; + trv_coord_t lnwidth; +#endif + trv_coord_t vexpand; + int i; + + /* Loop for each row in the srce render buffer */ + + vexpand = (1 << ginfo->vscale); +#ifdef CONFIG_NX + destrow = 0; +#else + lnwidth = ginfo->hwwidth * sizeof(dev_pixel_t); +#endif + + for (srcrow = 0; srcrow < ginfo->swheight; srcrow++) + { + /* Transfer the row to the device row/buffer */ + + trv_row_update(ginfo, (FAR const trv_pixel_t *)src, + (FAR dev_pixel_t *)dest); + +#ifdef CONFIG_NX + /* Transfer the row buffer to the NX window */ + + trv_row_tranfer(ginfo, dest, destrow); + destrow++; +#else + first = dest; + dest += ginfo->stride; +#endif + + /* Then replicate as many times as is necessary */ + + for (i = 1; i < vexpand; i++) + { +#ifdef CONFIG_NX + /* Transfer the row buffer to the NX window */ + + trv_row_tranfer(ginfo, dest, destrow); + destrow++; +#else + /* Point to the next row in the frame buffer */ + + memcpy(dest, first, lnwidth); + dest += ginfo->stride; +#endif + } + + /* Point to the next src row */ + + src += ginfo->swwidth; + } +} + |