1/* Blackfin GUI (SDL) helper code 2 3 Copyright (C) 2010-2020 Free Software Foundation, Inc. 4 Contributed by Analog Devices, Inc. 5 6 This file is part of simulators. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21#include "config.h" 22 23#ifdef HAVE_SDL 24# include <SDL.h> 25#endif 26#ifdef HAVE_DLFCN_H 27# include <dlfcn.h> 28#endif 29 30#include "libiberty.h" 31#include "gui.h" 32 33#ifdef HAVE_SDL 34 35static struct { 36 void *handle; 37 int (*Init) (Uint32 flags); 38 void (*Quit) (void); 39 SDL_Surface *(*SetVideoMode) (int width, int height, int bpp, Uint32 flags); 40 void (*WM_SetCaption) (const char *title, const char *icon); 41 int (*ShowCursor) (int toggle); 42 int (*LockSurface) (SDL_Surface *surface); 43 void (*UnlockSurface) (SDL_Surface *surface); 44 void (*GetRGB) (Uint32 pixel, const SDL_PixelFormat * const fmt, Uint8 *r, Uint8 *g, Uint8 *b); 45 Uint32 (*MapRGB) (const SDL_PixelFormat * const format, const Uint8 r, const Uint8 g, const Uint8 b); 46 void (*UpdateRect) (SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h); 47} sdl; 48 49static const char * const sdl_syms[] = 50{ 51 "SDL_Init", 52 "SDL_Quit", 53 "SDL_SetVideoMode", 54 "SDL_WM_SetCaption", 55 "SDL_ShowCursor", 56 "SDL_LockSurface", 57 "SDL_UnlockSurface", 58 "SDL_GetRGB", 59 "SDL_MapRGB", 60 "SDL_UpdateRect", 61}; 62 63struct gui_state { 64 SDL_Surface *screen; 65 const SDL_PixelFormat *format; 66 int throttle, throttle_limit; 67 enum gui_color color; 68 int curr_line; 69}; 70 71/* Load the SDL lib on the fly to avoid hard linking against it. */ 72static int 73bfin_gui_sdl_setup (void) 74{ 75 int i; 76 uintptr_t **funcs; 77 78 if (sdl.handle) 79 return 0; 80 81 sdl.handle = dlopen ("libSDL-1.2.so.0", RTLD_LAZY); 82 if (sdl.handle == NULL) 83 return -1; 84 85 funcs = (void *) &sdl.Init; 86 for (i = 0; i < ARRAY_SIZE (sdl_syms); ++i) 87 { 88 funcs[i] = dlsym (sdl.handle, sdl_syms[i]); 89 if (funcs[i] == NULL) 90 { 91 dlclose (sdl.handle); 92 sdl.handle = NULL; 93 return -1; 94 } 95 } 96 97 return 0; 98} 99 100static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color); 101 102void * 103bfin_gui_setup (void *state, int enabled, int width, int height, 104 enum gui_color color) 105{ 106 if (bfin_gui_sdl_setup ()) 107 return NULL; 108 109 /* Create an SDL window if enabled and we don't have one yet. */ 110 if (enabled && !state) 111 { 112 struct gui_state *gui = xmalloc (sizeof (*gui)); 113 if (!gui) 114 return NULL; 115 116 if (sdl.Init (SDL_INIT_VIDEO)) 117 goto error; 118 119 gui->color = color; 120 gui->format = bfin_gui_color_format (gui->color); 121 gui->screen = sdl.SetVideoMode (width, height, 32, 122 SDL_ANYFORMAT|SDL_HWSURFACE); 123 if (!gui->screen) 124 { 125 sdl.Quit(); 126 goto error; 127 } 128 129 sdl.WM_SetCaption ("GDB Blackfin Simulator", NULL); 130 sdl.ShowCursor (0); 131 gui->curr_line = 0; 132 gui->throttle = 0; 133 gui->throttle_limit = 0xf; /* XXX: let people control this ? */ 134 return gui; 135 136 error: 137 free (gui); 138 return NULL; 139 } 140 141 /* Else break down a window if disabled and we had one. */ 142 else if (!enabled && state) 143 { 144 sdl.Quit(); 145 free (state); 146 return NULL; 147 } 148 149 /* Retain existing state, whatever that may be. */ 150 return state; 151} 152 153static int 154SDL_ConvertBlitLineFrom (const Uint8 *src, const SDL_PixelFormat * const format, 155 SDL_Surface *dst, int dsty) 156{ 157 Uint8 r, g, b; 158 Uint32 *pixels; 159 unsigned i, j; 160 161 if (SDL_MUSTLOCK (dst)) 162 if (sdl.LockSurface (dst)) 163 return 1; 164 165 pixels = dst->pixels; 166 pixels += (dsty * dst->pitch / 4); 167 168 for (i = 0; i < dst->w; ++i) 169 { 170 /* Exract the packed source pixel; RGB or BGR. */ 171 Uint32 pix = 0; 172 for (j = 0; j < format->BytesPerPixel; ++j) 173 if (format->Rshift) 174 pix = (pix << 8) | src[j]; 175 else 176 pix = pix | ((Uint32)src[j] << (j * 8)); 177 178 /* Unpack the source pixel into its components. */ 179 sdl.GetRGB (pix, format, &r, &g, &b); 180 /* Translate into the screen pixel format. */ 181 *pixels++ = sdl.MapRGB (dst->format, r, g, b); 182 183 src += format->BytesPerPixel; 184 } 185 186 if (SDL_MUSTLOCK (dst)) 187 sdl.UnlockSurface (dst); 188 189 sdl.UpdateRect (dst, 0, dsty, dst->w, 1); 190 191 return 0; 192} 193 194unsigned 195bfin_gui_update (void *state, const void *source, unsigned nr_bytes) 196{ 197 struct gui_state *gui = state; 198 int ret; 199 200 if (!gui) 201 return 0; 202 203 /* XXX: Make this an option ? */ 204 gui->throttle = (gui->throttle + 1) & gui->throttle_limit; 205 if (gui->throttle) 206 return 0; 207 208 ret = SDL_ConvertBlitLineFrom (source, gui->format, gui->screen, 209 gui->curr_line); 210 if (ret) 211 return 0; 212 213 gui->curr_line = (gui->curr_line + 1) % gui->screen->h; 214 215 return nr_bytes; 216} 217 218#define FMASK(cnt, shift) (((1 << (cnt)) - 1) << (shift)) 219#define _FORMAT(bpp, rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \ 220 NULL, bpp, (bpp)/8, 8-(rcnt), 8-(gcnt), 8-(bcnt), 8-(acnt), rsh, gsh, bsh, ash, \ 221 FMASK (rcnt, rsh), FMASK (gcnt, gsh), FMASK (bcnt, bsh), FMASK (acnt, ash), 222#define FORMAT(rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \ 223 _FORMAT(((((rcnt) + (gcnt) + (bcnt) + (acnt)) + 7) / 8) * 8, \ 224 rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) 225 226static const SDL_PixelFormat sdl_rgb_565 = 227{ 228 FORMAT (5, 6, 5, 0, 11, 5, 0, 0) 229}; 230static const SDL_PixelFormat sdl_bgr_565 = 231{ 232 FORMAT (5, 6, 5, 0, 0, 5, 11, 0) 233}; 234static const SDL_PixelFormat sdl_rgb_888 = 235{ 236 FORMAT (8, 8, 8, 0, 16, 8, 0, 0) 237}; 238static const SDL_PixelFormat sdl_bgr_888 = 239{ 240 FORMAT (8, 8, 8, 0, 0, 8, 16, 0) 241}; 242static const SDL_PixelFormat sdl_rgba_8888 = 243{ 244 FORMAT (8, 8, 8, 8, 24, 16, 8, 0) 245}; 246 247static const struct { 248 const char *name; 249 const SDL_PixelFormat *format; 250 enum gui_color color; 251} color_spaces[] = { 252 { "rgb565", &sdl_rgb_565, GUI_COLOR_RGB_565, }, 253 { "bgr565", &sdl_bgr_565, GUI_COLOR_BGR_565, }, 254 { "rgb888", &sdl_rgb_888, GUI_COLOR_RGB_888, }, 255 { "bgr888", &sdl_bgr_888, GUI_COLOR_BGR_888, }, 256 { "rgba8888", &sdl_rgba_8888, GUI_COLOR_RGBA_8888, }, 257}; 258 259enum gui_color bfin_gui_color (const char *color) 260{ 261 int i; 262 263 if (!color) 264 goto def; 265 266 for (i = 0; i < ARRAY_SIZE (color_spaces); ++i) 267 if (!strcmp (color, color_spaces[i].name)) 268 return color_spaces[i].color; 269 270 /* Pick a random default. */ 271 def: 272 return GUI_COLOR_RGB_888; 273} 274 275static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color) 276{ 277 int i; 278 279 for (i = 0; i < ARRAY_SIZE (color_spaces); ++i) 280 if (color == color_spaces[i].color) 281 return color_spaces[i].format; 282 283 return NULL; 284} 285 286int bfin_gui_color_depth (enum gui_color color) 287{ 288 const SDL_PixelFormat *format = bfin_gui_color_format (color); 289 return format ? format->BitsPerPixel : 0; 290} 291 292#endif 293