VirtualBox

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

Last change on this file since 10557 was 10501, checked in by vboxsync, 17 years ago

FE/SDL: added (undocumented) -pidfile parameter

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

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