diff options
Diffstat (limited to 'src/VBox/Frontends/VBoxFB/Framebuffer.cpp')
-rw-r--r-- | src/VBox/Frontends/VBoxFB/Framebuffer.cpp | 409 |
1 files changed, 409 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..db3b7fa1 --- /dev/null +++ b/src/VBox/Frontends/VBoxFB/Framebuffer.cpp @@ -0,0 +1,409 @@ +/* $Id: Framebuffer.cpp $ */ +/** @file + * VBoxFB - Implementation of the VBoxDirectFB class. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#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((DFBResult)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(BitmapFormat_T *pixelFormat) +{ + if (!pixelFormat) + return NS_ERROR_INVALID_POINTER; + *pixelFormat = BitmapFormat_RGBA; + 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::GetCapabilities(PRUint32 *pcCapabilites, FramebufferCapabilities_T **ppaenmCapabilities) +{ + RT_NOREF(pcCapabilites, ppaenmCapabilities); + AssertMsgFailed(("Not implemented")); + return E_NOTIMPL; +} + + +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 (g_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::NotifyUpdateImage(PRUint32 x, PRUint32 y, PRUint32 cx, PRUint32 cy, PRUint32 cbImage, PRUint8 *pbImage) +{ + RT_NOREF(x, y, cx, cy, cbImage, pbImage); + AssertMsgFailed(("Not implemented")); + return E_NOTIMPL; +} + +NS_IMETHODIMP VBoxDirectFB::NotifyChange(PRUint32 idScreen, PRUint32 xOrigin, PRUint32 yOrigin, PRUint32 cx, PRUint32 cy) +{ + RT_NOREF(idScreen, xOrigin, yOrigin, cx, cy); + AssertMsgFailed(("Not implemented")); + return E_NOTIMPL; +} + +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 (g_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 ( g_videoModes[bestMode].width != w + || g_videoModes[bestMode].height != h + || g_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, + g_videoModes[bestMode].width, + g_videoModes[bestMode].height, + g_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) +{ + RT_NOREF(w, h, bpp); + if (!supported) + return NS_ERROR_INVALID_POINTER; + *supported = true; + return NS_OK; +} + +NS_IMETHODIMP VBoxDirectFB::GetVisibleRegion(PRUint8 *rectangles, PRUint32 count, PRUint32 *countCopied) +{ + RT_NOREF(count); + 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) +{ + RT_NOREF(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, PRUint32 cbData, PRUint8 *pbData) +{ + RT_NOREF(type, cbData, pbData); + 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; +} |