VirtualBox

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

Last change on this file since 3571 was 3571, checked in by vboxsync, 18 years ago

Added framebuffer property RenderMode.

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