VirtualBox

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

Last change on this file since 11400 was 11400, checked in by vboxsync, 16 years ago

VBoxSDL: improve fullscreenresize hack a little bit

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