VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBufferDirectDraw.cpp@ 35740

Last change on this file since 35740 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: UIFrameBufferDirectDraw.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 *
4 * VBox frontends: Qt GUI ("VirtualBox"):
5 * DDRAW framebuffer implementation
6 */
7
8/*
9 * Copyright (C) 2006-2007 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#ifdef VBOX_GUI_USE_DDRAW
21
22#ifdef VBOX_WITH_PRECOMPILED_HEADERS
23# include "precomp.h"
24#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
25
26/* Local includes */
27# include "UIFrameBufferDirectDraw.h"
28# include "UIMachineView.h"
29
30# include <iprt/param.h>
31# include <iprt/alloc.h>
32
33/* Global includes */
34# include <QApplication>
35
36#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
37
38#define LOGDDRAW Log
39
40// TODO_NEW_CORE
41#if 0
42/* @todo
43 * - when paused in Guest VRAM mode after pause the screen is dimmed. because VRAM is dimmed.
44 * - when GUI window is resized, somehow take this into account, blit only visible parts.
45 */
46
47/*
48 * Helpers.
49 */
50static LPDIRECTDRAW7 getDDRAW (void)
51{
52 LPDIRECTDRAW7 pDDRAW = NULL;
53 LPDIRECTDRAW iface = NULL;
54
55 HRESULT rc = DirectDrawCreate (NULL, &iface, NULL);
56
57 if (rc != DD_OK)
58 {
59 LOGDDRAW(("DDRAW: Could not create DirectDraw interface rc= 0x%08X\n", rc));
60 }
61 else
62 {
63 rc = iface->QueryInterface (IID_IDirectDraw7, (void**)&pDDRAW);
64
65 if (rc != DD_OK)
66 {
67 LOGDDRAW(("DDRAW: Could not query DirectDraw 7 interface rc = 0x%08X\n", rc));
68 }
69 else
70 {
71 rc = pDDRAW->SetCooperativeLevel (NULL, DDSCL_NORMAL);
72
73 if (rc != DD_OK)
74 {
75 LOGDDRAW(("DDRAW: Could not set the DirectDraw cooperative level rc = 0x%08X\n", rc));
76 pDDRAW->Release ();
77 }
78 }
79
80 iface->Release();
81 }
82
83 return rc == DD_OK? pDDRAW: NULL;
84}
85
86static LPDIRECTDRAWSURFACE7 createPrimarySurface (LPDIRECTDRAW7 pDDRAW)
87{
88 LPDIRECTDRAWSURFACE7 pPrimarySurface = NULL;
89
90 DDSURFACEDESC2 sd;
91 memset (&sd, 0, sizeof (sd));
92 sd.dwSize = sizeof (sd);
93 sd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
94 sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
95 sd.dwBackBufferCount = 0;
96
97 HRESULT rc = pDDRAW->CreateSurface (&sd, &pPrimarySurface, NULL);
98
99 if (rc != DD_OK)
100 {
101 LOGDDRAW(("DDRAW: Could not create primary DirectDraw surface rc = 0x%08X\n", rc));
102 }
103
104 return rc == DD_OK? pPrimarySurface: NULL;
105}
106
107static LPDIRECTDRAWCLIPPER createClipper (LPDIRECTDRAW7 pDDRAW, HWND hwnd)
108{
109 LPDIRECTDRAWCLIPPER pClipper = NULL;
110
111 HRESULT rc = pDDRAW->CreateClipper (0, &pClipper, NULL);
112
113 if (rc != DD_OK)
114 {
115 LOGDDRAW(("DDRAW: Could not create DirectDraw clipper rc = 0x%08X\n", rc));
116 }
117 else
118 {
119 rc = pClipper->SetHWnd (0, hwnd);
120
121 if (rc != DD_OK)
122 {
123 LOGDDRAW(("DDRAW: Could not set the HWND on clipper rc = 0x%08X\n", rc));
124 pClipper->Release ();
125 }
126 }
127
128 return rc == DD_OK? pClipper: NULL;
129}
130
131//
132// VBoxDDRAWFrameBuffer class
133/////////////////////////////////////////////////////////////////////////////
134
135/** @class VBoxDDRAWFrameBuffer
136 *
137 * The VBoxDDRAWFrameBuffer class is a class that implements the IFrameBuffer
138 * interface and uses Win32 DirectDraw to store and render VM display data.
139 */
140
141VBoxDDRAWFrameBuffer::VBoxDDRAWFrameBuffer (VBoxConsoleView *aView) :
142 VBoxFrameBuffer (aView),
143 mDDRAW (NULL),
144 mClipper (NULL),
145 mSurface (NULL),
146 mPrimarySurface (NULL),
147 mPixelFormat (FramebufferPixelFormat_FOURCC_RGB),
148 mUsesGuestVRAM (false),
149 mWndX (0),
150 mWndY (0),
151 mSynchronousUpdates (true)
152{
153 memset (&mSurfaceDesc, 0, sizeof (mSurfaceDesc));
154
155 LOGDDRAW (("DDRAW: Creating\n"));
156
157 /* Release all created objects if something will go wrong. */
158 BOOL bReleaseObjects = TRUE;
159
160 mDDRAW = getDDRAW ();
161
162 if (mDDRAW)
163 {
164 mClipper = createClipper (mDDRAW, mView->viewport()->winId());
165
166 if (mClipper)
167 {
168 mPrimarySurface = createPrimarySurface (mDDRAW);
169
170 if (mPrimarySurface)
171 {
172 mPrimarySurface->SetClipper (mClipper);
173
174 VBoxResizeEvent *re =
175 new VBoxResizeEvent (FramebufferPixelFormat_Opaque,
176 NULL, 0, 0, 640, 480);
177
178 if (re)
179 {
180 resizeEvent (re);
181 delete re;
182
183 if (mSurface)
184 {
185 /* Everything was initialized. */
186 bReleaseObjects = FALSE;
187 }
188 }
189 }
190 }
191 }
192
193 if (bReleaseObjects)
194 {
195 releaseObjects();
196 }
197}
198
199VBoxDDRAWFrameBuffer::~VBoxDDRAWFrameBuffer()
200{
201 releaseObjects();
202}
203
204void VBoxDDRAWFrameBuffer::releaseObjects()
205{
206 deleteSurface ();
207
208 if (mPrimarySurface)
209 {
210 if (mClipper)
211 {
212 mPrimarySurface->SetClipper (NULL);
213 }
214
215 mPrimarySurface->Release ();
216 mPrimarySurface = NULL;
217 }
218
219 if (mClipper)
220 {
221 mClipper->Release();
222 mClipper = NULL;
223 }
224
225 if (mDDRAW)
226 {
227 mDDRAW->Release();
228 mDDRAW = NULL;
229 }
230}
231
232/** @note This method is called on EMT from under this object's lock */
233STDMETHODIMP VBoxDDRAWFrameBuffer::NotifyUpdate (ULONG aX, ULONG aY,
234 ULONG aW, ULONG aH)
235{
236 LOGDDRAW(("DDRAW: NotifyUpdate %d,%d %dx%d\n", aX, aY, aW, aH));
237
238 if (mSynchronousUpdates)
239 {
240//#warning check me!
241 mView->viewport()->update (aX, aY, aW, aH);
242 }
243 else
244 {
245 drawRect (aX, aY, aW, aH);
246 }
247
248 return S_OK;
249}
250
251void VBoxDDRAWFrameBuffer::paintEvent (QPaintEvent *pe)
252{
253 LOGDDRAW (("DDRAW: paintEvent %d,%d %dx%d\n",
254 pe->rect().x(), pe->rect().y(),
255 pe->rect().width(), pe->rect().height()));
256
257 drawRect (pe->rect().x(), pe->rect().y(),
258 pe->rect().width(), pe->rect().height());
259}
260
261void VBoxDDRAWFrameBuffer::resizeEvent (VBoxResizeEvent *re)
262{
263 LOGDDRAW (("DDRAW: resizeEvent %d, %p, %d %d %dx%d\n",
264 re->pixelFormat(), re->VRAM(), re->bitsPerPixel(),
265 re->bytesPerLine(), re->width(), re->height()));
266
267 VBoxFrameBuffer::resizeEvent (re);
268
269 bool ok = createSurface (re->pixelFormat(), re->VRAM (), re->bitsPerPixel(),
270 re->bytesPerLine (), re->width(), re->height());
271 if (!ok && re->pixelFormat() != FramebufferPixelFormat_Opaque)
272 {
273 /* try to create a fallback surface with indirect buffer
274 * (only if haven't done so already) */
275 ok = createSurface (FramebufferPixelFormat_Opaque,
276 NULL, 0, 0, re->width(), re->height());
277 }
278
279 Assert (ok);
280
281 getWindowPosition();
282
283//#warning: port me
284// mView->setBackgroundMode (Qt::NoBackground);
285}
286
287void VBoxDDRAWFrameBuffer::moveEvent (QMoveEvent *me)
288{
289 getWindowPosition();
290}
291
292/*
293 * Private methods.
294 */
295
296/**
297 * Creates a new surface in the requested format.
298 * On success, returns @c true and assigns the created surface to mSurface
299 * and its definition to mSurfaceDesc. On failure, returns @c false.
300 *
301 * If @a aPixelFormat is other than FramebufferPixelFormat_Opaque,
302 * then the method will attempt to attach @a aVRAM directly to the created
303 * surface. If this fails, the caller may call this method again with
304 * @a aPixelFormat set to FramebufferPixelFormat_Opaque to try
305 * setting up an indirect fallback buffer for the surface. This opeartion may
306 * theoretically also fail.
307 *
308 * @note Deletes the existing surface before attempting to create a new one.
309 */
310bool VBoxDDRAWFrameBuffer::createSurface (ULONG aPixelFormat, uchar *aVRAM,
311 ULONG aBitsPerPixel, ULONG aBytesPerLine,
312 ULONG aWidth, ULONG aHeight)
313{
314 deleteSurface();
315
316 DDSURFACEDESC2 sd;
317
318 /* Prepare the surface description structure. */
319 memset (&sd, 0, sizeof (sd));
320
321 sd.dwSize = sizeof (sd);
322 sd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH |
323 DDSD_LPSURFACE | DDSD_PITCH | DDSD_PIXELFORMAT;
324
325 sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
326 sd.dwWidth = aWidth;
327 sd.dwHeight = aHeight;
328
329 /* Setup the desired pixel format on the surface. */
330
331 sd.ddpfPixelFormat.dwSize = sizeof (sd.ddpfPixelFormat);
332 sd.ddpfPixelFormat.dwFlags = DDPF_RGB;
333
334 if (aPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
335 {
336 /* Try to use the guest VRAM directly */
337
338 switch (aBitsPerPixel)
339 {
340 case 32:
341 sd.ddpfPixelFormat.dwRGBBitCount = 32;
342 sd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
343 sd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
344 sd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
345 break;
346 case 24:
347 sd.ddpfPixelFormat.dwRGBBitCount = 24;
348 sd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
349 sd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
350 sd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
351 break;
352 case 16:
353 sd.ddpfPixelFormat.dwRGBBitCount = 16;
354 sd.ddpfPixelFormat.dwRBitMask = 0xF800;
355 sd.ddpfPixelFormat.dwGBitMask = 0x07E0;
356 sd.ddpfPixelFormat.dwBBitMask = 0x001F;
357 break;
358 default:
359 /* we don't directly support any other color depth */
360 return false;
361 }
362
363 sd.lPitch = (LONG) aBytesPerLine;
364
365 sd.lpSurface = aVRAM;
366 mUsesGuestVRAM = true;
367
368 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
369 }
370 else
371 if (aPixelFormat != FramebufferPixelFormat_Opaque)
372 {
373 /* we don't directly support any other pixel format */
374 return false;
375 }
376 else
377 {
378 /* for the Opaque format, we use the indirect memory buffer as a
379 * 32 bpp surface. */
380
381 sd.ddpfPixelFormat.dwRGBBitCount = 32;
382 sd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
383 sd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
384 sd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
385
386 sd.lPitch = sd.dwWidth * 4;
387
388 /* Allocate the memory buffer for the surface */
389 sd.lpSurface = RTMemAlloc (sd.lPitch * sd.dwHeight);
390 if (sd.lpSurface == NULL)
391 {
392 LOGDDRAW (("DDRAW: could not allocate memory for surface.\n"));
393 return false;
394 }
395 mUsesGuestVRAM = false;
396
397 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
398 }
399
400 /* create the surface */
401 HRESULT rc = mDDRAW->CreateSurface (&sd, &mSurface, NULL);
402
403 if (rc != DD_OK)
404 {
405 LOGDDRAW (("DDRAW: Could not create DirectDraw surface, rc=0x%08X\n", rc));
406 deleteSurface();
407 return false;
408 }
409
410 /* Initialize the surface description member. It will be used to obtain
411 * address, bpp and bpl. */
412 mSurfaceDesc = sd;
413
414 LOGDDRAW(("DDRAW: Created %s surface: format = %d, address = %p\n",
415 mUsesGuestVRAM ? "GuestVRAM": "system memory",
416 aPixelFormat, address ()));
417
418 if (!mUsesGuestVRAM)
419 {
420 /* Clear just created surface. */
421 memset (address(), 0, bytesPerLine() * height());
422 }
423
424 return true;
425}
426
427void VBoxDDRAWFrameBuffer::deleteSurface ()
428{
429 if (mSurface)
430 {
431 mSurface->Release ();
432 mSurface = NULL;
433
434 if (!mUsesGuestVRAM)
435 {
436 RTMemFree (mSurfaceDesc.lpSurface);
437 }
438
439 memset (&mSurfaceDesc, '\0', sizeof (mSurfaceDesc));
440 mUsesGuestVRAM = false;
441 }
442}
443
444/**
445 * Draws a rectangular area of guest screen DDRAW surface onto the
446 * host screen primary surface.
447 */
448void VBoxDDRAWFrameBuffer::drawRect (ULONG x, ULONG y, ULONG w, ULONG h)
449{
450 LOGDDRAW (("DDRAW: drawRect: %d,%d, %dx%d\n", x, y, w, h));
451
452 if (mSurface && w > 0 && h > 0)
453 {
454 RECT rectSrc;
455 RECT rectDst;
456
457 rectSrc.left = x;
458 rectSrc.right = x + w;
459 rectSrc.top = y;
460 rectSrc.bottom = y + h;
461
462 rectDst.left = mWndX + x;
463 rectDst.right = rectDst.left + w;
464 rectDst.top = mWndY + y;
465 rectDst.bottom = rectDst.top + h;
466
467 /* DDBLT_ASYNC performs this blit asynchronously through the
468 * first in, first out (FIFO) hardware in the order received.
469 * If no room is available in the FIFO hardware, the call fails.
470 * DDBLT_WAIT waits if blitter is busy, and returns as soon as the
471 * blit can be set up or another error occurs.
472 *
473 * I assume that DDBLT_WAIT will also wait for a room in the FIFO.
474 */
475 HRESULT rc = mPrimarySurface->Blt (&rectDst, mSurface, &rectSrc, DDBLT_ASYNC | DDBLT_WAIT, NULL);
476
477 if (rc != DD_OK)
478 {
479 /* Repeat without DDBLT_ASYNC. */
480 LOGDDRAW(("DDRAW: drawRect: async blit failed rc = 0x%08X\n", rc));
481 rc = mPrimarySurface->Blt (&rectDst, mSurface, &rectSrc, DDBLT_WAIT, NULL);
482
483 if (rc != DD_OK)
484 {
485 LOGDDRAW(("DDRAW: drawRect: sync blit failed rc = 0x%08X\n", rc));
486 }
487 }
488 }
489
490 return;
491}
492
493void VBoxDDRAWFrameBuffer::getWindowPosition (void)
494{
495// if (mPrimarySurface)
496// {
497// /* Lock surface to synchronize with Blt in drawRect. */
498// DDSURFACEDESC2 sd;
499// memset (&sd, 0, sizeof (sd));
500// sd.dwSize = sizeof (sd);
501//
502// HRESULT rc = mPrimarySurface->Lock (NULL, &sd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
503// LOGDDRAW(("DDRAW: getWindowPosition rc = 0x%08X\n", rc));
504// }
505
506 RECT rect;
507 GetWindowRect (mView->viewport()->winId(), &rect);
508 mWndX = rect.left;
509 mWndY = rect.top;
510
511// if (mPrimarySurface)
512// {
513// mPrimarySurface->Unlock (NULL);
514// }
515}
516
517#endif
518
519#endif /* VBOX_GUI_USE_DDRAW */
520
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use