Blame sim/bfin/gui.c

Packit Service 706eca
/* Blackfin GUI (SDL) helper code
Packit Service 706eca
Packit Service 706eca
   Copyright (C) 2010-2018 Free Software Foundation, Inc.
Packit Service 706eca
   Contributed by Analog Devices, Inc.
Packit Service 706eca
Packit Service 706eca
   This file is part of simulators.
Packit Service 706eca
Packit Service 706eca
   This program is free software; you can redistribute it and/or modify
Packit Service 706eca
   it under the terms of the GNU General Public License as published by
Packit Service 706eca
   the Free Software Foundation; either version 3 of the License, or
Packit Service 706eca
   (at your option) any later version.
Packit Service 706eca
Packit Service 706eca
   This program is distributed in the hope that it will be useful,
Packit Service 706eca
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 706eca
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 706eca
   GNU General Public License for more details.
Packit Service 706eca
Packit Service 706eca
   You should have received a copy of the GNU General Public License
Packit Service 706eca
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 706eca
Packit Service 706eca
#include "config.h"
Packit Service 706eca
Packit Service 706eca
#ifdef HAVE_SDL
Packit Service 706eca
# include <SDL.h>
Packit Service 706eca
#endif
Packit Service 706eca
#ifdef HAVE_DLFCN_H
Packit Service 706eca
# include <dlfcn.h>
Packit Service 706eca
#endif
Packit Service 706eca
Packit Service 706eca
#include "libiberty.h"
Packit Service 706eca
#include "gui.h"
Packit Service 706eca
Packit Service 706eca
#ifdef HAVE_SDL
Packit Service 706eca
Packit Service 706eca
static struct {
Packit Service 706eca
  void *handle;
Packit Service 706eca
  int (*Init) (Uint32 flags);
Packit Service 706eca
  void (*Quit) (void);
Packit Service 706eca
  SDL_Surface *(*SetVideoMode) (int width, int height, int bpp, Uint32 flags);
Packit Service 706eca
  void (*WM_SetCaption) (const char *title, const char *icon);
Packit Service 706eca
  int (*ShowCursor) (int toggle);
Packit Service 706eca
  int (*LockSurface) (SDL_Surface *surface);
Packit Service 706eca
  void (*UnlockSurface) (SDL_Surface *surface);
Packit Service 706eca
  void (*GetRGB) (Uint32 pixel, const SDL_PixelFormat * const fmt, Uint8 *r, Uint8 *g, Uint8 *b);
Packit Service 706eca
  Uint32 (*MapRGB) (const SDL_PixelFormat * const format, const Uint8 r, const Uint8 g, const Uint8 b);
Packit Service 706eca
  void (*UpdateRect) (SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h);
Packit Service 706eca
} sdl;
Packit Service 706eca
Packit Service 706eca
static const char * const sdl_syms[] =
Packit Service 706eca
{
Packit Service 706eca
  "SDL_Init",
Packit Service 706eca
  "SDL_Quit",
Packit Service 706eca
  "SDL_SetVideoMode",
Packit Service 706eca
  "SDL_WM_SetCaption",
Packit Service 706eca
  "SDL_ShowCursor",
Packit Service 706eca
  "SDL_LockSurface",
Packit Service 706eca
  "SDL_UnlockSurface",
Packit Service 706eca
  "SDL_GetRGB",
Packit Service 706eca
  "SDL_MapRGB",
Packit Service 706eca
  "SDL_UpdateRect",
Packit Service 706eca
};
Packit Service 706eca
Packit Service 706eca
struct gui_state {
Packit Service 706eca
  SDL_Surface *screen;
Packit Service 706eca
  const SDL_PixelFormat *format;
Packit Service 706eca
  int throttle, throttle_limit;
Packit Service 706eca
  enum gui_color color;
Packit Service 706eca
  int curr_line;
Packit Service 706eca
};
Packit Service 706eca
Packit Service 706eca
/* Load the SDL lib on the fly to avoid hard linking against it.  */
Packit Service 706eca
static int
Packit Service 706eca
bfin_gui_sdl_setup (void)
Packit Service 706eca
{
Packit Service 706eca
  int i;
Packit Service 706eca
  uintptr_t **funcs;
Packit Service 706eca
Packit Service 706eca
  if (sdl.handle)
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  sdl.handle = dlopen ("libSDL-1.2.so.0", RTLD_LAZY);
Packit Service 706eca
  if (sdl.handle == NULL)
Packit Service 706eca
    return -1;
Packit Service 706eca
Packit Service 706eca
  funcs = (void *) &sdl.Init;
Packit Service 706eca
  for (i = 0; i < ARRAY_SIZE (sdl_syms); ++i)
Packit Service 706eca
    {
Packit Service 706eca
      funcs[i] = dlsym (sdl.handle, sdl_syms[i]);
Packit Service 706eca
      if (funcs[i] == NULL)
Packit Service 706eca
	{
Packit Service 706eca
	  dlclose (sdl.handle);
Packit Service 706eca
	  sdl.handle = NULL;
Packit Service 706eca
	  return -1;
Packit Service 706eca
	}
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return 0;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color);
Packit Service 706eca
Packit Service 706eca
void *
Packit Service 706eca
bfin_gui_setup (void *state, int enabled, int width, int height,
Packit Service 706eca
		enum gui_color color)
Packit Service 706eca
{
Packit Service 706eca
  if (bfin_gui_sdl_setup ())
Packit Service 706eca
    return NULL;
Packit Service 706eca
Packit Service 706eca
  /* Create an SDL window if enabled and we don't have one yet.  */
Packit Service 706eca
  if (enabled && !state)
Packit Service 706eca
    {
Packit Service 706eca
      struct gui_state *gui = xmalloc (sizeof (*gui));
Packit Service 706eca
      if (!gui)
Packit Service 706eca
	return NULL;
Packit Service 706eca
Packit Service 706eca
      if (sdl.Init (SDL_INIT_VIDEO))
Packit Service 706eca
	goto error;
Packit Service 706eca
Packit Service 706eca
      gui->color = color;
Packit Service 706eca
      gui->format = bfin_gui_color_format (gui->color);
Packit Service 706eca
      gui->screen = sdl.SetVideoMode (width, height, 32,
Packit Service 706eca
				      SDL_ANYFORMAT|SDL_HWSURFACE);
Packit Service 706eca
      if (!gui->screen)
Packit Service 706eca
	{
Packit Service 706eca
	  sdl.Quit();
Packit Service 706eca
	  goto error;
Packit Service 706eca
	}
Packit Service 706eca
Packit Service 706eca
      sdl.WM_SetCaption ("GDB Blackfin Simulator", NULL);
Packit Service 706eca
      sdl.ShowCursor (0);
Packit Service 706eca
      gui->curr_line = 0;
Packit Service 706eca
      gui->throttle = 0;
Packit Service 706eca
      gui->throttle_limit = 0xf; /* XXX: let people control this ?  */
Packit Service 706eca
      return gui;
Packit Service 706eca
Packit Service 706eca
 error:
Packit Service 706eca
      free (gui);
Packit Service 706eca
      return NULL;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  /* Else break down a window if disabled and we had one.  */
Packit Service 706eca
  else if (!enabled && state)
Packit Service 706eca
    {
Packit Service 706eca
      sdl.Quit();
Packit Service 706eca
      free (state);
Packit Service 706eca
      return NULL;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  /* Retain existing state, whatever that may be.  */
Packit Service 706eca
  return state;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static int
Packit Service 706eca
SDL_ConvertBlitLineFrom (const Uint8 *src, const SDL_PixelFormat * const format,
Packit Service 706eca
			 SDL_Surface *dst, int dsty)
Packit Service 706eca
{
Packit Service 706eca
  Uint8 r, g, b;
Packit Service 706eca
  Uint32 *pixels;
Packit Service 706eca
  unsigned i, j;
Packit Service 706eca
Packit Service 706eca
  if (SDL_MUSTLOCK (dst))
Packit Service 706eca
    if (sdl.LockSurface (dst))
Packit Service 706eca
      return 1;
Packit Service 706eca
Packit Service 706eca
  pixels = dst->pixels;
Packit Service 706eca
  pixels += (dsty * dst->pitch / 4);
Packit Service 706eca
Packit Service 706eca
  for (i = 0; i < dst->w; ++i)
Packit Service 706eca
    {
Packit Service 706eca
      /* Exract the packed source pixel; RGB or BGR.  */
Packit Service 706eca
      Uint32 pix = 0;
Packit Service 706eca
      for (j = 0; j < format->BytesPerPixel; ++j)
Packit Service 706eca
	if (format->Rshift)
Packit Service 706eca
	  pix = (pix << 8) | src[j];
Packit Service 706eca
	else
Packit Service 706eca
	  pix = pix | ((Uint32)src[j] << (j * 8));
Packit Service 706eca
Packit Service 706eca
      /* Unpack the source pixel into its components.  */
Packit Service 706eca
      sdl.GetRGB (pix, format, &r, &g, &b);
Packit Service 706eca
      /* Translate into the screen pixel format.  */
Packit Service 706eca
      *pixels++ = sdl.MapRGB (dst->format, r, g, b);
Packit Service 706eca
Packit Service 706eca
      src += format->BytesPerPixel;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  if (SDL_MUSTLOCK (dst))
Packit Service 706eca
    sdl.UnlockSurface (dst);
Packit Service 706eca
Packit Service 706eca
  sdl.UpdateRect (dst, 0, dsty, dst->w, 1);
Packit Service 706eca
Packit Service 706eca
  return 0;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
unsigned
Packit Service 706eca
bfin_gui_update (void *state, const void *source, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct gui_state *gui = state;
Packit Service 706eca
  int ret;
Packit Service 706eca
Packit Service 706eca
  if (!gui)
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  /* XXX: Make this an option ?  */
Packit Service 706eca
  gui->throttle = (gui->throttle + 1) & gui->throttle_limit;
Packit Service 706eca
  if (gui->throttle)
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  ret = SDL_ConvertBlitLineFrom (source, gui->format, gui->screen,
Packit Service 706eca
				 gui->curr_line);
Packit Service 706eca
  if (ret)
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  gui->curr_line = (gui->curr_line + 1) % gui->screen->h;
Packit Service 706eca
Packit Service 706eca
  return nr_bytes;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
#define FMASK(cnt, shift) (((1 << (cnt)) - 1) << (shift))
Packit Service 706eca
#define _FORMAT(bpp, rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \
Packit Service 706eca
  NULL, bpp, (bpp)/8, 8-(rcnt), 8-(gcnt), 8-(bcnt), 8-(acnt), rsh, gsh, bsh, ash, \
Packit Service 706eca
  FMASK (rcnt, rsh), FMASK (gcnt, gsh), FMASK (bcnt, bsh), FMASK (acnt, ash),
Packit Service 706eca
#define FORMAT(rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash) \
Packit Service 706eca
  _FORMAT(((((rcnt) + (gcnt) + (bcnt) + (acnt)) + 7) / 8) * 8, \
Packit Service 706eca
	  rcnt, gcnt, bcnt, acnt, rsh, gsh, bsh, ash)
Packit Service 706eca
Packit Service 706eca
static const SDL_PixelFormat sdl_rgb_565 =
Packit Service 706eca
{
Packit Service 706eca
  FORMAT (5, 6, 5, 0, 11, 5, 0, 0)
Packit Service 706eca
};
Packit Service 706eca
static const SDL_PixelFormat sdl_bgr_565 =
Packit Service 706eca
{
Packit Service 706eca
  FORMAT (5, 6, 5, 0, 0, 5, 11, 0)
Packit Service 706eca
};
Packit Service 706eca
static const SDL_PixelFormat sdl_rgb_888 =
Packit Service 706eca
{
Packit Service 706eca
  FORMAT (8, 8, 8, 0, 16, 8, 0, 0)
Packit Service 706eca
};
Packit Service 706eca
static const SDL_PixelFormat sdl_bgr_888 =
Packit Service 706eca
{
Packit Service 706eca
  FORMAT (8, 8, 8, 0, 0, 8, 16, 0)
Packit Service 706eca
};
Packit Service 706eca
static const SDL_PixelFormat sdl_rgba_8888 =
Packit Service 706eca
{
Packit Service 706eca
  FORMAT (8, 8, 8, 8, 24, 16, 8, 0)
Packit Service 706eca
};
Packit Service 706eca
Packit Service 706eca
static const struct {
Packit Service 706eca
  const char *name;
Packit Service 706eca
  const SDL_PixelFormat *format;
Packit Service 706eca
  enum gui_color color;
Packit Service 706eca
} color_spaces[] = {
Packit Service 706eca
  { "rgb565",   &sdl_rgb_565,   GUI_COLOR_RGB_565,   },
Packit Service 706eca
  { "bgr565",   &sdl_bgr_565,   GUI_COLOR_BGR_565,   },
Packit Service 706eca
  { "rgb888",   &sdl_rgb_888,   GUI_COLOR_RGB_888,   },
Packit Service 706eca
  { "bgr888",   &sdl_bgr_888,   GUI_COLOR_BGR_888,   },
Packit Service 706eca
  { "rgba8888", &sdl_rgba_8888, GUI_COLOR_RGBA_8888, },
Packit Service 706eca
};
Packit Service 706eca
Packit Service 706eca
enum gui_color bfin_gui_color (const char *color)
Packit Service 706eca
{
Packit Service 706eca
  int i;
Packit Service 706eca
Packit Service 706eca
  if (!color)
Packit Service 706eca
    goto def;
Packit Service 706eca
Packit Service 706eca
  for (i = 0; i < ARRAY_SIZE (color_spaces); ++i)
Packit Service 706eca
    if (!strcmp (color, color_spaces[i].name))
Packit Service 706eca
      return color_spaces[i].color;
Packit Service 706eca
Packit Service 706eca
  /* Pick a random default.  */
Packit Service 706eca
 def:
Packit Service 706eca
  return GUI_COLOR_RGB_888;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static const SDL_PixelFormat *bfin_gui_color_format (enum gui_color color)
Packit Service 706eca
{
Packit Service 706eca
  int i;
Packit Service 706eca
Packit Service 706eca
  for (i = 0; i < ARRAY_SIZE (color_spaces); ++i)
Packit Service 706eca
    if (color == color_spaces[i].color)
Packit Service 706eca
      return color_spaces[i].format;
Packit Service 706eca
Packit Service 706eca
  return NULL;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
int bfin_gui_color_depth (enum gui_color color)
Packit Service 706eca
{
Packit Service 706eca
  const SDL_PixelFormat *format = bfin_gui_color_format (color);
Packit Service 706eca
  return format ? format->BitsPerPixel : 0;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
#endif