VirtualBox

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

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

Main,Frontends: IDisplay provides the guest screen bitmap to frontends.

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

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