Framebuffer.cpp revision 0c04bf3d366953a24840080b5f7be34d9406a7dc
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * VBox frontends: VBoxSDL (simple frontend based on SDL):
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Implementation of VBoxSDLFB (SDL framebuffer) class
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Copyright (C) 2006-2007 innotek GmbH
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * This file is part of VirtualBox Open Source Edition (OSE), as
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * available from http://www.virtualbox.org. This file is free software;
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * you can redistribute it and/or modify it under the terms of the GNU
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * General Public License as published by the Free Software Foundation,
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * distribution. VirtualBox OSE is distributed in the hope that it will
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * be useful, but WITHOUT ANY WARRANTY of any kind.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * If you received this file as part of a commercial VirtualBox
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * distribution, then only the terms of your commercial VirtualBox
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * license agreement apply instead of the previous paragraph.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley# define RT_MAX(Value1, Value2) ((Value1) >= (Value2) ? (Value1) : (Value2))
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elleyusing namespace com;
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir ElleyNS_IMPL_ISUPPORTS1_CI(VBoxSDLFBOverlay, IFramebufferOverlay)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley/* function pointers */
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleyDECLSPEC TTF_Font* (SDLCALL *pTTF_OpenFont)(const char *file, int ptsize);
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleyDECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Solid)(TTF_Font *font, const char *text, SDL_Color fg);
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleyDECLSPEC void (SDLCALL *pTTF_CloseFont)(TTF_Font *font);
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley#endif /* VBOX_SECURELABEL */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley// Constructor / destructor
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * SDL framebuffer constructor. It is called from the main
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * (i.e. SDL) thread. Therefore it is safe to use SDL calls
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param fFullscreen flag whether we start in fullscreen mode
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param fResizable flag whether the SDL window should be resizable
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param fShowSDLConfig flag whether we print out SDL settings
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param iFixedWidth fixed SDL width (-1 means not set)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param iFixedHeight fixed SDL height (-1 means not set)
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleyVBoxSDLFB::VBoxSDLFB(bool fFullscreen, bool fResizable, bool fShowSDLConfig,
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley uint32_t u32FixedWidth, uint32_t u32FixedHeight, uint32_t u32FixedBPP)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* Start with standard screen dimensions. */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley mPixelFormat = FramebufferPixelFormat_PixelFormatOpaque;
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* memorize the thread that inited us, that's the SDL thread */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley AssertMsg(rc == VINF_SUCCESS, ("Error from RTCritSectInit!\n"));
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* default to DirectX if nothing else set */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley// _putenv("SDL_VIDEODRIVER=windib");
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* On some X servers the mouse is stuck inside the bottom right corner.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * See http://wiki.clug.org.za/wiki/QEMU_mouse_not_working */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley /* output what SDL is capable of */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Hardware surface support: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Window manager available: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Screen to screen blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Screen to screen colorkey blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Screen to screen alpha blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Memory to screen blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Memory to screen colorkey blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Memory to screen alpha blits accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Color fills accelerated: %s\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Video memory in kilobytes: %d\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley " Optimal bpp mode: %d\n"
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley "SDL video driver: %s\n",
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley mWMIcon = SDL_AllocSurface(SDL_SWSURFACE, 64, 64, 24, 0xff, 0xff00, 0xff0000, 0);
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley /** @todo make it as simple as possible. No PNM interpreter here... */
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley memcpy(mWMIcon->pixels, g_abIco64x01+32, g_cbIco64x01-32);
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Returns the current framebuffer width in pixels.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param width Address of result buffer.
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(Width)(ULONG *width)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Returns the current framebuffer height in pixels.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param height Address of result buffer.
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(Height)(ULONG *height)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Lock the framebuffer (make its address immutable).
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Unlock the framebuffer.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Return the framebuffer start address.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param address Pointer to result variable.
64074e584a56611d7563667e0fcdadd215b0c922Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(Address)(BYTE **address)
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley /* That's actually rather bad. */
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley LogFlow(("VBoxSDL::GetAddress returning %p\n", *address));
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * Return the current framebuffer color depth.
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @returns COM status code
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley * @param colorDepth Address of result variable
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(ColorDepth)(ULONG *colorDepth)
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley /* get the information directly from the surface in use */
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley *colorDepth = (ULONG)(mSurfVRAM ? mSurfVRAM->format->BitsPerPixel : 0);
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * Return the current framebuffer line size in bytes.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * @returns COM status code.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * @param lineSize Address of result variable.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(LineSize)(ULONG *lineSize)
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley /* get the information directly from the surface */
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley *lineSize = (ULONG)(mSurfVRAM ? mSurfVRAM->pitch : 0);
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(PixelFormat) (FramebufferPixelFormat_T *pixelFormat)
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * Returns by how many pixels the guest should shrink its
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * video mode height values.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * @returns COM status code.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir Elley * @param heightReduction Address of result variable.
9bda5ab39fc3429191e2272a8be62e230677ecb1Yassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(HeightReduction)(ULONG *heightReduction)
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * Returns a pointer to an alpha-blended overlay used for displaying status
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * icons above the framebuffer.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @returns COM status code.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param aOverlay The overlay framebuffer.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir ElleySTDMETHODIMP VBoxSDLFB::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley /* Not yet implemented */
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * Notify framebuffer of an update.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @returns COM status code
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param x Update region upper left corner x value.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param y Update region upper left corner y value.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param w Update region width in pixels.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param h Update region height in pixels.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param finished Address of output flag whether the update
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * could be fully processed in this call (which
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * has to return immediately) or VBox should wait
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * for a call to the update complete API before
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * continuing with display updates.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir ElleySTDMETHODIMP VBoxSDLFB::NotifyUpdate(ULONG x, ULONG y,
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * The input values are in guest screen coordinates.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley LogFlow(("VBoxSDLFB::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley x, y, w, h));
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * SDL does not allow us to make this call from any other thread than
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * the main SDL thread (which initialized the video mode). So we have
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * to send an event to the main SDL thread and process it there. For
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * sake of simplicity, we encode all information in the event parameters.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley // 16 bit is enough for coordinates
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley#else /* !RT_OS_LINUX */
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley#endif /* !RT_OS_LINUX */
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * The Display thread can continue as we will lock the framebuffer
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * from the SDL thread when we get to actually doing the update.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * Request a display resize from the framebuffer.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @returns COM status code.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param pixelFormat The requested pixel format.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param vram Pointer to the guest VRAM buffer (can be NULL).
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param lineSize Size of a scanline in bytes.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param w New display width in pixels.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param h New display height in pixels.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * @param finished Address of output flag whether the update
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * could be fully processed in this call (which
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * has to return immediately) or VBox should wait
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * for all call to the resize complete API before
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * continuing with display updates.
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir ElleySTDMETHODIMP VBoxSDLFB::RequestResize(ULONG aScreenId, FramebufferPixelFormat_T pixelFormat, BYTE *vram,
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley ULONG lineSize, ULONG w, ULONG h, BOOL *finished)
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley LogFlow(("VBoxSDLFB::RequestResize: w = %d, h = %d, pixelFormat: %d, vram = %p, lineSize = %d\n",
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * SDL does not allow us to make this call from any other thread than
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * the main thread (the one which initialized the video mode). So we
eb0cde4e6dfdbda08588860534f7ece5776ec3afYassir Elley * have to send an event to the main SDL thread and tell VBox to wait.
return E_FAIL;
mGuestXRes = w;
mGuestYRes = h;
*finished = false;
return S_OK;
STDMETHODIMP VBoxSDLFB::OperationSupported(FramebufferAccelerationOperation_T operation, BOOL *supported)
if (!supported)
return E_POINTER;
*supported = false;
switch (operation)
*supported = true;
*supported = true;
*supported = false;
return S_OK;
if (!supported)
return E_POINTER;
#ifdef DEBUG
*supported = false;
*supported = true;
return S_OK;
if (!handled)
return E_POINTER;
*handled = true;
*handled = false;
return S_OK;
if (!handled)
return E_POINTER;
*handled = true;
*handled = false;
return S_OK;
if (!rects)
return E_POINTER;
return S_OK;
if (!rects)
return E_POINTER;
return S_OK;
switch (cBitsPerPixel)
if (mSurfVRAM)
resizeSDL();
if (mfResizable)
if (mfFullscreen)
/* Get available fullscreen/hardware modes */
mCenterXOffset = 0;
mCenterYOffset = 0;
#ifdef VBOX_SECURELABEL
mTopOffset = 0;
#ifdef VBOX_SECURELABEL
if (!mScreen)
if (mScreen)
#ifdef VBOX_WIN32_UI
if (mfShowSDLConfig)
repaint();
#ifdef RT_OS_LINUX
int yCutoffGuest = 0;
#ifdef VBOX_SECURELABEL
bool fPaintLabel = false;
if (y < (int)mLabelHeight)
if (!fGuestRelative)
#ifdef VBOX_SECURELABEL
if (y < (int)mLabelHeight)
fPaintLabel = true;
w = mGuestXRes;
h = mGuestYRes;
srcRect.x = x;
srcRect.w = w;
#ifdef VBOX_SECURELABEL
dstRect.w = w;
//RTPrintf("y = %d h = %d mapped to srcY %d srcH %d mapped to dstY = %d dstH %d (guestrel: %d, mLabelHeight: %d, mTopOffset: %d)\n",
#ifdef VBOX_SECURELABEL
if (fPaintLabel)
paintSecureLabel(0, 0, 0, 0, false);
return mfFullscreen;
resizeSDL();
return mCenterXOffset;
#ifdef VBOX_SECURELABEL
pTTF_Init();
if (!mLabelFont)
return VERR_OPEN_FAILED;
repaint();
return VINF_SUCCESS;
paintSecureLabel(0, 0, 0, 0, true);
paintSecureLabel(0, 0, 0, 0, true);
#ifdef RT_OS_LINUX
if (!pTTF_RenderUTF8_Solid)
if (mSurfVRAM)
#ifdef VBOX_SECURELABEL
if (mLabelFont)
if (pTTF_Quit)
pTTF_Quit();
if (mWMIcon)
return S_OK;
return E_INVALIDARG;
*x = mOverlayX;
return S_OK;
return E_INVALIDARG;
*y = mOverlayY;
return S_OK;
if (!width)
return E_INVALIDARG;
return S_OK;
if (!lineSize)
return E_INVALIDARG;
return S_OK;
if (!height)
return E_INVALIDARG;
return S_OK;
if (!visible)
return E_INVALIDARG;
return S_OK;
return S_OK;
return E_NOTIMPL;
return E_NOTIMPL;
if (!address)
return E_INVALIDARG;
return S_OK;
if (!colorDepth)
return E_INVALIDARG;
return S_OK;
if (!pixelFormat)
return E_INVALIDARG;
return S_OK;
if (!heightReduction)
return E_INVALIDARG;
*heightReduction = 0;
return S_OK;
if (!aOverlay)
return E_INVALIDARG;
*aOverlay = 0;
return S_OK;
return E_NOTIMPL;
return E_NOTIMPL;
mOverlayX = x;
mOverlayY = y;
return S_OK;
mOverlayWidth = w;
mOverlayHeight = h;
return S_OK;
if (!supported)
return E_POINTER;
*supported = false;
return S_OK;
if (!supported)
return E_POINTER;
*supported = true;
*supported = false;
return S_OK;
if (!handled)
return E_POINTER;
*handled = false;
return S_OK;
if (!handled)
return E_POINTER;
*handled = false;
return S_OK;