genode/repos/libports/src/lib/sdl/video/SDL_genode_fb_video.cc

326 lines
9.0 KiB
C++

/*
* \brief Genode-specific video backend
* \author Stefan Kalkowski
* \date 2008-12-12
*/
/*
* Copyright (c) <2008> Stefan Kalkowski
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <base/printf.h>
#include <base/env.h>
#include <framebuffer_session/connection.h>
extern "C" {
#include <SDL/SDL.h>
#include <SDL/SDL_video.h>
#include <SDL/SDL_mouse.h>
#include "SDL_sysvideo.h"
#include "SDL_pixels_c.h"
#include "SDL_events_c.h"
#include "SDL_genode_fb_events.h"
#include "SDL_genode_fb_video.h"
static Framebuffer::Connection *framebuffer = 0;
static Framebuffer::Mode scr_mode;
static SDL_Rect *modes[2];
static SDL_Rect df_mode;
/***************************************
* Genode_Fb driver bootstrap functions
**************************************/
/**
*
*/
static int Genode_Fb_Available(void) {
if(framebuffer == 0)
framebuffer = new(Genode::env()->heap()) Framebuffer::Connection();
if (!framebuffer->cap().valid())
{
PERR("Couldn't get framebuffer session!");
return 0;
}
return 1;
}
/**
*
*/
static void Genode_Fb_DeleteDevice(SDL_VideoDevice *device)
{
PDBG("Free framebuffer session object");
if(framebuffer != 0)
Genode::destroy(Genode::env()->heap(), framebuffer);
framebuffer = 0;
}
/**
*
*/
static SDL_VideoDevice *Genode_Fb_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
if ( device ) {
SDL_memset(device, 0, (sizeof *device));
device->hidden = (struct SDL_PrivateVideoData *)
SDL_malloc((sizeof *device->hidden));
}
if ( (device == 0) || (device->hidden == 0) ) {
SDL_OutOfMemory();
if ( device ) {
SDL_free(device);
}
return(0);
}
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
device->VideoInit = Genode_Fb_VideoInit;
device->ListModes = Genode_Fb_ListModes;
device->SetVideoMode = Genode_Fb_SetVideoMode;
device->SetColors = Genode_Fb_SetColors;
device->UpdateRects = Genode_Fb_UpdateRects;
device->VideoQuit = Genode_Fb_VideoQuit;
device->AllocHWSurface = Genode_Fb_AllocHWSurface;
device->LockHWSurface = Genode_Fb_LockHWSurface;
device->UnlockHWSurface = Genode_Fb_UnlockHWSurface;
device->FreeHWSurface = Genode_Fb_FreeHWSurface;
device->InitOSKeymap = Genode_Fb_InitOSKeymap;
device->PumpEvents = Genode_Fb_PumpEvents;
device->free = Genode_Fb_DeleteDevice;
device->CreateYUVOverlay = 0;
device->CheckHWBlit = 0;
device->FillHWRect = 0;
device->SetHWColorKey = 0;
device->SetHWAlpha = 0;
device->FlipHWSurface = 0;
device->SetCaption = 0;
device->SetIcon = 0;
device->IconifyWindow = 0;
device->GrabInput = 0;
device->GetWMInfo = 0;
return device;
}
VideoBootStrap Genode_fb_bootstrap = {
"Genode_Fb", "SDL genode_fb video driver",
Genode_Fb_Available, Genode_Fb_CreateDevice
};
/*****************
* Functionality
****************/
/**
* Initialize the native video subsystem, filling 'vformat' with the
* "best" display pixel format, returning 0 or -1 if there's an error.
*/
int Genode_Fb_VideoInit(SDL_VideoDevice *t, SDL_PixelFormat *vformat)
{
if(framebuffer == 0)
{
PERR("Framebuffer isn't initialized!");
return -1;
}
/* Get the framebuffer size and mode infos */
scr_mode = framebuffer->mode();
t->info.current_w = scr_mode.width();
t->info.current_h = scr_mode.height();
PDBG("Framebuffer has width=%d and height=%d",
t->info.current_w, t->info.current_h);
/* set mode specific values */
switch(scr_mode.format())
{
case Framebuffer::Mode::RGB565:
PDBG("We use pixelformat rgb565.");
vformat->BitsPerPixel = 16;
vformat->BytesPerPixel = scr_mode.bytes_per_pixel();
vformat->Rmask = 0x0000f800;
vformat->Gmask = 0x000007e0;
vformat->Bmask = 0x0000001f;
break;
default:
SDL_SetError("Couldn't get console mode info");
Genode_Fb_VideoQuit(t);
return -1;
}
modes[0] = &df_mode;
df_mode.w = scr_mode.width();
df_mode.h = scr_mode.height();
modes[1] = 0;
/* Map the buffer */
Genode::Dataspace_capability fb_ds_cap = framebuffer->dataspace();
if (!fb_ds_cap.valid()) {
PERR("Could not request dataspace for frame buffer");
return -1;
}
t->hidden->buffer = Genode::env()->rm_session()->attach(fb_ds_cap);
return 0;
}
/**
* List the available video modes for the given pixel format,
* sorted from largest to smallest.
*/
SDL_Rect **Genode_Fb_ListModes(SDL_VideoDevice *t,
SDL_PixelFormat *format,
Uint32 flags)
{
if(format->BitsPerPixel != 16)
return (SDL_Rect **) 0;
return modes;
}
/**
* Set the requested video mode, returning a surface which will be
* set to the SDL_VideoSurface. The width and height will already
* be verified by ListModes(), and the video subsystem is free to
* set the mode to a supported bit depth different from the one
* specified -- the desired bpp will be emulated with a shadow
* surface if necessary. If a new mode is returned, this function
* should take care of cleaning up the current mode.
*/
SDL_Surface *Genode_Fb_SetVideoMode(SDL_VideoDevice *t,
SDL_Surface *current,
int width, int height,
int bpp, Uint32 flags)
{
PDBG("Set video mode to: width=%d height=%d bpp=%d",
width, height, bpp);
if ( ! t->hidden->buffer ) {
PERR("No buffer for requested mode");
return(0);
}
SDL_memset(t->hidden->buffer, 0, width * height * (bpp / 8));
/* Allocate the new pixel format for the screen */
if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
PERR("Couldn't allocate new pixel format for requested mode");
return(0);
}
/* Set up the new mode framebuffer */
current->flags = flags & SDL_FULLSCREEN;
t->hidden->w = current->w = width;
t->hidden->h = current->h = height;
current->pitch = current->w * (bpp / 8);
current->pixels = t->hidden->buffer;
return(current);
}
/**
* We don't actually allow hardware surfaces other than the main one
*/
static int Genode_Fb_AllocHWSurface(SDL_VideoDevice *t,
SDL_Surface *surface)
{
PDBG("Not supported yet ...");
return -1;
}
static void Genode_Fb_FreeHWSurface(SDL_VideoDevice *t,
SDL_Surface *surface)
{
PDBG("Not supported yet ...");
}
/**
* We need to wait for vertical retrace on page flipped displays
*/
static int Genode_Fb_LockHWSurface(SDL_VideoDevice *t,
SDL_Surface *surface)
{
PDBG("Not supported yet ...");
return 0;
}
static void Genode_Fb_UnlockHWSurface(SDL_VideoDevice *t,
SDL_Surface *surface)
{
PDBG("Not supported yet ...");
}
static void Genode_Fb_UpdateRects(SDL_VideoDevice *t, int numrects,
SDL_Rect *rects)
{
int i;
for(i=0;i<numrects;i++)
framebuffer->refresh(rects[i].x, rects[i].y, rects[i].w, rects[i].h);
}
/**
* Sets the color entries { firstcolor .. (firstcolor+ncolors-1) }
* of the physical palette to those in 'colors'. If the device is
* using a software palette (SDL_HWPALETTE not set), then the
* changes are reflected in the logical palette of the screen
* as well.
* The return value is 1 if all entries could be set properly
* or 0 otherwise.
*/
int Genode_Fb_SetColors(SDL_VideoDevice *t, int firstcolor,
int ncolors, SDL_Color *colors)
{
PWRN("Not implemented yet");
return 1;
}
/**
*Note: If we are terminated, this could be called in the middle of
* another SDL video routine -- notably UpdateRects.
*/
void Genode_Fb_VideoQuit(SDL_VideoDevice *t)
{
PDBG("Quit video device ...");
if (t->screen->pixels != 0)
{
SDL_free(t->screen->pixels);
t->screen->pixels = 0;
}
}
} //extern "C"