diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 14:19:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 14:19:18 +0000 |
commit | 4035b1bfb1e5843a539a8b624d21952b756974d1 (patch) | |
tree | f1e9cd5bf548cbc57ff2fddfb2b4aa9ae95587e2 /src/VBox/Frontends/VBoxFB | |
parent | Initial commit. (diff) | |
download | virtualbox-4035b1bfb1e5843a539a8b624d21952b756974d1.tar.xz virtualbox-4035b1bfb1e5843a539a8b624d21952b756974d1.zip |
Adding upstream version 6.1.22-dfsg.upstream/6.1.22-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Frontends/VBoxFB')
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Framebuffer.cpp | 373 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Framebuffer.h | 74 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Helper.cpp | 98 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Helper.h | 39 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Makefile.kmk | 42 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/VBoxFB.cpp | 577 | ||||
-rw-r--r-- | src/VBox/Frontends/VBoxFB/VBoxFB.h | 81 |
7 files changed, 1284 insertions, 0 deletions
diff --git a/src/VBox/Frontends/VBoxFB/Framebuffer.cpp b/src/VBox/Frontends/VBoxFB/Framebuffer.cpp new file mode 100644 index 00000000..f743cac5 --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Framebuffer.cpp @@ -0,0 +1,373 @@ +/* $Id: Framebuffer.cpp $ */ +/** @file + * VBoxFB - implementation of VBoxDirectFB class. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "VBoxFB.h" +#include "Framebuffer.h" + +NS_IMPL_ISUPPORTS1_CI(VBoxDirectFB, IFramebuffer) +NS_DECL_CLASSINFO(VBoxDirectFB) + +VBoxDirectFB::VBoxDirectFB(IDirectFB *aDFB, IDirectFBSurface *aSurface) +{ + dfb = aDFB; + surface = aSurface; + fbInternalSurface = NULL; + fbBufferAddress = NULL; + // initialize screen dimensions + DFBCHECK(surface->GetSize(surface, (int*)&screenWidth, (int*)&screenHeight)); + fbWidth = 640; + fbHeight = 480; + if ((screenWidth != fbWidth) || (screenHeight != fbHeight)) + { + createSurface(fbWidth, fbHeight); + } + fbSurfaceLocked = 0; + PRUint32 bitsPerPixel; + GetBitsPerPixel(&bitsPerPixel); + fbPitch = fbWidth * (bitsPerPixel / 8); +} + +VBoxDirectFB::~VBoxDirectFB() +{ + // free our internal surface + if (fbInternalSurface) + { + DFBCHECK(fbInternalSurface->Release(fbInternalSurface)); + fbInternalSurface = NULL; + } +} + +NS_IMETHODIMP VBoxDirectFB::GetWidth(uint32 *width) +{ + if (!width) + return NS_ERROR_INVALID_POINTER; + *width = fbWidth; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetHeight(PRUint32 *height) +{ + if (!height) + return NS_ERROR_INVALID_POINTER; + *height = fbHeight; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::Lock() +{ + // do we have an internal framebuffer? + if (fbInternalSurface) + { + if (fbSurfaceLocked) + { + printf("internal surface already locked!\n"); + } else + { + DFBCHECK(fbInternalSurface->Lock(fbInternalSurface, + (DFBSurfaceLockFlags)(DSLF_WRITE | DSLF_READ), + &fbBufferAddress, (int*)&fbPitch)); + fbSurfaceLocked = 1; + } + } else + { + if (fbSurfaceLocked) + { + printf("surface already locked!\n"); + } else + { + DFBCHECK(surface->Lock(surface, (DFBSurfaceLockFlags)(DSLF_WRITE | DSLF_READ), + &fbBufferAddress, (int*)&fbPitch)); + fbSurfaceLocked = 1; + } + } + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::Unlock() +{ + // do we have an internal framebuffer? + if (fbInternalSurface) + { + if (!fbSurfaceLocked) + { + printf("internal surface not locked!\n"); + } else + { + DFBCHECK(fbInternalSurface->Unlock(fbInternalSurface)); + fbSurfaceLocked = 0; + } + } else + { + if (!fbSurfaceLocked) + { + printf("surface not locked!\n"); + } else + { + DFBCHECK(surface->Unlock(surface)); + fbSurfaceLocked = 0; + } + } + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetAddress(PRUint8 **address) +{ + if (!address) + return NS_ERROR_INVALID_POINTER; + *address = (PRUint8 *)fbBufferAddress; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetBitsPerPixel(PRUint32 *bitsPerPixel) +{ + if (!bitsPerPixel) + return NS_ERROR_INVALID_POINTER; + DFBSurfacePixelFormat pixelFormat; + DFBCHECK(surface->GetPixelFormat(surface, &pixelFormat)); + switch (pixelFormat) + { + case DSPF_RGB16: + *bitsPerPixel = 16; + break; + case DSPF_RGB24: + *bitsPerPixel = 24; + break; + case DSPF_RGB32: + *bitsPerPixel = 32; + break; + default: + // not good! @@@AH do something! + *bitsPerPixel = 16; + } + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetBytesPerLine(PRUint32 *bytesPerLine) +{ + if (!bytesPerLine) + return NS_ERROR_INVALID_POINTER; + *bytesPerLine = fbPitch; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetPixelFormat (PRUint32 *pixelFormat) +{ + if (!pixelFormat) + return NS_ERROR_INVALID_POINTER; + *pixelFormat = FramebufferPixelFormat_FOURCC_RGB; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetUsesGuestVRAM (PRBool *usesGuestVRAM) +{ + if (!usesGuestVRAM) + return NS_ERROR_INVALID_POINTER; + *usesGuestVRAM = false; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetHeightReduction(PRUint32 *heightReduction) +{ + if (!heightReduction) + return NS_ERROR_INVALID_POINTER; + *heightReduction = 0; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetOverlay(IFramebufferOverlay **overlay) +{ + if (!overlay) + return NS_ERROR_INVALID_POINTER; + /* Not yet implemented */ + *overlay = 0; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetWinId(PRint64 *winId) +{ + if (!winId) + return NS_ERROR_INVALID_POINTER; + *winId = 0; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::NotifyUpdate(PRUint32 x, PRUint32 y, + PRUint32 w, PRUint32 h) +{ + // we only need to take action if we have a memory framebuffer + if (fbInternalSurface) + { + //printf("blitting %u %u %u %u...\n", x, y, w, h); + DFBRectangle blitRectangle; + blitRectangle.x = x; + blitRectangle.y = y; + blitRectangle.w = w; + blitRectangle.h = h; + if (scaleGuest) + { + DFBRectangle hostRectangle; + float factorX = (float)screenWidth / (float)fbWidth; + float factorY = (float)screenHeight / (float)fbHeight; + hostRectangle.x = (int)((float)blitRectangle.x * factorX); + hostRectangle.y = (int)((float)blitRectangle.y * factorY); + hostRectangle.w = (int)((float)blitRectangle.w * factorX); + hostRectangle.h = (int)((float)blitRectangle.h * factorY); + DFBCHECK(surface->StretchBlit(surface, fbInternalSurface, + &blitRectangle, &hostRectangle)); + } + else + { + DFBCHECK(surface->Blit(surface, fbInternalSurface, &blitRectangle, + x + ((screenWidth - fbWidth) / 2), + y + (screenHeight - fbHeight) / 2)); + } + } + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::RequestResize(PRUint32 aScreenId, PRUint32 pixelFormat, PRUint8 *vram, + PRUint32 bitsPerPixel, PRUint32 bytesPerLine, + PRUint32 w, PRUint32 h, + PRBool *finished) +{ + uint32_t needsLocking = fbSurfaceLocked; + + printf("RequestResize: aScreenId = %d, pixelFormat = %d, vram = %p, bitsPerPixel = %d, bytesPerLine = %d, w = %d, h = %d, fbSurfaceLocked = %d\n", aScreenId, pixelFormat, vram, bitsPerPixel, bytesPerLine, w, h, fbSurfaceLocked); + + // we can't work with a locked surface + if (needsLocking) + { + Unlock(); + } + + // in any case we gotta free a possible internal framebuffer + if (fbInternalSurface) + { + printf("freeing internal surface\n"); + fbInternalSurface->Release(fbInternalSurface); + fbInternalSurface = NULL; + } + + // check if we have a fixed host video mode + if (useFixedVideoMode) + { + // does the current video mode differ from what the guest wants? + if ((screenWidth == w) && (screenHeight == h)) + { + printf("requested guest mode matches current host mode!\n"); + } else + { + createSurface(w, h); + } + } else + { + // we adopt to the guest resolution or the next higher that is available + int32_t bestMode = getBestVideoMode(w, h, bitsPerPixel); + if (bestMode == -1) + { + // oh oh oh oh + printf("RequestResize: no suitable mode found!\n"); + return NS_OK; + } + + // does the mode differ from what we wanted? + if ((videoModes[bestMode].width != w) || (videoModes[bestMode].height != h) || + (videoModes[bestMode].bpp != bitsPerPixel)) + { + printf("The mode does not fit exactly!\n"); + createSurface(w, h); + } else + { + printf("The mode fits exactly!\n"); + } + // switch to this mode + DFBCHECK(dfb->SetVideoMode(dfb, videoModes[bestMode].width, videoModes[bestMode].height, + videoModes[bestMode].bpp)); + } + + // update dimensions to the new size + fbWidth = w; + fbHeight = h; + + // clear the screen + DFBCHECK(surface->Clear(surface, 0, 0, 0, 0)); + + // if it was locked before the resize, obtain the lock again + if (needsLocking) + { + Lock(); + } + + if (finished) + *finished = true; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::VideoModeSupported(PRUint32 w, PRUint32 h, PRUint32 bpp, PRBool *supported) +{ + if (!supported) + return NS_ERROR_INVALID_POINTER; + *supported = true; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetVisibleRegion(PRUint8 *rectangles, PRUint32 count, PRUint32 *countCopied) +{ + PRTRECT rects = (PRTRECT)rectangles; + + if (!rects || !countCopied) + return NS_ERROR_INVALID_POINTER; + /** @todo */ + *countCopied = 0; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::SetVisibleRegion(PRUint8 *rectangles, PRUint32 count) +{ + PRTRECT rects = (PRTRECT)rectangles; + + if (!rects) + return NS_ERROR_INVALID_POINTER; + /** @todo */ + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::ProcessVHWACommand(PRUint8 *command, LONG enmCmd, BOOL fGuestCmd) +{ + RT_NOREF(command, enmCmd, fGuestCmd); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP VBoxDirectFB::Notify3DEvent(PRUint32 type, PRUint8 *reserved) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +int VBoxDirectFB::createSurface(uint32_t w, uint32_t h) +{ + printf("creating a new internal surface, w = %u, h = %u...\n", w, h); + // create a surface + DFBSurfaceDescription dsc; + DFBSurfacePixelFormat pixelFormat; + dsc.flags = (DFBSurfaceDescriptionFlags)(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT); + dsc.width = w; + dsc.height = h; + DFBCHECK(surface->GetPixelFormat(surface, &pixelFormat)); + dsc.pixelformat = pixelFormat; + DFBCHECK(dfb->CreateSurface(dfb, &dsc, &fbInternalSurface)); + return 0; +} diff --git a/src/VBox/Frontends/VBoxFB/Framebuffer.h b/src/VBox/Frontends/VBoxFB/Framebuffer.h new file mode 100644 index 00000000..55637be8 --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Framebuffer.h @@ -0,0 +1,74 @@ +/** @file + * VBoxFB - Declaration of VBoxDirectFB class. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h +#define VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxFB.h" + +class VBoxDirectFB : public IFramebuffer +{ +public: + VBoxDirectFB(IDirectFB *aDFB, IDirectFBSurface *aSurface); + virtual ~VBoxDirectFB(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetWidth(PRUint32 *width); + NS_IMETHOD GetHeight(PRUint32 *height); + NS_IMETHOD Lock(); + NS_IMETHOD Unlock(); + NS_IMETHOD GetAddress(PRUint8 **address); + NS_IMETHOD GetBitsPerPixel(PRUint32 *bitsPerPixel); + NS_IMETHOD GetBytesPerLine(PRUint32 *bytesPerLine); + NS_IMETHOD GetPixelFormat(PRUint32 *pixelFormat); + NS_IMETHOD GetUsesGuestVRAM(PRBool *usesGuestVRAM); + NS_IMETHOD GetHeightReduction(PRUint32 *heightReduction); + NS_IMETHOD GetOverlay(IFramebufferOverlay **aOverlay); + NS_IMETHOD GetWinId(PRUint64 *winId); + NS_IMETHOD NotifyUpdate(PRUint32 x, PRUint32 y, PRUint32 w, PRUint32 h); + NS_IMETHOD RequestResize(PRUint32 aScreenId, PRUint32 pixelFormat, PRUint8 *vram, + PRUint32 bitsPerPixel, PRUint32 bytesPerLine, + PRUint32 w, PRUint32 h, + PRBool *finished); + NS_IMETHOD VideoModeSupported(PRUint32 width, PRUint32 height, PRUint32 bpp, PRBool *supported); + NS_IMETHOD GetVisibleRegion(PRUint8 *aRectangles, PRUint32 aCount, PRUint32 *aCountCopied); + NS_IMETHOD SetVisibleRegion(PRUint8 *aRectangles, PRUint32 aCount); + + NS_IMETHOD ProcessVHWACommand(PRUint8 *pCommand, LONG enmCmd, BOOL fGuestCmd); + + NS_IMETHOD Notify3DEvent(PRUint32 type, PRUint8 *reserved); +private: + int createSurface(uint32_t w, uint32_t h); + + IDirectFB *dfb; + IDirectFBSurface *surface; + uint32_t screenWidth; + uint32_t screenHeight; + IDirectFBSurface *fbInternalSurface; + void *fbBufferAddress; + uint32_t fbWidth; + uint32_t fbHeight; + uint32_t fbPitch; + int fbSurfaceLocked; +}; + + +#endif /* !VBOX_INCLUDED_SRC_VBoxFB_Framebuffer_h */ + diff --git a/src/VBox/Frontends/VBoxFB/Helper.cpp b/src/VBox/Frontends/VBoxFB/Helper.cpp new file mode 100644 index 00000000..35f0e55a --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Helper.cpp @@ -0,0 +1,98 @@ +/** @file + * + * VBox frontends: Framebuffer (FB, DirectFB): + * Helper routines + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "VBoxFB.h" +#include "Helper.h" + +/** + * Globals + */ +videoMode videoModes[MAX_VIDEOMODES] = {{0}}; +uint32_t numVideoModes = 0; + +/** + * callback handler for populating the supported video modes + * + * @returns callback success indicator + * @param width width in pixels of the current video mode + * @param height height in pixels of the current video mode + * @param bpp bits per pixel of the current video mode + * @param callbackdata user data pointer + */ +DFBEnumerationResult enumVideoModesHandler(int width, int height, int bpp, void *callbackdata) +{ + if (numVideoModes >= MAX_VIDEOMODES) + { + return DFENUM_CANCEL; + } + // don't take palette based modes + if (bpp >= 16) + { + // don't take modes we already have (I have seen many cases where + // DirectFB returns the same modes several times) + int32_t existingMode = getBestVideoMode(width, height, bpp); + if ((existingMode == -1) || + ((videoModes[existingMode].width != (uint32_t)width) || + (videoModes[existingMode].height != (uint32_t)height) || + (videoModes[existingMode].bpp != (uint32_t)bpp))) + { + videoModes[numVideoModes].width = (uint32_t)width; + videoModes[numVideoModes].height = (uint32_t)height; + videoModes[numVideoModes].bpp = (uint32_t)bpp; + numVideoModes++; + } + } + return DFENUM_OK; +} + +/** + * Returns the best fitting video mode for the given characteristics. + * + * @returns index of the best video mode, -1 if no suitable mode found + * @param width requested width + * @param height requested height + * @param bpp requested bit depth + */ +int32_t getBestVideoMode(uint32_t width, uint32_t height, uint32_t bpp) +{ + int32_t bestMode = -1; + + for (uint32_t i = 0; i < numVideoModes; i++) + { + // is this mode compatible? + if ((videoModes[i].width >= width) && (videoModes[i].height >= height) && + (videoModes[i].bpp >= bpp)) + { + // first suitable mode? + if (bestMode == -1) + { + bestMode = i; + } else + { + // is it better than the one we got before? + if ((videoModes[i].width < videoModes[bestMode].width) || + (videoModes[i].height < videoModes[bestMode].height) || + (videoModes[i].bpp < videoModes[bestMode].bpp)) + { + bestMode = i; + } + } + } + } + return bestMode; +} diff --git a/src/VBox/Frontends/VBoxFB/Helper.h b/src/VBox/Frontends/VBoxFB/Helper.h new file mode 100644 index 00000000..282f0c6d --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Helper.h @@ -0,0 +1,39 @@ +/** @file + * + * VBox frontends: Framebuffer (FB, DirectFB): + * Helper routines + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxFB_Helper_h +#define VBOX_INCLUDED_SRC_VBoxFB_Helper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define MAX_VIDEOMODES 64 +struct videoMode +{ + uint32_t width; + uint32_t height; + uint32_t bpp; +}; +extern videoMode videoModes[]; +extern uint32_t numVideoModes; + +DFBEnumerationResult enumVideoModesHandler(int width, int height, int bpp, void *callbackdata); +int32_t getBestVideoMode(uint32_t width, uint32_t height, uint32_t bpp); + + +#endif /* !VBOX_INCLUDED_SRC_VBoxFB_Helper_h */ diff --git a/src/VBox/Frontends/VBoxFB/Makefile.kmk b/src/VBox/Frontends/VBoxFB/Makefile.kmk new file mode 100644 index 00000000..76d80eba --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Makefile.kmk @@ -0,0 +1,42 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxFB. +# + +# +# Copyright (C) 2006-2020 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + +PROGRAMS += VBoxFB + +# +# VBoxFB +# +VBoxFB_TEMPLATE = VBOXR3NPEXE +VBoxFB_SOURCES = \ + VBoxFB.cpp \ + Framebuffer.cpp \ + Helper.cpp +VBoxFB_CXXFLAGS = -Wno-non-virtual-dtor -fshort-wchar +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + VBoxFB_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +endif +VBoxFB_INCS = $(VBOX_XPCOM_INCS) /usr/include/directfb +VBoxFB_LIBPATH = $(LIBPATH_XPCOM) +VBoxFB_LIBS = $(LIB_XPCOM) $(LIB_RUNTIME) directfb +VBoxFB_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h + +# generate rules. +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Frontends/VBoxFB/VBoxFB.cpp b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp new file mode 100644 index 00000000..483de59d --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/VBoxFB.cpp @@ -0,0 +1,577 @@ +/** @file + * + * VBox frontends: Framebuffer (FB, DirectFB): + * main() routine. + * + * NOTE: this code has not been tested, so expect bugs. It is not part + * of a regular VirtualBox build. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "VBoxFB.h" +#include "Framebuffer.h" +#include <getopt.h> +#include <VBox/param.h> +#include <iprt/path.h> + +/** + * Globals + */ +uint32_t useFixedVideoMode = 0; +int scaleGuest = 0; +videoMode fixedVideoMode = {0}; +int32_t initialVideoMode = -1; + +void showusage() +{ + printf("\nThe following parameters are supported:\n" + "--startvm uuid start VM with UUID 'uuid'\n" + "--fixedres WxHxBPP always use fixed host resolution\n" + "--listhostmodes display list of supported host display modes and exit\n" + "--scale scale guest video mode to host video mode\n" + "--nodirectblit disable direct blitting, use intermediate framebuffer\n" + "--showlabel show VM name on top of the VM display\n"); +} + +/** entry point */ +int main(int argc, char *argv[]) +{ + const char *uuid = NULL; + int c; + int listHostModes = 0; + int quit = 0; + const struct option options[] = + { + { "help", no_argument, NULL, 'h' }, + { "startvm", required_argument, NULL, 's' }, + { "fixedres", required_argument, NULL, 'f' }, + { "listhostmodes", no_argument, NULL, 'l' }, + { "scale", no_argument, NULL, 'c' } + }; + + printf("VirtualBox DirectFB GUI built %s %s\n" + "(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n" + "(C) 2004-2005 secunet Security Networks AG\n", __DATE__, __TIME__); + + for (;;) + { + c = getopt_long(argc, argv, "s:", options, NULL); + if (c == -1) + break; + switch (c) + { + case 'h': + { + showusage(); + exit(0); + } + case 's': + { + // UUID as string, parse it + RTUUID buuid; + if (!RT_SUCCESS(RTUuidFromStr((PRTUUID)&buuid, optarg))) + { + printf("Error, invalid UUID format given!\n"); + showusage(); + exit(-1); + } + uuid = optarg; + break; + } + case 'f': + { + if (sscanf(optarg, "%ux%ux%u", &fixedVideoMode.width, &fixedVideoMode.height, + &fixedVideoMode.bpp) != 3) + { + printf("Error, invalid resolution argument!\n"); + showusage(); + exit(-1); + } + useFixedVideoMode = 1; + break; + } + case 'l': + { + listHostModes = 1; + break; + } + case 'c': + { + scaleGuest = 1; + break; + } + default: + break; + } + } + + // check if we got a UUID + if (!uuid) + { + printf("Error, no UUID given!\n"); + showusage(); + exit(-1); + } + + + /** + * XPCOM setup + */ + + nsresult rc; + /* + * Note that we scope all nsCOMPtr variables in order to have all XPCOM + * objects automatically released before we call NS_ShutdownXPCOM at the + * end. This is an XPCOM requirement. + */ + { + nsCOMPtr<nsIServiceManager> serviceManager; + rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull); + if (NS_FAILED(rc)) + { + printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc); + exit(-1); + } + + // register our component + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager); + if (!registrar) + { + printf("Error: could not query nsIComponentRegistrar interface!\n"); + exit(-1); + } + registrar->AutoRegister(nsnull); + + /* + * Make sure the main event queue is created. This event queue is + * responsible for dispatching incoming XPCOM IPC messages. The main + * thread should run this event queue's loop during lengthy non-XPCOM + * operations to ensure messages from the VirtualBox server and other + * XPCOM IPC clients are processed. This use case doesn't perform such + * operations so it doesn't run the event loop. + */ + nsCOMPtr<nsIEventQueue> eventQ; + rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rc)) + { + printf("Error: could not get main event queue! rc=%08X\n", rc); + return -1; + } + + /* + * Now XPCOM is ready and we can start to do real work. + * IVirtualBox is the root interface of VirtualBox and will be + * retrieved from the XPCOM component manager. We use the + * XPCOM provided smart pointer nsCOMPtr for all objects because + * that's very convenient and removes the need deal with reference + * counting and freeing. + */ + nsCOMPtr<nsIComponentManager> manager; + rc = NS_GetComponentManager(getter_AddRefs(manager)); + if (NS_FAILED(rc)) + { + printf("Error: could not get component manager! rc=%08X\n", rc); + exit(-1); + } + + nsCOMPtr<IVirtualBox> virtualBox; + rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID, + nsnull, + NS_GET_IID(IVirtualBox), + getter_AddRefs(virtualBox)); + if (NS_FAILED(rc)) + { + printf("Error, could not instantiate object! rc=0x%x\n", rc); + exit(-1); + } + + nsCOMPtr<ISession> session; + rc = manager->CreateInstance(CLSID_Session, + nsnull, + NS_GET_IID(ISession), + getter_AddRefs(session)); + if (NS_FAILED(rc)) + { + printf("Error: could not instantiate Session object! rc = %08X\n", rc); + exit(-1); + } + + // open session for this VM + rc = virtualBox->OpenSession(session, NS_ConvertUTF8toUTF16(uuid).get()); + if (NS_FAILED(rc)) + { + printf("Error: given machine not found!\n"); + exit(-1); + } + nsCOMPtr<IMachine> machine; + session->GetMachine(getter_AddRefs(machine)); + if (!machine) + { + printf("Error: given machine not found!\n"); + exit(-1); + } + nsCOMPtr<IConsole> console; + session->GetConsole(getter_AddRefs(console)); + if (!console) + { + printf("Error: cannot get console!\n"); + exit(-1); + } + + nsCOMPtr<IDisplay> display; + console->GetDisplay(getter_AddRefs(display)); + if (!display) + { + printf("Error: could not get display object!\n"); + exit(-1); + } + + nsCOMPtr<IKeyboard> keyboard; + nsCOMPtr<IMouse> mouse; + VBoxDirectFB *frameBuffer = NULL; + + /** + * Init DirectFB + */ + IDirectFB *dfb = NULL; + IDirectFBSurface *surface = NULL; + IDirectFBInputDevice *dfbKeyboard = NULL; + IDirectFBInputDevice *dfbMouse = NULL; + IDirectFBEventBuffer *dfbEventBuffer = NULL; + DFBSurfaceDescription dsc; + int screen_width, screen_height; + + DFBCHECK(DirectFBInit(&argc, &argv)); + DFBCHECK(DirectFBCreate(&dfb)); + DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN)); + // populate our structure of supported video modes + DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL)); + + if (listHostModes) + { + printf("*****************************************************\n"); + printf("Number of available host video modes: %u\n", numVideoModes); + for (uint32_t i = 0; i < numVideoModes; i++) + { + printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i, + videoModes[i].width, videoModes[i].height, videoModes[i].bpp); + } + printf("Note: display modes with bpp < have been filtered out\n"); + printf("*****************************************************\n"); + goto Leave; + } + + if (useFixedVideoMode) + { + int32_t bestVideoMode = getBestVideoMode(fixedVideoMode.width, + fixedVideoMode.height, + fixedVideoMode.bpp); + // validate the fixed mode + if ((bestVideoMode == -1) || + ((fixedVideoMode.width != videoModes[bestVideoMode].width) || + (fixedVideoMode.height != videoModes[bestVideoMode].height) || + (fixedVideoMode.bpp != videoModes[bestVideoMode].bpp))) + { + printf("Error: the specified fixed video mode is not available!\n"); + exit(-1); + } + } else + { + initialVideoMode = getBestVideoMode(640, 480, 16); + if (initialVideoMode == -1) + { + printf("Error: initial video mode 640x480x16 is not available!\n"); + exit(-1); + } + } + + dsc.flags = DSDESC_CAPS; + dsc.caps = DSCAPS_PRIMARY; + DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface)); + DFBCHECK(surface->Clear(surface, 0, 0, 0, 0)); + DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height)); + DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard)); + DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer)); + DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse)); + DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer)); + + + if (useFixedVideoMode) + { + printf("Information: setting video mode to %ux%ux%u\n", fixedVideoMode.width, + fixedVideoMode.height, fixedVideoMode.bpp); + DFBCHECK(dfb->SetVideoMode(dfb, fixedVideoMode.width, + fixedVideoMode.height, fixedVideoMode.bpp)); + } else + { + printf("Information: starting with default video mode %ux%ux%u\n", + videoModes[initialVideoMode].width, videoModes[initialVideoMode].height, + videoModes[initialVideoMode].bpp); + DFBCHECK(dfb->SetVideoMode(dfb, videoModes[initialVideoMode].width, + videoModes[initialVideoMode].height, + videoModes[initialVideoMode].bpp)); + } + + // register our framebuffer + frameBuffer = new VBoxDirectFB(dfb, surface); + display->SetFramebuffer(0, frameBuffer); + + /** + * Start the VM execution thread + */ + console->PowerUp(NULL); + + console->GetKeyboard(getter_AddRefs(keyboard)); + console->GetMouse(getter_AddRefs(mouse)); + + /** + * Main event loop + */ + #define MAX_KEYEVENTS 10 + PRInt32 keyEvents[MAX_KEYEVENTS]; + int numKeyEvents; + + while (!quit) + { + DFBInputEvent event; + + numKeyEvents = 0; + DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer)); + while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK) + { + int mouseXDelta = 0; + int mouseYDelta = 0; + int mouseZDelta = 0; + switch (event.type) + { + #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0 + #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00) + #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan + case DIET_KEYPRESS: + case DIET_KEYRELEASE: + { + // @@@AH development hack to get out of it! + if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT))) + quit = 1; + + if (numKeyEvents < MAX_KEYEVENTS) + { + //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code); + switch ((uint32_t)event.key_id) + { + case DIKI_CONTROL_R: + QUEUEEXT(); + QUEUEKEY(0x1d); + break; + case DIKI_INSERT: + QUEUEEXT(); + QUEUEKEY(0x52); + break; + case DIKI_DELETE: + QUEUEEXT(); + QUEUEKEY(0x53); + break; + case DIKI_HOME: + QUEUEEXT(); + QUEUEKEY(0x47); + break; + case DIKI_END: + QUEUEEXT(); + QUEUEKEY(0x4f); + break; + case DIKI_PAGE_UP: + QUEUEEXT(); + QUEUEKEY(0x49); + break; + case DIKI_PAGE_DOWN: + QUEUEEXT(); + QUEUEKEY(0x51); + break; + case DIKI_LEFT: + QUEUEEXT(); + QUEUEKEY(0x4b); + break; + case DIKI_RIGHT: + QUEUEEXT(); + QUEUEKEY(0x4d); + break; + case DIKI_UP: + QUEUEEXT(); + QUEUEKEY(0x48); + break; + case DIKI_DOWN: + QUEUEEXT(); + QUEUEKEY(0x50); + break; + case DIKI_KP_DIV: + QUEUEEXT(); + QUEUEKEY(0x35); + break; + case DIKI_KP_ENTER: + QUEUEEXT(); + QUEUEKEY(0x1c); + break; + case DIKI_PRINT: + // the break code is inverted! + if (event.type == DIET_KEYPRESS) + { + QUEUEEXT(); + QUEUEKEY(0x2a); + QUEUEEXT(); + QUEUEKEY(0x37); + } else + { + QUEUEEXT(); + QUEUEKEY(0x37); + QUEUEEXT(); + QUEUEKEY(0x2a); + } + break; + case DIKI_PAUSE: + // This is a super weird key. No break code and a 6 byte + // combination. + if (event.type == DIET_KEYPRESS) + { + QUEUEKEY(0xe1); + QUEUEKEY(0x1d); + QUEUEKEY(0x45); + QUEUEKEY(0xe1); + QUEUEKEY(0x9d); + QUEUEKEY(0xc5); + } + break; + case DIKI_META_L: + // the left Windows logo is a bit different + if (event.type == DIET_KEYPRESS) + { + QUEUEEXT(); + QUEUEKEYRAW(0x1f); + } else + { + QUEUEEXT(); + QUEUEKEYRAW(0xf0); + QUEUEKEYRAW(0x1f); + } + break; + case DIKI_META_R: + // the right Windows logo is a bit different + if (event.type == DIET_KEYPRESS) + { + QUEUEEXT(); + QUEUEKEYRAW(0x27); + } else + { + QUEUEEXT(); + QUEUEKEYRAW(0xf0); + QUEUEKEYRAW(0x27); + } + break; + case DIKI_SUPER_R: + // the popup menu is a bit different + if (event.type == DIET_KEYPRESS) + { + QUEUEEXT(); + QUEUEKEYRAW(0x2f); + } else + { + QUEUEEXT(); + QUEUEKEYRAW(0xf0); + QUEUEKEYRAW(0x2f); + } + break; + + default: + // check if we got a hardware scancode + if (event.key_code != -1) + { + // take the scancode from DirectFB as is + QUEUEKEY(event.key_code); + } else + { + // XXX need extra handling! + } + } + } + break; + } + #undef QUEUEEXT + #undef QUEUEKEY + #undef QUEUEKEYRAW + + case DIET_AXISMOTION: + { + switch (event.axis) + { + case DIAI_X: + mouseXDelta += event.axisrel; + break; + case DIAI_Y: + mouseYDelta += event.axisrel; + break; + case DIAI_Z: + mouseZDelta += event.axisrel; + break; + default: + break; + } + // fall through + } + case DIET_BUTTONPRESS: + // fall through; + case DIET_BUTTONRELEASE: + { + int buttonState = 0; + if (event.buttons & DIBM_LEFT) + buttonState |= MouseButtonState::LeftButton; + if (event.buttons & DIBM_RIGHT) + buttonState |= MouseButtonState::RightButton; + if (event.buttons & DIBM_MIDDLE) + buttonState |= MouseButtonState::MiddleButton; + mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta, + buttonState); + break; + } + default: + break; + } + } + // did we get any keyboard events? + if (numKeyEvents > 0) + { + uint32_t codesStored; + if (numKeyEvents > 1) + { + keyboard->PutScancodes(numKeyEvents, keyEvents, + &codesStored); + } else + { + keyboard->PutScancode(keyEvents[0]); + } + } + } + { + nsCOMPtr<IProgress> progress; + console->PowerDown(getter_AddRefs(progress)); + progress->WaitForCompletion(-1); + } + } + +Leave: + /* + * Perform the standard XPCOM shutdown procedure. + */ + NS_ShutdownXPCOM(nsnull); + + return 0; +} diff --git a/src/VBox/Frontends/VBoxFB/VBoxFB.h b/src/VBox/Frontends/VBoxFB/VBoxFB.h new file mode 100644 index 00000000..e1e89acb --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/VBoxFB.h @@ -0,0 +1,81 @@ +/** @file + * + * VBox frontends: Framebuffer (FB, DirectFB): + * Main header file + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h +#define VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +// XPCOM headers +#include <nsIServiceManager.h> +#include <nsIComponentRegistrar.h> +#include <nsXPCOMGlue.h> +#include <nsMemory.h> +#include <nsIProgrammingLanguage.h> +#include <nsIFile.h> +#include <nsILocalFile.h> +#include <nsString.h> +#include <nsReadableUtils.h> +#include <VirtualBox_XPCOM.h> +#include <ipcIService.h> +#include <nsEventQueueUtils.h> +#include <ipcCID.h> +#include <ipcIDConnectService.h> +#define IPC_DCONNECTSERVICE_CONTRACTID \ + "@mozilla.org/ipc/dconnect-service;1" + +#include <VBox/types.h> +#include <VBox/err.h> +#include <VBox/log.h> +#include <iprt/assert.h> +#include <iprt/uuid.h> + +// DirectFB header +#include <directfb/directfb.h> + +/** + * Executes the passed in expression and verifies the return code. + * + * On failure a debug message is printed to stderr and the application will + * abort with an fatal error. + */ +#define DFBCHECK(x...) \ + do { \ + DFBResult err = x; \ + if (err != DFB_OK) \ + { \ + fprintf(stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \ + DirectFBErrorFatal(#x, err); \ + } \ + } while (0) + +#include "Helper.h" + +/** + * Globals + */ +extern uint32_t useFixedVideoMode; +extern videoMode fixedVideoMode; +extern int scaleGuest; + +#endif /* !VBOX_INCLUDED_SRC_VBoxFB_VBoxFB_h */ |