VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp@ 51548

Last change on this file since 51548 was 51547, checked in by vboxsync, 11 years ago

VBoxSDL: new IFramebuffer interface cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.1 KB
Line 
1/** @file
2 *
3 * VBox frontends: VBoxSDL (simple frontend based on SDL):
4 * Implementation of VBoxSDLFB (SDL framebuffer) class
5 */
6
7/*
8 * Copyright (C) 2006-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/com/com.h>
20#include <VBox/com/string.h>
21#include <VBox/com/Guid.h>
22#include <VBox/com/ErrorInfo.h>
23#include <VBox/com/VirtualBox.h>
24
25#include <iprt/stream.h>
26#include <iprt/env.h>
27
28#ifdef RT_OS_OS2
29# undef RT_MAX
30// from <iprt/cdefs.h>
31# define RT_MAX(Value1, Value2) ((Value1) >= (Value2) ? (Value1) : (Value2))
32#endif
33
34using namespace com;
35
36#define LOG_GROUP LOG_GROUP_GUI
37#include <VBox/err.h>
38#include <VBox/log.h>
39
40#include "VBoxSDL.h"
41#include "Framebuffer.h"
42#include "Ico64x01.h"
43
44#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
45#include <SDL_syswm.h> /* for SDL_GetWMInfo() */
46#endif
47
48#if defined(VBOX_WITH_XPCOM)
49NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VBoxSDLFB, IFramebuffer)
50NS_DECL_CLASSINFO(VBoxSDLFB)
51NS_IMPL_THREADSAFE_ISUPPORTS2_CI(VBoxSDLFBOverlay, IFramebufferOverlay, IFramebuffer)
52NS_DECL_CLASSINFO(VBoxSDLFBOverlay)
53#endif
54
55#ifdef VBOX_SECURELABEL
56/* function pointers */
57extern "C"
58{
59DECLSPEC int (SDLCALL *pTTF_Init)(void);
60DECLSPEC TTF_Font* (SDLCALL *pTTF_OpenFont)(const char *file, int ptsize);
61DECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Solid)(TTF_Font *font, const char *text, SDL_Color fg);
62DECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Blended)(TTF_Font *font, const char *text, SDL_Color fg);
63DECLSPEC void (SDLCALL *pTTF_CloseFont)(TTF_Font *font);
64DECLSPEC void (SDLCALL *pTTF_Quit)(void);
65}
66#endif /* VBOX_SECURELABEL */
67
68static bool gfSdlInitialized = false; /**< if SDL was initialized */
69static SDL_Surface *gWMIcon = NULL; /**< the application icon */
70static RTNATIVETHREAD gSdlNativeThread = NIL_RTNATIVETHREAD; /**< the SDL thread */
71
72//
73// Constructor / destructor
74//
75
76/**
77 * SDL framebuffer constructor. It is called from the main
78 * (i.e. SDL) thread. Therefore it is safe to use SDL calls
79 * here.
80 * @param fFullscreen flag whether we start in fullscreen mode
81 * @param fResizable flag whether the SDL window should be resizable
82 * @param fShowSDLConfig flag whether we print out SDL settings
83 * @param fKeepHostRes flag whether we switch the host screen resolution
84 * when switching to fullscreen or not
85 * @param iFixedWidth fixed SDL width (-1 means not set)
86 * @param iFixedHeight fixed SDL height (-1 means not set)
87 */
88VBoxSDLFB::VBoxSDLFB(uint32_t uScreenId,
89 bool fFullscreen, bool fResizable, bool fShowSDLConfig,
90 bool fKeepHostRes, uint32_t u32FixedWidth,
91 uint32_t u32FixedHeight, uint32_t u32FixedBPP)
92{
93 int rc;
94 LogFlow(("VBoxSDLFB::VBoxSDLFB\n"));
95
96#if defined (RT_OS_WINDOWS)
97 refcnt = 0;
98#endif
99
100 mScreenId = uScreenId;
101 mScreen = NULL;
102#ifdef VBOX_WITH_SDL13
103 mWindow = 0;
104 mTexture = 0;
105#endif
106 mSurfVRAM = NULL;
107 mfInitialized = false;
108 mfFullscreen = fFullscreen;
109 mfKeepHostRes = fKeepHostRes;
110 mTopOffset = 0;
111 mfResizable = fResizable;
112 mfShowSDLConfig = fShowSDLConfig;
113 mFixedSDLWidth = u32FixedWidth;
114 mFixedSDLHeight = u32FixedHeight;
115 mFixedSDLBPP = u32FixedBPP;
116 mCenterXOffset = 0;
117 mCenterYOffset = 0;
118 /* Start with standard screen dimensions. */
119 mGuestXRes = 640;
120 mGuestYRes = 480;
121 mPtrVRAM = NULL;
122 mBitsPerPixel = 0;
123 mBytesPerLine = 0;
124 mfSameSizeRequested = false;
125#ifdef VBOX_SECURELABEL
126 mLabelFont = NULL;
127 mLabelHeight = 0;
128 mLabelOffs = 0;
129#endif
130
131 mfUpdates = false;
132
133 rc = RTCritSectInit(&mUpdateLock);
134 AssertMsg(rc == VINF_SUCCESS, ("Error from RTCritSectInit!\n"));
135
136 resizeGuest();
137 Assert(mScreen);
138 mfInitialized = true;
139}
140
141VBoxSDLFB::~VBoxSDLFB()
142{
143 LogFlow(("VBoxSDLFB::~VBoxSDLFB\n"));
144 if (mSurfVRAM)
145 {
146 SDL_FreeSurface(mSurfVRAM);
147 mSurfVRAM = NULL;
148 }
149 mScreen = NULL;
150
151#ifdef VBOX_SECURELABEL
152 if (mLabelFont)
153 pTTF_CloseFont(mLabelFont);
154 if (pTTF_Quit)
155 pTTF_Quit();
156#endif
157
158 RTCritSectDelete(&mUpdateLock);
159}
160
161bool VBoxSDLFB::init(bool fShowSDLConfig)
162{
163 LogFlow(("VBoxSDLFB::init\n"));
164
165 /* memorize the thread that inited us, that's the SDL thread */
166 gSdlNativeThread = RTThreadNativeSelf();
167
168#ifdef RT_OS_WINDOWS
169 /* default to DirectX if nothing else set */
170 if (!RTEnvExist("SDL_VIDEODRIVER"))
171 {
172 _putenv("SDL_VIDEODRIVER=directx");
173// _putenv("SDL_VIDEODRIVER=windib");
174 }
175#endif
176#ifdef VBOXSDL_WITH_X11
177 /* On some X servers the mouse is stuck inside the bottom right corner.
178 * See http://wiki.clug.org.za/wiki/QEMU_mouse_not_working */
179 RTEnvSet("SDL_VIDEO_X11_DGAMOUSE", "0");
180#endif
181 int rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
182 if (rc != 0)
183 {
184 RTPrintf("SDL Error: '%s'\n", SDL_GetError());
185 return false;
186 }
187 gfSdlInitialized = true;
188
189 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
190 Assert(videoInfo);
191 if (videoInfo)
192 {
193 /* output what SDL is capable of */
194 if (fShowSDLConfig)
195 RTPrintf("SDL capabilities:\n"
196 " Hardware surface support: %s\n"
197 " Window manager available: %s\n"
198 " Screen to screen blits accelerated: %s\n"
199 " Screen to screen colorkey blits accelerated: %s\n"
200 " Screen to screen alpha blits accelerated: %s\n"
201 " Memory to screen blits accelerated: %s\n"
202 " Memory to screen colorkey blits accelerated: %s\n"
203 " Memory to screen alpha blits accelerated: %s\n"
204 " Color fills accelerated: %s\n"
205 " Video memory in kilobytes: %d\n"
206 " Optimal bpp mode: %d\n"
207 "SDL video driver: %s\n",
208 videoInfo->hw_available ? "yes" : "no",
209 videoInfo->wm_available ? "yes" : "no",
210 videoInfo->blit_hw ? "yes" : "no",
211 videoInfo->blit_hw_CC ? "yes" : "no",
212 videoInfo->blit_hw_A ? "yes" : "no",
213 videoInfo->blit_sw ? "yes" : "no",
214 videoInfo->blit_sw_CC ? "yes" : "no",
215 videoInfo->blit_sw_A ? "yes" : "no",
216 videoInfo->blit_fill ? "yes" : "no",
217 videoInfo->video_mem,
218 videoInfo->vfmt->BitsPerPixel,
219 RTEnvGet("SDL_VIDEODRIVER"));
220 }
221
222 if (12320 == g_cbIco64x01)
223 {
224 gWMIcon = SDL_AllocSurface(SDL_SWSURFACE, 64, 64, 24, 0xff, 0xff00, 0xff0000, 0);
225 /** @todo make it as simple as possible. No PNM interpreter here... */
226 if (gWMIcon)
227 {
228 memcpy(gWMIcon->pixels, g_abIco64x01+32, g_cbIco64x01-32);
229 SDL_WM_SetIcon(gWMIcon, NULL);
230 }
231 }
232
233 return true;
234}
235
236/**
237 * Terminate SDL
238 *
239 * @remarks must be called from the SDL thread!
240 */
241void VBoxSDLFB::uninit()
242{
243 if (gfSdlInitialized)
244 {
245 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
246 SDL_QuitSubSystem(SDL_INIT_VIDEO);
247 if (gWMIcon)
248 {
249 SDL_FreeSurface(gWMIcon);
250 gWMIcon = NULL;
251 }
252 }
253}
254
255/**
256 * Returns the current framebuffer width in pixels.
257 *
258 * @returns COM status code
259 * @param width Address of result buffer.
260 */
261STDMETHODIMP VBoxSDLFB::COMGETTER(Width)(ULONG *width)
262{
263 LogFlow(("VBoxSDLFB::GetWidth\n"));
264 if (!width)
265 return E_INVALIDARG;
266 *width = mGuestXRes;
267 return S_OK;
268}
269
270/**
271 * Returns the current framebuffer height in pixels.
272 *
273 * @returns COM status code
274 * @param height Address of result buffer.
275 */
276STDMETHODIMP VBoxSDLFB::COMGETTER(Height)(ULONG *height)
277{
278 LogFlow(("VBoxSDLFB::GetHeight\n"));
279 if (!height)
280 return E_INVALIDARG;
281 *height = mGuestYRes;
282 return S_OK;
283}
284
285/**
286 * Lock the framebuffer (make its address immutable).
287 *
288 * @returns COM status code
289 */
290STDMETHODIMP VBoxSDLFB::Lock()
291{
292 LogFlow(("VBoxSDLFB::Lock\n"));
293 RTCritSectEnter(&mUpdateLock);
294 return S_OK;
295}
296
297/**
298 * Unlock the framebuffer.
299 *
300 * @returns COM status code
301 */
302STDMETHODIMP VBoxSDLFB::Unlock()
303{
304 LogFlow(("VBoxSDLFB::Unlock\n"));
305 RTCritSectLeave(&mUpdateLock);
306 return S_OK;
307}
308
309/**
310 * Return the framebuffer start address.
311 *
312 * @returns COM status code.
313 * @param address Pointer to result variable.
314 */
315STDMETHODIMP VBoxSDLFB::COMGETTER(Address)(BYTE **address)
316{
317 LogFlow(("VBoxSDLFB::GetAddress\n"));
318 if (!address)
319 return E_INVALIDARG;
320
321 if (!mSurfVRAM)
322 {
323 /* That's actually rather bad. */
324 AssertMsgFailed(("mSurfVRAM is NULL!\n"));
325 return E_FAIL;
326 }
327
328 *address = (BYTE *) mSurfVRAM->pixels;
329 LogFlow(("VBoxSDL::GetAddress returning %p\n", *address));
330 return S_OK;
331}
332
333/**
334 * Return the current framebuffer color depth.
335 *
336 * @returns COM status code
337 * @param bitsPerPixel Address of result variable
338 */
339STDMETHODIMP VBoxSDLFB::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
340{
341 LogFlow(("VBoxSDLFB::GetBitsPerPixel\n"));
342 if (!bitsPerPixel)
343 return E_INVALIDARG;
344 /* get the information directly from the surface in use */
345 Assert(mSurfVRAM);
346 *bitsPerPixel = (ULONG)(mSurfVRAM ? mSurfVRAM->format->BitsPerPixel : 0);
347 return S_OK;
348}
349
350/**
351 * Return the current framebuffer line size in bytes.
352 *
353 * @returns COM status code.
354 * @param lineSize Address of result variable.
355 */
356STDMETHODIMP VBoxSDLFB::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
357{
358 LogFlow(("VBoxSDLFB::GetBytesPerLine\n"));
359 if (!bytesPerLine)
360 return E_INVALIDARG;
361 /* get the information directly from the surface */
362 Assert(mSurfVRAM);
363 *bytesPerLine = (ULONG)(mSurfVRAM ? mSurfVRAM->pitch : 0);
364 return S_OK;
365}
366
367STDMETHODIMP VBoxSDLFB::COMGETTER(PixelFormat) (ULONG *pixelFormat)
368{
369 if (!pixelFormat)
370 return E_POINTER;
371 *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
372 return S_OK;
373}
374
375STDMETHODIMP VBoxSDLFB::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM)
376{
377 if (!usesGuestVRAM)
378 return E_POINTER;
379 *usesGuestVRAM = TRUE;
380 return S_OK;
381}
382
383/**
384 * Returns by how many pixels the guest should shrink its
385 * video mode height values.
386 *
387 * @returns COM status code.
388 * @param heightReduction Address of result variable.
389 */
390STDMETHODIMP VBoxSDLFB::COMGETTER(HeightReduction)(ULONG *heightReduction)
391{
392 if (!heightReduction)
393 return E_POINTER;
394#ifdef VBOX_SECURELABEL
395 *heightReduction = mLabelHeight;
396#else
397 *heightReduction = 0;
398#endif
399 return S_OK;
400}
401
402/**
403 * Returns a pointer to an alpha-blended overlay used for displaying status
404 * icons above the framebuffer.
405 *
406 * @returns COM status code.
407 * @param aOverlay The overlay framebuffer.
408 */
409STDMETHODIMP VBoxSDLFB::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
410{
411 if (!aOverlay)
412 return E_POINTER;
413 /* Not yet implemented */
414 *aOverlay = 0;
415 return S_OK;
416}
417
418/**
419 * Returns handle of window where framebuffer context is being drawn
420 *
421 * @returns COM status code.
422 * @param winId Handle of associated window.
423 */
424STDMETHODIMP VBoxSDLFB::COMGETTER(WinId)(int64_t *winId)
425{
426 if (!winId)
427 return E_POINTER;
428 *winId = mWinId;
429 return S_OK;
430}
431
432/**
433 * Notify framebuffer of an update.
434 *
435 * @returns COM status code
436 * @param x Update region upper left corner x value.
437 * @param y Update region upper left corner y value.
438 * @param w Update region width in pixels.
439 * @param h Update region height in pixels.
440 * @param finished Address of output flag whether the update
441 * could be fully processed in this call (which
442 * has to return immediately) or VBox should wait
443 * for a call to the update complete API before
444 * continuing with display updates.
445 */
446STDMETHODIMP VBoxSDLFB::NotifyUpdate(ULONG x, ULONG y,
447 ULONG w, ULONG h)
448{
449 /*
450 * The input values are in guest screen coordinates.
451 */
452 LogFlow(("VBoxSDLFB::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
453 x, y, w, h));
454
455#ifdef VBOXSDL_WITH_X11
456 /*
457 * SDL does not allow us to make this call from any other thread than
458 * the main SDL thread (which initialized the video mode). So we have
459 * to send an event to the main SDL thread and process it there. For
460 * sake of simplicity, we encode all information in the event parameters.
461 */
462 SDL_Event event;
463 event.type = SDL_USEREVENT;
464 event.user.code = mScreenId;
465 event.user.type = SDL_USER_EVENT_UPDATERECT;
466 // 16 bit is enough for coordinates
467 event.user.data1 = (void*)(uintptr_t)(x << 16 | y);
468 event.user.data2 = (void*)(uintptr_t)(w << 16 | h);
469 PushNotifyUpdateEvent(&event);
470#else /* !VBOXSDL_WITH_X11 */
471 update(x, y, w, h, true /* fGuestRelative */);
472#endif /* !VBOXSDL_WITH_X11 */
473
474 return S_OK;
475}
476
477extern ComPtr<IDisplay> gpDisplay;
478
479STDMETHODIMP VBoxSDLFB::NotifyChange(ULONG aScreenId,
480 ULONG aXOrigin,
481 ULONG aYOrigin,
482 ULONG aWidth,
483 ULONG aHeight)
484{
485 LogRel(("NotifyChange: %d %d,%d %dx%d\n",
486 aScreenId, aXOrigin, aYOrigin, aWidth, aHeight));
487
488 RTCritSectEnter(&mUpdateLock);
489
490 /* Disable screen updates. */
491 mfUpdates = false;
492
493 /* Save the new bitmap. */
494 mpPendingSourceBitmap.setNull();
495 gpDisplay->QuerySourceBitmap(aScreenId, mpPendingSourceBitmap.asOutParam());
496
497 RTCritSectLeave(&mUpdateLock);
498
499 SDL_Event event;
500 event.type = SDL_USEREVENT;
501 event.user.type = SDL_USER_EVENT_NOTIFYCHANGE;
502 event.user.code = mScreenId;
503
504 PushSDLEventForSure(&event);
505
506 RTThreadYield();
507
508 return S_OK;
509}
510
511/**
512 * Returns whether we like the given video mode.
513 *
514 * @returns COM status code
515 * @param width video mode width in pixels
516 * @param height video mode height in pixels
517 * @param bpp video mode bit depth in bits per pixel
518 * @param supported pointer to result variable
519 */
520STDMETHODIMP VBoxSDLFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported)
521{
522 if (!supported)
523 return E_POINTER;
524
525 /* are constraints set? */
526 if ( ( (mMaxScreenWidth != ~(uint32_t)0)
527 && (width > mMaxScreenWidth))
528 || ( (mMaxScreenHeight != ~(uint32_t)0)
529 && (height > mMaxScreenHeight)))
530 {
531 /* nope, we don't want that (but still don't freak out if it is set) */
532#ifdef DEBUG
533 printf("VBoxSDL::VideoModeSupported: we refused mode %dx%dx%d\n", width, height, bpp);
534#endif
535 *supported = false;
536 }
537 else
538 {
539 /* anything will do */
540 *supported = true;
541 }
542 return S_OK;
543}
544
545STDMETHODIMP VBoxSDLFB::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
546 ULONG *aCountCopied)
547{
548 PRTRECT rects = (PRTRECT)aRectangles;
549
550 if (!rects)
551 return E_POINTER;
552
553 /// @todo
554
555 NOREF(aCount);
556 NOREF(aCountCopied);
557
558 return S_OK;
559}
560
561STDMETHODIMP VBoxSDLFB::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
562{
563 PRTRECT rects = (PRTRECT)aRectangles;
564
565 if (!rects)
566 return E_POINTER;
567
568 /// @todo
569
570 NOREF(aCount);
571
572 return S_OK;
573}
574
575STDMETHODIMP VBoxSDLFB::ProcessVHWACommand(BYTE *pCommand)
576{
577 return E_NOTIMPL;
578}
579
580STDMETHODIMP VBoxSDLFB::Notify3DEvent(ULONG uType, BYTE *pReserved)
581{
582 return E_NOTIMPL;
583}
584
585//
586// Internal public methods
587//
588
589/* This method runs on the main SDL thread. */
590void VBoxSDLFB::notifyChange(ULONG aScreenId)
591{
592 /* Disable screen updates. */
593 RTCritSectEnter(&mUpdateLock);
594
595 if (mpPendingSourceBitmap.isNull())
596 {
597 /* Do nothing. Change event already processed. */
598 RTCritSectLeave(&mUpdateLock);
599 return;
600 }
601
602 /* Release the current bitmap and keep the pending one. */
603 mpSourceBitmap = mpPendingSourceBitmap;
604 mpPendingSourceBitmap.setNull();
605
606 RTCritSectLeave(&mUpdateLock);
607
608 if (mpSourceBitmap.isNull())
609 {
610 mPtrVRAM = NULL;
611 mBitsPerPixel = 32;
612 mBytesPerLine = mGuestXRes * 4;
613 }
614 else
615 {
616 BYTE *pAddress = NULL;
617 ULONG ulWidth = 0;
618 ULONG ulHeight = 0;
619 ULONG ulBitsPerPixel = 0;
620 ULONG ulBytesPerLine = 0;
621 ULONG ulPixelFormat = 0;
622
623 mpSourceBitmap->QueryBitmapInfo(&pAddress,
624 &ulWidth,
625 &ulHeight,
626 &ulBitsPerPixel,
627 &ulBytesPerLine,
628 &ulPixelFormat);
629
630 if ( mGuestXRes == ulWidth
631 && mGuestYRes == ulHeight
632 && mBitsPerPixel == ulBitsPerPixel
633 && mBytesPerLine == ulBytesPerLine
634 && mPtrVRAM == pAddress
635 )
636 {
637 mfSameSizeRequested = true;
638 }
639 else
640 {
641 mfSameSizeRequested = false;
642 }
643
644 mGuestXRes = ulWidth;
645 mGuestYRes = ulHeight;
646 mPtrVRAM = pAddress;
647 mBitsPerPixel = ulBitsPerPixel;
648 mBytesPerLine = ulBytesPerLine;
649 }
650
651 resizeGuest();
652}
653
654/**
655 * Method that does the actual resize of the guest framebuffer and
656 * then changes the SDL framebuffer setup.
657 */
658void VBoxSDLFB::resizeGuest()
659{
660 LogFlowFunc (("mGuestXRes: %d, mGuestYRes: %d\n", mGuestXRes, mGuestYRes));
661 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(),
662 ("Wrong thread! SDL is not threadsafe!\n"));
663
664 const uint32_t Rmask = 0x00FF0000, Gmask = 0x0000FF00, Bmask = 0x000000FF, Amask = 0;
665
666 /* first free the current surface */
667 if (mSurfVRAM)
668 {
669 SDL_FreeSurface(mSurfVRAM);
670 mSurfVRAM = NULL;
671 }
672
673 if (mPtrVRAM)
674 {
675 /* Create a source surface from the source bitmap. */
676 mSurfVRAM = SDL_CreateRGBSurfaceFrom(mPtrVRAM, mGuestXRes, mGuestYRes, mBitsPerPixel,
677 mBytesPerLine, Rmask, Gmask, Bmask, Amask);
678 LogFlow(("VBoxSDL:: using the source bitmap\n"));
679 }
680 else
681 {
682 mSurfVRAM = SDL_CreateRGBSurface(SDL_SWSURFACE, mGuestXRes, mGuestYRes, mBitsPerPixel,
683 Rmask, Gmask, Bmask, Amask);
684 LogFlow(("VBoxSDL:: using SDL_SWSURFACE\n"));
685 }
686 LogFlow(("VBoxSDL:: created VRAM surface %p\n", mSurfVRAM));
687
688 if (mfSameSizeRequested)
689 {
690 mfSameSizeRequested = false;
691 LogFlow(("VBoxSDL:: the same resolution requested, skipping the resize.\n"));
692 }
693 else
694 {
695 /* now adjust the SDL resolution */
696 resizeSDL();
697 }
698
699 /* Enable screen updates. */
700 RTCritSectEnter(&mUpdateLock);
701 mfUpdates = true;
702 RTCritSectLeave(&mUpdateLock);
703
704 repaint();
705}
706
707/**
708 * Sets SDL video mode. This is independent from guest video
709 * mode changes.
710 *
711 * @remarks Must be called from the SDL thread!
712 */
713void VBoxSDLFB::resizeSDL(void)
714{
715 LogFlow(("VBoxSDL:resizeSDL\n"));
716
717 /*
718 * We request a hardware surface from SDL so that we can perform
719 * accelerated system memory to VRAM blits. The way video handling
720 * works it that on the one hand we have the screen surface from SDL
721 * and on the other hand we have a software surface that we create
722 * using guest VRAM memory for linear modes and using SDL allocated
723 * system memory for text and non linear graphics modes. We never
724 * directly write to the screen surface but always use SDL blitting
725 * functions to blit from our system memory surface to the VRAM.
726 * Therefore, SDL can take advantage of hardware acceleration.
727 */
728 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
729#ifndef RT_OS_OS2 /* doesn't seem to work for some reason... */
730 if (mfResizable)
731 sdlFlags |= SDL_RESIZABLE;
732#endif
733 if (mfFullscreen)
734 sdlFlags |= SDL_FULLSCREEN;
735
736 /*
737 * Now we have to check whether there are video mode restrictions
738 */
739 SDL_Rect **modes;
740 /* Get available fullscreen/hardware modes */
741 modes = SDL_ListModes(NULL, sdlFlags);
742 Assert(modes != NULL);
743 /* -1 means that any mode is possible (usually non fullscreen) */
744 if (modes != (SDL_Rect **)-1)
745 {
746 /*
747 * according to the SDL documentation, the API guarantees that
748 * the modes are sorted from larger to smaller, so we just
749 * take the first entry as the maximum.
750 */
751 mMaxScreenWidth = modes[0]->w;
752 mMaxScreenHeight = modes[0]->h;
753 }
754 else
755 {
756 /* no restriction */
757 mMaxScreenWidth = ~(uint32_t)0;
758 mMaxScreenHeight = ~(uint32_t)0;
759 }
760
761 uint32_t newWidth;
762 uint32_t newHeight;
763
764 /* reset the centering offsets */
765 mCenterXOffset = 0;
766 mCenterYOffset = 0;
767
768 /* we either have a fixed SDL resolution or we take the guest's */
769 if (mFixedSDLWidth != ~(uint32_t)0)
770 {
771 newWidth = mFixedSDLWidth;
772 newHeight = mFixedSDLHeight;
773 }
774 else
775 {
776 newWidth = RT_MIN(mGuestXRes, mMaxScreenWidth);
777#ifdef VBOX_SECURELABEL
778 newHeight = RT_MIN(mGuestYRes + mLabelHeight, mMaxScreenHeight);
779#else
780 newHeight = RT_MIN(mGuestYRes, mMaxScreenHeight);
781#endif
782 }
783
784 /* we don't have any extra space by default */
785 mTopOffset = 0;
786
787#if defined(VBOX_WITH_SDL13)
788 int sdlWindowFlags = SDL_WINDOW_SHOWN;
789 if (mfResizable)
790 sdlWindowFlags |= SDL_WINDOW_RESIZABLE;
791 if (!mWindow)
792 {
793 SDL_DisplayMode desktop_mode;
794 int x = 40 + mScreenId * 20;
795 int y = 40 + mScreenId * 15;
796
797 SDL_GetDesktopDisplayMode(&desktop_mode);
798 /* create new window */
799
800 char szTitle[64];
801 RTStrPrintf(szTitle, sizeof(szTitle), "SDL window %d", mScreenId);
802 mWindow = SDL_CreateWindow(szTitle, x, y,
803 newWidth, newHeight, sdlWindowFlags);
804 if (SDL_CreateRenderer(mWindow, -1,
805 SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD) < 0)
806 AssertReleaseFailed();
807
808 SDL_GetRendererInfo(&mRenderInfo);
809
810 mTexture = SDL_CreateTexture(desktop_mode.format,
811 SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight);
812 if (!mTexture)
813 AssertReleaseFailed();
814 }
815 else
816 {
817 int w, h;
818 uint32_t format;
819 int access;
820
821 /* resize current window */
822 SDL_GetWindowSize(mWindow, &w, &h);
823
824 if (w != (int)newWidth || h != (int)newHeight)
825 SDL_SetWindowSize(mWindow, newWidth, newHeight);
826
827 SDL_QueryTexture(mTexture, &format, &access, &w, &h);
828 SDL_SelectRenderer(mWindow);
829 SDL_DestroyTexture(mTexture);
830 mTexture = SDL_CreateTexture(format, access, newWidth, newHeight);
831 if (!mTexture)
832 AssertReleaseFailed();
833 }
834
835 void *pixels;
836 int pitch;
837 int w, h, bpp;
838 uint32_t Rmask, Gmask, Bmask, Amask;
839 uint32_t format;
840
841 if (SDL_QueryTexture(mTexture, &format, NULL, &w, &h) < 0)
842 AssertReleaseFailed();
843
844 if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask))
845 AssertReleaseFailed();
846
847 if (SDL_QueryTexturePixels(mTexture, &pixels, &pitch) == 0)
848 {
849 mScreen = SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch,
850 Rmask, Gmask, Bmask, Amask);
851 }
852 else
853 {
854 mScreen = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
855 AssertReleaseFailed();
856 }
857
858 SDL_SetClipRect(mScreen, NULL);
859
860#else
861 /*
862 * Now set the screen resolution and get the surface pointer
863 * @todo BPP is not supported!
864 */
865 mScreen = SDL_SetVideoMode(newWidth, newHeight, 0, sdlFlags);
866
867 /*
868 * Set the Window ID. Currently used for OpenGL accelerated guests.
869 */
870# if defined (RT_OS_WINDOWS)
871 SDL_SysWMinfo info;
872 SDL_VERSION(&info.version);
873 if (SDL_GetWMInfo(&info))
874 mWinId = (LONG64) info.window;
875# elif defined (RT_OS_LINUX)
876 SDL_SysWMinfo info;
877 SDL_VERSION(&info.version);
878 if (SDL_GetWMInfo(&info))
879 mWinId = (LONG64) info.info.x11.wmwindow;
880# else
881 /* XXX ignore this for other architectures */
882# endif
883#endif
884#ifdef VBOX_SECURELABEL
885 /*
886 * For non fixed SDL resolution, the above call tried to add the label height
887 * to the guest height. If it worked, we have an offset. If it didn't the below
888 * code will try again with the original guest resolution.
889 */
890 if (mFixedSDLWidth == ~(uint32_t)0)
891 {
892 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
893 if (!mScreen)
894 {
895 mScreen = SDL_SetVideoMode(newWidth, newHeight - mLabelHeight, 0, sdlFlags);
896 }
897 else
898 {
899 /* we now have some extra space */
900 mTopOffset = mLabelHeight;
901 }
902 }
903 else
904 {
905 /* in case the guest resolution is small enough, we do have a top offset */
906 if (mFixedSDLHeight - mGuestYRes >= mLabelHeight)
907 mTopOffset = mLabelHeight;
908
909 /* we also might have to center the guest picture */
910 if (mFixedSDLWidth > mGuestXRes)
911 mCenterXOffset = (mFixedSDLWidth - mGuestXRes) / 2;
912 if (mFixedSDLHeight > mGuestYRes + mLabelHeight)
913 mCenterYOffset = (mFixedSDLHeight - (mGuestYRes + mLabelHeight)) / 2;
914 }
915#endif
916 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
917 if (mScreen)
918 {
919#ifdef VBOX_WIN32_UI
920 /* inform the UI code */
921 resizeUI(mScreen->w, mScreen->h);
922#endif
923 if (mfShowSDLConfig)
924 RTPrintf("Resized to %dx%d, screen surface type: %s\n", mScreen->w, mScreen->h,
925 ((mScreen->flags & SDL_HWSURFACE) == 0) ? "software" : "hardware");
926 }
927}
928
929/**
930 * Update specified framebuffer area. The coordinates can either be
931 * relative to the guest framebuffer or relative to the screen.
932 *
933 * @remarks Must be called from the SDL thread on Linux!
934 * @param x left column
935 * @param y top row
936 * @param w width in pixels
937 * @param h height in pixels
938 * @param fGuestRelative flag whether the above values are guest relative or screen relative;
939 */
940void VBoxSDLFB::update(int x, int y, int w, int h, bool fGuestRelative)
941{
942#ifdef VBOXSDL_WITH_X11
943 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
944#endif
945 Assert(mScreen);
946 Assert(mSurfVRAM);
947 if (!mScreen || !mSurfVRAM)
948 return;
949
950 RTCritSectEnter(&mUpdateLock);
951 Log(("Updates %d, %d,%d %dx%d\n", mfUpdates, x, y, w, h));
952 if (!mfUpdates)
953 {
954 RTCritSectLeave(&mUpdateLock);
955 return;
956 }
957 /* the source and destination rectangles */
958 SDL_Rect srcRect;
959 SDL_Rect dstRect;
960
961 /* this is how many pixels we have to cut off from the height for this specific blit */
962 int yCutoffGuest = 0;
963
964#ifdef VBOX_SECURELABEL
965 bool fPaintLabel = false;
966 /* if we have a label and no space for it, we have to cut off a bit */
967 if (mLabelHeight && !mTopOffset)
968 {
969 if (y < (int)mLabelHeight)
970 yCutoffGuest = mLabelHeight - y;
971 }
972#endif
973
974 /**
975 * If we get a SDL window relative update, we
976 * just perform a full screen update to keep things simple.
977 *
978 * @todo improve
979 */
980 if (!fGuestRelative)
981 {
982#ifdef VBOX_SECURELABEL
983 /* repaint the label if necessary */
984 if (y < (int)mLabelHeight)
985 fPaintLabel = true;
986#endif
987 x = 0;
988 w = mGuestXRes;
989 y = 0;
990 h = mGuestYRes;
991 }
992
993 srcRect.x = x;
994 srcRect.y = y + yCutoffGuest;
995 srcRect.w = w;
996 srcRect.h = RT_MAX(0, h - yCutoffGuest);
997
998 /*
999 * Destination rectangle is just offset by the label height.
1000 * There are two cases though: label height is added to the
1001 * guest resolution (mTopOffset == mLabelHeight; yCutoffGuest == 0)
1002 * or the label cuts off a portion of the guest screen (mTopOffset == 0;
1003 * yCutoffGuest >= 0)
1004 */
1005 dstRect.x = x + mCenterXOffset;
1006#ifdef VBOX_SECURELABEL
1007 dstRect.y = RT_MAX(mLabelHeight, y + yCutoffGuest + mTopOffset) + mCenterYOffset;
1008#else
1009 dstRect.y = y + yCutoffGuest + mTopOffset + mCenterYOffset;
1010#endif
1011 dstRect.w = w;
1012 dstRect.h = RT_MAX(0, h - yCutoffGuest);
1013
1014 /*
1015 * Now we just blit
1016 */
1017 SDL_BlitSurface(mSurfVRAM, &srcRect, mScreen, &dstRect);
1018 /* hardware surfaces don't need update notifications */
1019#if defined(VBOX_WITH_SDL13)
1020 AssertRelease(mScreen->flags & SDL_PREALLOC);
1021 SDL_SelectRenderer(mWindow);
1022 SDL_DirtyTexture(mTexture, 1, &dstRect);
1023 AssertRelease(mRenderInfo.flags & SDL_RENDERER_PRESENTCOPY);
1024 SDL_RenderCopy(mTexture, &dstRect, &dstRect);
1025 SDL_RenderPresent();
1026#else
1027 if ((mScreen->flags & SDL_HWSURFACE) == 0)
1028 SDL_UpdateRect(mScreen, dstRect.x, dstRect.y, dstRect.w, dstRect.h);
1029#endif
1030
1031#ifdef VBOX_SECURELABEL
1032 if (fPaintLabel)
1033 paintSecureLabel(0, 0, 0, 0, false);
1034#endif
1035 RTCritSectLeave(&mUpdateLock);
1036}
1037
1038/**
1039 * Repaint the whole framebuffer
1040 *
1041 * @remarks Must be called from the SDL thread!
1042 */
1043void VBoxSDLFB::repaint()
1044{
1045 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1046 LogFlow(("VBoxSDLFB::repaint\n"));
1047 update(0, 0, mScreen->w, mScreen->h, false /* fGuestRelative */);
1048}
1049
1050/**
1051 * Toggle fullscreen mode
1052 *
1053 * @remarks Must be called from the SDL thread!
1054 */
1055void VBoxSDLFB::setFullscreen(bool fFullscreen)
1056{
1057 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1058 LogFlow(("VBoxSDLFB::SetFullscreen: fullscreen: %d\n", fFullscreen));
1059 mfFullscreen = fFullscreen;
1060 /* only change the SDL resolution, do not touch the guest framebuffer */
1061 resizeSDL();
1062 repaint();
1063}
1064
1065/**
1066 * Return the geometry of the host. This isn't very well tested but it seems
1067 * to work at least on Linux hosts.
1068 */
1069void VBoxSDLFB::getFullscreenGeometry(uint32_t *width, uint32_t *height)
1070{
1071 SDL_Rect **modes;
1072
1073 /* Get available fullscreen/hardware modes */
1074 modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
1075 Assert(modes != NULL);
1076 /* -1 means that any mode is possible (usually non fullscreen) */
1077 if (modes != (SDL_Rect **)-1)
1078 {
1079 /*
1080 * According to the SDL documentation, the API guarantees that the modes
1081 * are sorted from larger to smaller, so we just take the first entry as
1082 * the maximum.
1083 *
1084 * XXX Crude Xinerama hack :-/
1085 */
1086 if ( modes[0]->w > (16*modes[0]->h/9)
1087 && modes[1]
1088 && modes[1]->h == modes[0]->h)
1089 {
1090 *width = modes[1]->w;
1091 *height = modes[1]->h;
1092 }
1093 else
1094 {
1095 *width = modes[0]->w;
1096 *height = modes[0]->w;
1097 }
1098 }
1099}
1100
1101#ifdef VBOX_SECURELABEL
1102/**
1103 * Setup the secure labeling parameters
1104 *
1105 * @returns VBox status code
1106 * @param height height of the secure label area in pixels
1107 * @param font file path fo the TrueType font file
1108 * @param pointsize font size in points
1109 */
1110int VBoxSDLFB::initSecureLabel(uint32_t height, char *font, uint32_t pointsize, uint32_t labeloffs)
1111{
1112 LogFlow(("VBoxSDLFB:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
1113 height, font, pointsize));
1114 mLabelHeight = height;
1115 mLabelOffs = labeloffs;
1116 Assert(font);
1117 pTTF_Init();
1118 mLabelFont = pTTF_OpenFont(font, pointsize);
1119 if (!mLabelFont)
1120 {
1121 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
1122 return VERR_OPEN_FAILED;
1123 }
1124 mSecureLabelColorFG = 0x0000FF00;
1125 mSecureLabelColorBG = 0x00FFFF00;
1126 repaint();
1127 return VINF_SUCCESS;
1128}
1129
1130/**
1131 * Set the secure label text and repaint the label
1132 *
1133 * @param text UTF-8 string of new label
1134 * @remarks must be called from the SDL thread!
1135 */
1136void VBoxSDLFB::setSecureLabelText(const char *text)
1137{
1138 mSecureLabelText = text;
1139 paintSecureLabel(0, 0, 0, 0, true);
1140}
1141
1142/**
1143 * Sets the secure label background color.
1144 *
1145 * @param colorFG encoded RGB value for text
1146 * @param colorBG encored RGB value for background
1147 * @remarks must be called from the SDL thread!
1148 */
1149void VBoxSDLFB::setSecureLabelColor(uint32_t colorFG, uint32_t colorBG)
1150{
1151 mSecureLabelColorFG = colorFG;
1152 mSecureLabelColorBG = colorBG;
1153 paintSecureLabel(0, 0, 0, 0, true);
1154}
1155
1156/**
1157 * Paint the secure label if required
1158 *
1159 * @param fForce Force the repaint
1160 * @remarks must be called from the SDL thread!
1161 */
1162void VBoxSDLFB::paintSecureLabel(int x, int y, int w, int h, bool fForce)
1163{
1164#ifdef VBOXSDL_WITH_X11
1165 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1166#endif
1167 /* only when the function is present */
1168 if (!pTTF_RenderUTF8_Solid)
1169 return;
1170 /* check if we can skip the paint */
1171 if (!fForce && ((uint32_t)y > mLabelHeight))
1172 {
1173 return;
1174 }
1175 /* first fill the background */
1176 SDL_Rect rect = {0, 0, (Uint16)mScreen->w, (Uint16)mLabelHeight};
1177 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format,
1178 (mSecureLabelColorBG & 0x00FF0000) >> 16, /* red */
1179 (mSecureLabelColorBG & 0x0000FF00) >> 8, /* green */
1180 mSecureLabelColorBG & 0x000000FF)); /* blue */
1181
1182 /* now the text */
1183 if ( mLabelFont != NULL
1184 && !mSecureLabelText.isEmpty()
1185 )
1186 {
1187 SDL_Color clrFg = {(uint8_t)((mSecureLabelColorFG & 0x00FF0000) >> 16),
1188 (uint8_t)((mSecureLabelColorFG & 0x0000FF00) >> 8),
1189 (uint8_t)( mSecureLabelColorFG & 0x000000FF ), 0};
1190 SDL_Surface *sText = (pTTF_RenderUTF8_Blended != NULL)
1191 ? pTTF_RenderUTF8_Blended(mLabelFont, mSecureLabelText.c_str(), clrFg)
1192 : pTTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText.c_str(), clrFg);
1193 rect.x = 10;
1194 rect.y = mLabelOffs;
1195 SDL_BlitSurface(sText, NULL, mScreen, &rect);
1196 SDL_FreeSurface(sText);
1197 }
1198 /* make sure to update the screen */
1199 SDL_UpdateRect(mScreen, 0, 0, mScreen->w, mLabelHeight);
1200}
1201#endif /* VBOX_SECURELABEL */
1202
1203// IFramebufferOverlay
1204///////////////////////////////////////////////////////////////////////////////////
1205
1206/**
1207 * Constructor for the VBoxSDLFBOverlay class (IFramebufferOverlay implementation)
1208 *
1209 * @param x Initial X offset for the overlay
1210 * @param y Initial Y offset for the overlay
1211 * @param width Initial width for the overlay
1212 * @param height Initial height for the overlay
1213 * @param visible Whether the overlay is initially visible
1214 * @param alpha Initial alpha channel value for the overlay
1215 */
1216VBoxSDLFBOverlay::VBoxSDLFBOverlay(ULONG x, ULONG y, ULONG width, ULONG height,
1217 BOOL visible, VBoxSDLFB *aParent) :
1218 mOverlayX(x), mOverlayY(y), mOverlayWidth(width),
1219 mOverlayHeight(height), mOverlayVisible(visible),
1220 mParent(aParent)
1221{}
1222
1223/**
1224 * Destructor for the VBoxSDLFBOverlay class.
1225 */
1226VBoxSDLFBOverlay::~VBoxSDLFBOverlay()
1227{
1228 SDL_FreeSurface(mBlendedBits);
1229 SDL_FreeSurface(mOverlayBits);
1230}
1231
1232/**
1233 * Perform any initialisation of the overlay that can potentially fail
1234 *
1235 * @returns S_OK on success or the reason for the failure
1236 */
1237HRESULT VBoxSDLFBOverlay::init()
1238{
1239 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1240 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1241 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1242 E_OUTOFMEMORY);
1243 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1244 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1245 0x000000ff, 0xff000000);
1246 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1247 E_OUTOFMEMORY);
1248 return S_OK;
1249}
1250
1251/**
1252 * Returns the current overlay X offset in pixels.
1253 *
1254 * @returns COM status code
1255 * @param x Address of result buffer.
1256 */
1257STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(X)(ULONG *x)
1258{
1259 LogFlow(("VBoxSDLFBOverlay::GetX\n"));
1260 if (!x)
1261 return E_INVALIDARG;
1262 *x = mOverlayX;
1263 return S_OK;
1264}
1265
1266/**
1267 * Returns the current overlay height in pixels.
1268 *
1269 * @returns COM status code
1270 * @param height Address of result buffer.
1271 */
1272STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Y)(ULONG *y)
1273{
1274 LogFlow(("VBoxSDLFBOverlay::GetY\n"));
1275 if (!y)
1276 return E_INVALIDARG;
1277 *y = mOverlayY;
1278 return S_OK;
1279}
1280
1281/**
1282 * Returns the current overlay width in pixels. In fact, this returns the line size.
1283 *
1284 * @returns COM status code
1285 * @param width Address of result buffer.
1286 */
1287STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Width)(ULONG *width)
1288{
1289 LogFlow(("VBoxSDLFBOverlay::GetWidth\n"));
1290 if (!width)
1291 return E_INVALIDARG;
1292 *width = mOverlayBits->pitch;
1293 return S_OK;
1294}
1295
1296/**
1297 * Returns the current overlay line size in pixels.
1298 *
1299 * @returns COM status code
1300 * @param lineSize Address of result buffer.
1301 */
1302STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
1303{
1304 LogFlow(("VBoxSDLFBOverlay::GetBytesPerLine\n"));
1305 if (!bytesPerLine)
1306 return E_INVALIDARG;
1307 *bytesPerLine = mOverlayBits->pitch;
1308 return S_OK;
1309}
1310
1311/**
1312 * Returns the current overlay height in pixels.
1313 *
1314 * @returns COM status code
1315 * @param height Address of result buffer.
1316 */
1317STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Height)(ULONG *height)
1318{
1319 LogFlow(("VBoxSDLFBOverlay::GetHeight\n"));
1320 if (!height)
1321 return E_INVALIDARG;
1322 *height = mOverlayHeight;
1323 return S_OK;
1324}
1325
1326/**
1327 * Returns whether the overlay is currently visible.
1328 *
1329 * @returns COM status code
1330 * @param visible Address of result buffer.
1331 */
1332STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Visible)(BOOL *visible)
1333{
1334 LogFlow(("VBoxSDLFBOverlay::GetVisible\n"));
1335 if (!visible)
1336 return E_INVALIDARG;
1337 *visible = mOverlayVisible;
1338 return S_OK;
1339}
1340
1341/**
1342 * Sets whether the overlay is currently visible.
1343 *
1344 * @returns COM status code
1345 * @param visible New value.
1346 */
1347STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Visible)(BOOL visible)
1348{
1349 LogFlow(("VBoxSDLFBOverlay::SetVisible\n"));
1350 mOverlayVisible = visible;
1351 return S_OK;
1352}
1353
1354/**
1355 * Returns the value of the global alpha channel.
1356 *
1357 * @returns COM status code
1358 * @param alpha Address of result buffer.
1359 */
1360STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Alpha)(ULONG *alpha)
1361{
1362 LogFlow(("VBoxSDLFBOverlay::GetAlpha\n"));
1363 return E_NOTIMPL;
1364}
1365
1366/**
1367 * Sets whether the overlay is currently visible.
1368 *
1369 * @returns COM status code
1370 * @param alpha new value.
1371 */
1372STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Alpha)(ULONG alpha)
1373{
1374 LogFlow(("VBoxSDLFBOverlay::SetAlpha\n"));
1375 return E_NOTIMPL;
1376}
1377
1378/**
1379 * Returns the address of the framebuffer bits for writing to.
1380 *
1381 * @returns COM status code
1382 * @param alpha Address of result buffer.
1383 */
1384STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Address)(ULONG *address)
1385{
1386 LogFlow(("VBoxSDLFBOverlay::GetAddress\n"));
1387 if (!address)
1388 return E_INVALIDARG;
1389 *address = (uintptr_t) mOverlayBits->pixels;
1390 return S_OK;
1391}
1392
1393/**
1394 * Returns the current colour depth. In fact, this is always 32bpp.
1395 *
1396 * @returns COM status code
1397 * @param bitsPerPixel Address of result buffer.
1398 */
1399STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
1400{
1401 LogFlow(("VBoxSDLFBOverlay::GetBitsPerPixel\n"));
1402 if (!bitsPerPixel)
1403 return E_INVALIDARG;
1404 *bitsPerPixel = 32;
1405 return S_OK;
1406}
1407
1408/**
1409 * Returns the current pixel format. In fact, this is always RGB.
1410 *
1411 * @returns COM status code
1412 * @param pixelFormat Address of result buffer.
1413 */
1414STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(PixelFormat)(ULONG *pixelFormat)
1415{
1416 LogFlow(("VBoxSDLFBOverlay::GetPixelFormat\n"));
1417 if (!pixelFormat)
1418 return E_INVALIDARG;
1419 *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
1420 return S_OK;
1421}
1422
1423/**
1424 * Returns whether the guest VRAM is used directly. In fact, this is always FALSE.
1425 *
1426 * @returns COM status code
1427 * @param usesGuestVRAM Address of result buffer.
1428 */
1429STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(UsesGuestVRAM)(BOOL *usesGuestVRAM)
1430{
1431 LogFlow(("VBoxSDLFBOverlay::GetUsesGuestVRAM\n"));
1432 if (!usesGuestVRAM)
1433 return E_INVALIDARG;
1434 *usesGuestVRAM = FALSE;
1435 return S_OK;
1436}
1437
1438/**
1439 * Returns the height reduction. In fact, this is always 0.
1440 *
1441 * @returns COM status code
1442 * @param heightReduction Address of result buffer.
1443 */
1444STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(HeightReduction)(ULONG *heightReduction)
1445{
1446 LogFlow(("VBoxSDLFBOverlay::GetHeightReduction\n"));
1447 if (!heightReduction)
1448 return E_INVALIDARG;
1449 *heightReduction = 0;
1450 return S_OK;
1451}
1452
1453/**
1454 * Returns the overlay for this framebuffer. Obviously, we return NULL here.
1455 *
1456 * @returns COM status code
1457 * @param overlay Address of result buffer.
1458 */
1459STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
1460{
1461 LogFlow(("VBoxSDLFBOverlay::GetOverlay\n"));
1462 if (!aOverlay)
1463 return E_INVALIDARG;
1464 *aOverlay = 0;
1465 return S_OK;
1466}
1467
1468/**
1469 * Returns associated window handle. We return NULL here.
1470 *
1471 * @returns COM status code
1472 * @param winId Address of result buffer.
1473 */
1474STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(WinId)(LONG64 *winId)
1475{
1476 LogFlow(("VBoxSDLFBOverlay::GetWinId\n"));
1477 if (!winId)
1478 return E_INVALIDARG;
1479 *winId = 0;
1480 return S_OK;
1481}
1482
1483
1484/**
1485 * Lock the overlay. This should not be used - lock the parent IFramebuffer instead.
1486 *
1487 * @returns COM status code
1488 */
1489STDMETHODIMP VBoxSDLFBOverlay::Lock()
1490{
1491 LogFlow(("VBoxSDLFBOverlay::Lock\n"));
1492 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1493 "lock the parent IFramebuffer object instead.\n"));
1494 return E_NOTIMPL;
1495}
1496
1497/**
1498 * Unlock the overlay.
1499 *
1500 * @returns COM status code
1501 */
1502STDMETHODIMP VBoxSDLFBOverlay::Unlock()
1503{
1504 LogFlow(("VBoxSDLFBOverlay::Unlock\n"));
1505 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1506 "lock the parent IFramebuffer object instead.\n"));
1507 return E_NOTIMPL;
1508}
1509
1510/**
1511 * Change the X and Y co-ordinates of the overlay area.
1512 *
1513 * @returns COM status code
1514 * @param x New X co-ordinate.
1515 * @param y New Y co-ordinate.
1516 */
1517STDMETHODIMP VBoxSDLFBOverlay::Move(ULONG x, ULONG y)
1518{
1519 mOverlayX = x;
1520 mOverlayY = y;
1521 return S_OK;
1522}
1523
1524/**
1525 * Notify the overlay that a section of the framebuffer has been redrawn.
1526 *
1527 * @returns COM status code
1528 * @param x X co-ordinate of upper left corner of modified area.
1529 * @param y Y co-ordinate of upper left corner of modified area.
1530 * @param w Width of modified area.
1531 * @param h Height of modified area.
1532 * @retval finished Set if the operation has completed.
1533 *
1534 * All we do here is to send a request to the parent to update the affected area,
1535 * translating between our co-ordinate system and the parent's. It would be have
1536 * been better to call the parent directly, but such is life. We leave bounds
1537 * checking to the parent.
1538 */
1539STDMETHODIMP VBoxSDLFBOverlay::NotifyUpdate(ULONG x, ULONG y,
1540 ULONG w, ULONG h)
1541{
1542 return mParent->NotifyUpdate(x + mOverlayX, y + mOverlayY, w, h);
1543}
1544
1545/**
1546 * Change the dimensions of the overlay.
1547 *
1548 * @returns COM status code
1549 * @param pixelFormat Must be FramebufferPixelFormat_PixelFormatRGB32.
1550 * @param vram Must be NULL.
1551 * @param lineSize Ignored.
1552 * @param w New overlay width.
1553 * @param h New overlay height.
1554 * @retval finished Set if the operation has completed.
1555 */
1556STDMETHODIMP VBoxSDLFBOverlay::RequestResize(ULONG aScreenId, ULONG pixelFormat, ULONG vram,
1557 ULONG bitsPerPixel, ULONG bytesPerLine,
1558 ULONG w, ULONG h, BOOL *finished)
1559{
1560 AssertReturn(pixelFormat == FramebufferPixelFormat_FOURCC_RGB, E_INVALIDARG);
1561 AssertReturn(vram == 0, E_INVALIDARG);
1562 AssertReturn(bitsPerPixel == 32, E_INVALIDARG);
1563 mOverlayWidth = w;
1564 mOverlayHeight = h;
1565 SDL_FreeSurface(mOverlayBits);
1566 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1567 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1568 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1569 E_OUTOFMEMORY);
1570 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1571 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1572 0x000000ff, 0xff000000);
1573 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1574 E_OUTOFMEMORY);
1575 return S_OK;
1576}
1577
1578/**
1579 * Returns whether we like the given video mode.
1580 *
1581 * @returns COM status code
1582 * @param width video mode width in pixels
1583 * @param height video mode height in pixels
1584 * @param bpp video mode bit depth in bits per pixel
1585 * @retval supported pointer to result variable
1586 *
1587 * Basically, we support anything with 32bpp.
1588 */
1589STDMETHODIMP VBoxSDLFBOverlay::VideoModeSupported(ULONG width, ULONG height, ULONG bpp,
1590 BOOL *supported)
1591{
1592 if (!supported)
1593 return E_POINTER;
1594 if (bpp == 32)
1595 *supported = true;
1596 else
1597 *supported = false;
1598 return S_OK;
1599}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette