VirtualBox

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

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

Main,Frontends: IFramebuffer::NotifyUpdateImage

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