VirtualBox

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

Last change on this file since 51670 was 51670, checked in by vboxsync, 10 years ago

Main,Frontends: use safearray for IFramebuffer::Notify3DEvent

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