merge the formfield patch from ooo-build
[ooovba.git] / canvas / source / directx / dx_5rm.cxx
blob3e9388759d9dba669f9625a61ea4222819bd61cc
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dx_5rm.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #if DIRECTX_VERSION < 0x0900
36 // Nvidia GeForce Go 6800 crashes with a bluescreen if we take the
37 // maximum texture size, which would be twice as large. this behaviors
38 // has only been observed on directx5.
39 // This value is simply the maximum size for textures we request from
40 // the system, it has absolutely nothing to do with the size of primitives
41 // we're able to render, both concepts are totally independent from each other.
42 #define MAX_TEXTURE_SIZE (2048)
43 #define MIN_TEXTURE_SIZE (32)
44 //#define FAKE_MAX_NUMBER_TEXTURES (2)
45 //#define FAKE_MAX_TEXTURE_SIZE (512)
47 //////////////////////////////////////////////////////////////////////////////////
48 // includes
49 //////////////////////////////////////////////////////////////////////////////////
50 #include <vcl/syschild.hxx>
51 #include <vcl/window.hxx>
52 #include <canvas/debug.hxx>
53 #include <canvas/verbosetrace.hxx>
54 #include <canvas/elapsedtime.hxx>
55 #include <canvas/canvastools.hxx>
56 #include <canvas/rendering/icolorbuffer.hxx>
57 #include <canvas/rendering/isurface.hxx>
58 #include <canvas/rendering/irendermodule.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <basegfx/numeric/ftools.hxx>
61 #include <basegfx/vector/b2dsize.hxx>
62 #include <basegfx/vector/b2isize.hxx>
63 #include <basegfx/point/b2ipoint.hxx>
64 #include <basegfx/range/b2irectangle.hxx>
65 #include <boost/scoped_ptr.hpp>
66 #include <com/sun/star/lang/NoSupportException.hpp>
68 #define COMPILE_MULTIMON_STUBS
70 #include "dx_rendermodule.hxx"
71 #include "dx_surfacegraphics.hxx"
72 #include <vcl/sysdata.hxx>
74 #undef WB_LEFT
75 #undef WB_RIGHT
77 #include "dx_impltools.hxx"
78 #include <malloc.h>
80 #if defined(DX_DEBUG_IMAGES)
81 # if OSL_DEBUG_LEVEL > 0
82 # include <imdebug.h>
83 # undef min
84 # undef max
85 # endif
86 #endif
88 #undef COMPILE_MULTIMON_STUBS
90 #include <stdio.h>
92 #define MONITOR_DEFAULTTONULL 0x00000000
93 #define MONITOR_DEFAULTTOPRIMARY 0x00000001
94 #define MONITOR_DEFAULTTONEAREST 0x00000002
96 using namespace ::com::sun::star;
98 //////////////////////////////////////////////////////////////////////////////////
99 // 'dxcanvas' namespace
100 //////////////////////////////////////////////////////////////////////////////////
102 namespace dxcanvas
104 namespace
106 bool doBlit( const ::basegfx::B2IPoint& rDestPos,
107 IDirectDrawSurface& rOutSurface,
108 const ::basegfx::B2IRange& rSourceArea,
109 IDirectDrawSurface& rSourceSurface,
110 DDBLTFX* pBltFx,
111 bool bForceSoftware )
113 if( !bForceSoftware )
115 // blit surface to backbuffer
116 RECT aOutRect =
118 rDestPos.getX(),
119 rDestPos.getY(),
120 rDestPos.getX() + static_cast<sal_Int32>(rSourceArea.getWidth()),
121 rDestPos.getY() + static_cast<sal_Int32>(rSourceArea.getHeight()),
123 RECT aSourceRect =
125 rSourceArea.getMinX(),
126 rSourceArea.getMinY(),
127 rSourceArea.getMaxX(),
128 rSourceArea.getMaxY()
131 if( SUCCEEDED(rOutSurface.Blt( &aOutRect,
132 &rSourceSurface,
133 &aSourceRect,
134 DDBLT_WAIT,
135 pBltFx )) )
137 return true;
141 // failed, or forced to use SW copy. attempt manual copy.
142 bool bResult = false;
144 // lock source surface
145 DDSURFACEDESC aDescSrc;
146 rtl_fillMemory(&aDescSrc,sizeof(DDSURFACEDESC),0);
147 aDescSrc.dwSize = sizeof(DDSURFACEDESC);
148 const DWORD dwSrcFlags = DDLOCK_NOSYSLOCK|
149 DDLOCK_SURFACEMEMORYPTR|
150 DDLOCK_WAIT|
151 DDLOCK_READONLY;
152 if(SUCCEEDED(rSourceSurface.Lock(NULL,
153 &aDescSrc,
154 dwSrcFlags,
155 NULL)))
157 // lock destination surface
158 DDSURFACEDESC aDescDst;
159 rtl_fillMemory(&aDescDst,sizeof(DDSURFACEDESC),0);
160 aDescDst.dwSize = sizeof(DDSURFACEDESC);
161 const DWORD dwDstFlags = DDLOCK_NOSYSLOCK|
162 DDLOCK_SURFACEMEMORYPTR|
163 DDLOCK_WAIT|
164 DDLOCK_WRITEONLY;
165 if(SUCCEEDED(rOutSurface.Lock(NULL,
166 &aDescDst,
167 dwDstFlags,
168 NULL)))
170 sal_uInt32 nSrcFormat;
171 nSrcFormat = ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
172 nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRBitMask)<<8;
173 nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwGBitMask)<<4;
174 nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwBBitMask);
176 sal_uInt32 nDstFormat;
177 nDstFormat = ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
178 nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRBitMask)<<8;
179 nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwGBitMask)<<4;
180 nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwBBitMask);
182 // TODO(E1): Use numeric_cast to catch overflow here
183 const sal_uInt32 nWidth( static_cast<sal_uInt32>(
184 rSourceArea.getWidth() ) );
185 const sal_uInt32 nHeight( static_cast<sal_uInt32>(
186 rSourceArea.getHeight() ) );
188 if((nSrcFormat == 0x8888) && (nDstFormat == 0x0565))
190 // medium range 8888 to 0565 pixel format conversion.
191 bResult = true;
192 sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
193 rSourceArea.getMinY()*aDescSrc.lPitch +
194 (rSourceArea.getMinX()<<2);
195 sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
196 rDestPos.getY()*aDescDst.lPitch +
197 (rDestPos.getX()<<1);
198 for(sal_uInt32 y=0; y<nHeight; ++y)
200 sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface;
201 sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
202 for(sal_uInt32 x=0; x<nWidth; ++x)
204 sal_uInt32 srcPixel = *pSrcScanline++;
205 sal_uInt16 dstPixel;
206 dstPixel = (sal_uInt16)((srcPixel & 0x0000F8) >> 3);
207 dstPixel |= (srcPixel & 0x00FC00) >> 5;
208 dstPixel |= (srcPixel & 0xF80000) >> 8;
209 *pDstScanline++ = dstPixel;
211 pSrcSurface += aDescSrc.lPitch;
212 pDstSurface += aDescDst.lPitch;
215 else if((nSrcFormat == 0x8888) && (nDstFormat == 0x0888))
217 // medium range 8888 to 0888 pixel format conversion.
218 bResult = true;
219 sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
220 rSourceArea.getMinY()*aDescSrc.lPitch +
221 (rSourceArea.getMinX()<<2);
222 sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
223 rDestPos.getY()*aDescDst.lPitch +
224 (rDestPos.getX()<<2);
225 for(sal_uInt32 y=0; y<nHeight; ++y)
227 sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface;
228 sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
229 for(sal_uInt32 x=0; x<nWidth; ++x)
231 *pDstScanline++ = (sal_uInt16)*pSrcScanline++;
233 pSrcSurface += aDescSrc.lPitch;
234 pDstSurface += aDescDst.lPitch;
237 else if((nSrcFormat == 0x8888) && (nDstFormat == 0x1555))
239 // medium range 8888 to 1555 pixel format conversion.
240 bResult = true;
241 sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
242 rSourceArea.getMinY()*aDescSrc.lPitch +
243 (rSourceArea.getMinX()<<2);
244 sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
245 rDestPos.getY()*aDescDst.lPitch +
246 (rDestPos.getX()<<1);
247 for(sal_uInt32 y=0; y<nHeight; ++y)
249 sal_uInt32 *pSrcScanline = (sal_uInt32*)pSrcSurface;
250 sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
251 for(sal_uInt32 x=0; x<nWidth; ++x)
253 sal_uInt32 srcPixel = *pSrcScanline++;
254 sal_uInt16 dstPixel;
255 dstPixel = (sal_uInt16)((srcPixel & 0x000000F8) >> 3);
256 dstPixel |= (srcPixel & 0x0000F800) >> 6;
257 dstPixel |= (srcPixel & 0x00F80000) >> 9;
258 dstPixel |= (srcPixel & 0x80000000) >> 16;
259 *pDstScanline++ = dstPixel;
261 pSrcSurface += aDescSrc.lPitch;
262 pDstSurface += aDescDst.lPitch;
266 // unlock destination surface
267 rOutSurface.Unlock(NULL);
270 // unlock source surface
271 rSourceSurface.Unlock(NULL);
274 return bResult;
277 void dumpSurface( const COMReference<IDirectDrawSurface> &pSurface, const char *szFilename )
279 if(!(pSurface.get()))
280 return;
282 DDSURFACEDESC aSurfaceDesc;
283 rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
284 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
286 if( FAILED(pSurface->Lock( NULL,
287 &aSurfaceDesc,
288 DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY,
289 NULL)) )
290 return;
292 const std::size_t dwBitmapSize(aSurfaceDesc.dwWidth*aSurfaceDesc.dwHeight*4);
293 sal_uInt8 *pBuffer = static_cast<sal_uInt8 *>(_alloca(dwBitmapSize));
294 if(pBuffer)
296 sal_uInt8 *pSource = reinterpret_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface);
297 sal_uInt8 *pDest = reinterpret_cast<sal_uInt8 *>(pBuffer);
298 const std::size_t dwDestPitch(aSurfaceDesc.dwWidth<<2);
299 pDest += aSurfaceDesc.dwHeight*dwDestPitch;
300 for(sal_uInt32 y=0; y<aSurfaceDesc.dwHeight; ++y)
302 pDest -= dwDestPitch;
303 rtl_copyMemory( pDest, pSource, dwDestPitch );
304 pSource += aSurfaceDesc.lPitch;
307 if(FILE *fp = fopen(szFilename,"wb"))
309 BITMAPINFOHEADER bitmapInfo;
311 bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
312 bitmapInfo.biWidth = aSurfaceDesc.dwWidth;
313 bitmapInfo.biHeight = aSurfaceDesc.dwHeight;
314 bitmapInfo.biPlanes = 1;
315 bitmapInfo.biBitCount = 32;
316 bitmapInfo.biCompression = BI_RGB;
317 bitmapInfo.biSizeImage = 0;
318 bitmapInfo.biXPelsPerMeter = 0;
319 bitmapInfo.biYPelsPerMeter = 0;
320 bitmapInfo.biClrUsed = 0;
321 bitmapInfo.biClrImportant = 0;
323 const std::size_t dwFileSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwBitmapSize);
325 BITMAPFILEHEADER header;
326 header.bfType = 'MB';
327 header.bfSize = dwFileSize;
328 header.bfReserved1 = 0;
329 header.bfReserved2 = 0;
330 header.bfOffBits = sizeof(BITMAPFILEHEADER) + bitmapInfo.biSize;
332 fwrite(&header,1,sizeof(BITMAPFILEHEADER),fp);
333 fwrite(&bitmapInfo,1,sizeof(BITMAPINFOHEADER),fp);
334 fwrite(pBuffer,1,dwBitmapSize,fp);
336 fclose(fp);
340 pSurface->Unlock(NULL);
343 void clearSurface( const COMReference<IDirectDrawSurface>& pSurface )
345 if(!(pSurface.is()))
346 return;
348 DDBLTFX aBltFx;
350 rtl_fillMemory( &aBltFx,
351 sizeof(DDBLTFX), 0 );
352 aBltFx.dwSize = sizeof(DDBLTFX);
353 aBltFx.dwFillColor = 0;
355 pSurface->Blt( NULL,
356 NULL,
357 NULL,
358 DDBLT_COLORFILL | DDBLT_WAIT,
359 &aBltFx );
362 // Define struct for MonitorEntry
363 struct MonitorEntry
365 GUID mnGUID;
366 HMONITOR mhMonitor;
367 MONITORINFO maMonitorInfo;
370 // define type for MonitorList
371 typedef ::std::vector< MonitorEntry > MonitorList;
373 // Win32 system callback for DirectDrawEnumerateExA call
374 BOOL WINAPI EnumerateExA_Callback( GUID FAR* lpGUID,
375 LPSTR /*lpDriverDescription*/,
376 LPSTR /*lpDriverName*/,
377 LPVOID lpContext,
378 HMONITOR hMonitor )
380 if(lpGUID)
382 MonitorList* pMonitorList = (MonitorList*)lpContext;
383 MonitorEntry aEntry;
385 aEntry.mnGUID = *lpGUID;
386 aEntry.mhMonitor = hMonitor;
387 aEntry.maMonitorInfo.cbSize = sizeof(MONITORINFO);
388 GetMonitorInfo( hMonitor,
389 &aEntry.maMonitorInfo );
391 pMonitorList->push_back(aEntry);
394 return DDENUMRET_OK;
397 void fillMonitorList( MonitorList& rMonitorList )
399 // Try to fill MonitorList. If neither lib or call to
400 // DirectDrawEnumerateExA does not exist, it's an old
401 // DX version (< 5.0), or system does not support
402 // multiple monitors.
403 HINSTANCE hInstance = LoadLibrary("ddraw.dll");
405 if(hInstance)
407 LPDIRECTDRAWENUMERATEEX lpDDEnumEx =
408 (LPDIRECTDRAWENUMERATEEX)GetProcAddress(hInstance,"DirectDrawEnumerateExA");
410 if(lpDDEnumEx)
411 lpDDEnumEx( (LPDDENUMCALLBACKEXA) EnumerateExA_Callback,
412 &rMonitorList,
413 DDENUM_ATTACHEDSECONDARYDEVICES );
415 FreeLibrary(hInstance);
419 IDirectDraw2* createDirectDraw( const MonitorList& rMonitorList,
420 MONITORINFO& rMonitorInfo,
421 HWND renderWindow )
423 GUID* gpSelectedDriverGUID = NULL;
425 // if we have multiple monitors, choose a gpSelectedDriverGUID from monitor list
426 HMONITOR hMonitor = MonitorFromWindow(renderWindow,
427 MONITOR_DEFAULTTONEAREST);
429 MonitorList::const_iterator aCurr = rMonitorList.begin();
430 const MonitorList::const_iterator aEnd = rMonitorList.end();
431 while( !gpSelectedDriverGUID && aCurr != aEnd )
433 if(hMonitor == aCurr->mhMonitor)
435 // This is the monitor we are running on
436 gpSelectedDriverGUID = const_cast<GUID*>(&aCurr->mnGUID);
437 rMonitorInfo = aCurr->maMonitorInfo;
440 ++aCurr;
443 IDirectDraw* pDirectDraw;
444 if( FAILED( DirectDrawCreate( gpSelectedDriverGUID, &pDirectDraw, NULL )))
445 return NULL;
447 IDirectDraw2* pDirectDraw2;
448 if( FAILED( pDirectDraw->QueryInterface( IID_IDirectDraw2, (LPVOID*)&pDirectDraw2 )))
449 return NULL;
451 // queryInterface bumped up the refcount, so release the
452 // reference to the original IDirectDraw interface.
453 pDirectDraw->Release();
455 return pDirectDraw2;
458 HRESULT WINAPI EnumTextureFormatsCallback( LPDDSURFACEDESC pSurfaceDesc,
459 LPVOID pContext )
461 // dirty cast of given context back to result ModeSelectContext
462 DDPIXELFORMAT* pResult = (DDPIXELFORMAT*)pContext;
464 if( pResult == NULL || pSurfaceDesc == NULL )
465 return DDENUMRET_CANCEL;
467 VERBOSE_TRACE( "EnumTextureFormatsCallback: advertised texture format has dwRGBBitCount %d, dwRBitMask %x, "
468 "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The format uses %s alpha.",
469 pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
470 pSurfaceDesc->ddpfPixelFormat.dwRBitMask,
471 pSurfaceDesc->ddpfPixelFormat.dwGBitMask,
472 pSurfaceDesc->ddpfPixelFormat.dwBBitMask,
473 pSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask,
474 pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" );
476 // Only accept RGB surfaces with alpha channel
477 if( (DDPF_ALPHAPIXELS | DDPF_RGB) ==
478 (pSurfaceDesc->ddpfPixelFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) )
480 // ignore formats with the DDPF_ALPHAPREMULT flag
481 if(!(pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT))
483 // take widest alpha channel available
484 if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth > pResult->dwAlphaBitDepth )
486 // take new format
487 rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) );
489 else if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth == pResult->dwAlphaBitDepth )
491 // tie-breaking: take highest bitcount
492 if( pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount > pResult->dwRGBBitCount )
494 // take new format
495 rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) );
501 return DDENUMRET_OK;
504 class DXRenderModule;
506 //////////////////////////////////////////////////////////////////////////////////
507 // DXSurface
508 //////////////////////////////////////////////////////////////////////////////////
510 /** ISurface implemenation.
512 @attention holds the DXRenderModule via non-refcounted
513 reference! This is safe with current state of affairs, since
514 the canvas::PageManager holds surface and render module via
515 shared_ptr (and makes sure all surfaces are deleted before its
516 render module member goes out of scope).
518 class DXSurface : public canvas::ISurface
520 public:
521 DXSurface( DXRenderModule& rRenderModule,
522 const ::basegfx::B2ISize& rSize );
523 ~DXSurface();
525 virtual bool selectTexture();
526 virtual bool isValid();
527 virtual bool update( const ::basegfx::B2IPoint& rDestPos,
528 const ::basegfx::B2IRange& rSourceRect,
529 ::canvas::IColorBuffer& rSource );
530 virtual ::basegfx::B2IVector getSize();
532 private:
533 /// Guard local methods against concurrent acces to RenderModule
534 class ImplRenderModuleGuard : private ::boost::noncopyable
536 public:
537 explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
538 inline ~ImplRenderModuleGuard();
540 private:
541 DXRenderModule& mrRenderModule;
544 DXRenderModule& mrRenderModule;
546 COMReference<IDirectDrawSurface> mpSurface;
547 COMReference<IDirect3DTexture2> mpTexture;
549 ::basegfx::B2IVector maSize;
552 //////////////////////////////////////////////////////////////////////////////////
553 // DXRenderModule
554 //////////////////////////////////////////////////////////////////////////////////
556 /// Default implementation of IDXRenderModule
557 class DXRenderModule : public IDXRenderModule
559 public:
560 explicit DXRenderModule( const ::Window& rWindow );
562 virtual void lock() const { maMutex.acquire(); }
563 virtual void unlock() const { maMutex.release(); }
565 virtual COMReference<IDirectDrawSurface>
566 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
568 virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
569 const ::basegfx::B2IRectangle& rCurrWindowArea );
571 virtual void resize( const ::basegfx::B2IRange& rect );
572 virtual HWND getHWND() const { return mhWnd; }
573 virtual void disposing();
574 virtual void screenShot();
575 virtual ::basegfx::B2IVector getPageSize();
576 virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
577 virtual void beginPrimitive( PrimitiveType eType );
578 virtual void endPrimitive();
579 virtual void pushVertex( const ::canvas::Vertex& vertex );
580 virtual bool isError();
582 const D3DDEVICEDESC& getDeviceDesc() const { return maDeviceDesc; }
583 const DDPIXELFORMAT& getTextureFormat() const { return maTextureFormat; }
584 COMReference<IDirectDraw2> getDirectDraw() { return mpDirectDraw; }
585 COMReference< IDirect3DDevice2 > getDevice() { return mpDirect3DDevice; }
587 void flushVertexCache();
589 struct ModeSelectContext
591 DDSURFACEDESC selectedDesc;
592 ::basegfx::B2ISize requestedSize;
595 /** Query actual size of the device
597 This is especially interesting for fullscreen devices
599 ::basegfx::B2ISize getFramebufferSize() const;
601 /** Query the amount of memory available for new surfaces
603 This might differ from getAvailableTextureMem()
604 @see getAvailableTextureMem()
606 @param bWithAGPMema
607 When true, returned value includes non-local,
608 i.e. AGP-able memory, too.
610 @return the amount of free surface mem
612 std::size_t getAvailableSurfaceMem( bool bWithAGPMem=true ) const;
614 /** Query the amount of memory available for new textures
616 This might differ from getAvailableSurfaceMem()
617 @see getAvailableSurfaceMem()
619 @param bWithAGPMema
620 When true, returned value includes non-local,
621 i.e. AGP-able memory, too.
623 @return the amount of free texture mem
625 std::size_t getAvailableTextureMem( bool bWithAGPMem=true ) const;
627 private:
628 bool queryCaps();
629 bool validateCaps();
630 bool setup3DDevice();
631 unsigned int getDisplayFormat() const;
633 void convert2Screen( ::basegfx::B2IPoint& io_rDestPos,
634 ::basegfx::B2IRange& io_rDestArea );
636 void renderInfoText( const ::rtl::OUString& rStr,
637 const Gdiplus::PointF& rPos ) const;
638 void renderFPSCounter() const;
639 void renderMemAvailable() const;
641 bool create( const ::Window& rWindow );
642 bool validateMainSurfaces();
644 /** This object represents the DirectX state machine. In order
645 to serialize access to DirectX's global state, a global
646 mutex is required.
648 static ::osl::Mutex maMutex;
650 HWND mhWnd;
651 ::boost::scoped_ptr<SystemChildWindow> mpWindow;
652 ::basegfx::B2IVector maSize;
654 ModeSelectContext maSelectedFullscreenMode;
655 DDPIXELFORMAT maTextureFormat;
657 MONITORINFO maMonitorInfo; // monitor info for mpDirectDraw's monitor
658 COMReference<IDirectDraw2> mpDirectDraw;
659 COMReference<IDirectDrawSurface> mpPrimarySurface;
660 COMReference<IDirectDrawSurface> mpBackBufferSurface;
662 COMReference< IDirect3D2 > mpDirect3D;
663 COMReference< IDirect3DDevice2 > mpDirect3DDevice;
665 mutable ::canvas::tools::ElapsedTime maLastUpdate; // for the frame counter
667 D3DDEVICEDESC maDeviceDesc;
669 typedef std::vector<canvas::Vertex> vertexCache_t;
670 vertexCache_t maVertexCache;
671 std::size_t mnCount;
673 int mnBeginSceneCount;
675 const bool mbPageFlipping;
676 bool mbHasNoTearingBlt;
677 bool mbError;
678 PrimitiveType meType;
680 ::canvas::ISurfaceSharedPtr mpTexture;
681 ::basegfx::B2IVector maPageSize;
684 ::osl::Mutex DXRenderModule::maMutex;
686 //////////////////////////////////////////////////////////////////////////////////
687 // DXSurface::ImplRenderModuleGuard
688 //////////////////////////////////////////////////////////////////////////////////
690 inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
691 DXRenderModule& rRenderModule ) :
692 mrRenderModule( rRenderModule )
694 mrRenderModule.lock();
697 inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
699 mrRenderModule.unlock();
702 #ifdef FAKE_MAX_NUMBER_TEXTURES
703 static sal_uInt32 gNumSurfaces = 0;
704 #endif
706 void fillRect( sal_uInt32 *pDest,
707 sal_uInt32 dwWidth,
708 sal_uInt32 dwHeight,
709 sal_uInt32 dwPitch,
710 sal_uInt32 dwColor )
712 for(sal_uInt32 i=0; i<dwWidth; ++i)
714 pDest[i]=dwColor;
715 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
718 for(sal_uInt32 j=0; j<dwHeight; ++j)
720 pDest[0]=dwColor;
721 pDest[dwWidth-1]=dwColor;
722 pDest += dwPitch;
726 //////////////////////////////////////////////////////////////////////////////////
727 // DXSurface::DXSurface
728 //////////////////////////////////////////////////////////////////////////////////
730 DXSurface::DXSurface( DXRenderModule& rRenderModule,
731 const ::basegfx::B2ISize& rSize ) :
732 mrRenderModule(rRenderModule),
733 mpTexture(NULL),
734 mpSurface(NULL),
735 maSize()
737 ImplRenderModuleGuard aGuard( mrRenderModule );
739 #ifdef FAKE_MAX_NUMBER_TEXTURES
740 ++gNumSurfaces;
741 if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
742 return;
743 #endif
745 #ifdef FAKE_MAX_TEXTURE_SIZE
746 if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
747 return;
748 if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
749 return;
750 #endif
752 ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
753 "DXSurface::DXSurface(): request for zero-sized surface");
755 const D3DDEVICEDESC &deviceDesc = rRenderModule.getDeviceDesc();
757 DDSURFACEDESC aSurfaceDesc;
758 rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
759 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
760 aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
761 aSurfaceDesc.dwWidth = ::std::min(deviceDesc.dwMaxTextureWidth,::canvas::tools::nextPow2(rSize.getX()));
762 aSurfaceDesc.dwHeight = ::std::min(deviceDesc.dwMaxTextureHeight,::canvas::tools::nextPow2(rSize.getY()));
763 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE |
764 DDSCAPS_VIDEOMEMORY |
765 DDSCAPS_LOCALVIDMEM;
766 rtl_copyMemory(&aSurfaceDesc.ddpfPixelFormat,&rRenderModule.getTextureFormat(),sizeof(DDPIXELFORMAT));
768 IDirectDrawSurface *pSurface;
769 COMReference<IDirectDraw2> pDirectDraw(rRenderModule.getDirectDraw());
770 HRESULT hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
771 if(FAILED(hr))
773 // if the call failed due to 'out of videomemory',
774 // retry with request for AGP memory.
775 if(DDERR_OUTOFVIDEOMEMORY == hr)
777 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE |
778 DDSCAPS_VIDEOMEMORY |
779 DDSCAPS_NONLOCALVIDMEM;
780 hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
784 if(SUCCEEDED(hr))
786 IDirect3DTexture2* pTexture;
787 if( FAILED(pSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&pTexture)) )
789 pSurface->Release();
790 return;
793 maSize.setX(aSurfaceDesc.dwWidth);
794 maSize.setY(aSurfaceDesc.dwHeight);
796 mpSurface=COMReference<IDirectDrawSurface>(pSurface);
797 mpTexture=COMReference<IDirect3DTexture2>(pTexture);
799 // #122683# Clear texture, to avoid ugly artifacts at the
800 // border to invisible sprite areas (note that the textures
801 // are usually only partly utilized).
802 clearSurface( mpSurface );
806 //////////////////////////////////////////////////////////////////////////////////
807 // DXSurface::~DXSurface
808 //////////////////////////////////////////////////////////////////////////////////
810 DXSurface::~DXSurface()
812 ImplRenderModuleGuard aGuard( mrRenderModule );
814 #ifdef FAKE_MAX_NUMBER_TEXTURES
815 gNumSurfaces--;
816 #endif
819 //////////////////////////////////////////////////////////////////////////////////
820 // DXSurface::selectTexture
821 //////////////////////////////////////////////////////////////////////////////////
823 bool DXSurface::selectTexture()
825 ImplRenderModuleGuard aGuard( mrRenderModule );
827 mrRenderModule.flushVertexCache();
829 D3DTEXTUREHANDLE aTextureHandle;
830 if(FAILED(mpTexture->GetHandle(
831 mrRenderModule.getDevice().get(),
832 &aTextureHandle)))
834 return false;
837 // select texture for next primitive
838 if(FAILED(mrRenderModule.getDevice()->SetRenderState(
839 D3DRENDERSTATE_TEXTUREHANDLE,aTextureHandle)))
841 return false;
844 #if defined(DX_DEBUG_IMAGES)
845 # if OSL_DEBUG_LEVEL > 0
846 if( mpSurface.is() )
848 DDSURFACEDESC aSurfaceDesc;
849 rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
850 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
852 if( SUCCEEDED(mpSurface->Lock( NULL,
853 &aSurfaceDesc,
854 DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY,
855 NULL)) )
857 imdebug( "rgba w=%d h=%d %p",
858 aSurfaceDesc.dwWidth,
859 aSurfaceDesc.dwHeight,
860 aSurfaceDesc.lpSurface );
862 mpSurface->Unlock(NULL);
865 # endif
866 #endif
868 return true;
871 //////////////////////////////////////////////////////////////////////////////////
872 // DXSurface::isValid
873 //////////////////////////////////////////////////////////////////////////////////
875 bool DXSurface::isValid()
877 ImplRenderModuleGuard aGuard( mrRenderModule );
879 if(!(mpSurface.is()))
880 return false;
882 if(mpSurface->IsLost() == DDERR_SURFACELOST)
884 mpSurface->Restore();
885 return false;
888 return true;
891 //////////////////////////////////////////////////////////////////////////////////
892 // DXSurface::update
893 //////////////////////////////////////////////////////////////////////////////////
895 bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
896 const ::basegfx::B2IRange& rSourceRect,
897 ::canvas::IColorBuffer& rSource )
899 ImplRenderModuleGuard aGuard( mrRenderModule );
901 // can't update if surface is not valid, that means
902 // either not existent nor restored...
903 if(!(isValid()))
904 return false;
906 DDSURFACEDESC aSurfaceDesc;
907 rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
908 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
910 // TODO(P2): only lock the region we want to update
911 if( FAILED(mpSurface->Lock( NULL,
912 &aSurfaceDesc,
913 DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY,
914 NULL)) )
915 return false;
917 if(sal_uInt8* pImage = rSource.lock())
919 switch( rSource.getFormat() )
921 case ::canvas::IColorBuffer::FMT_A8R8G8B8:
923 const std::size_t nSourceBytesPerPixel(4);
924 const std::size_t nSourcePitchInBytes(rSource.getStride());
925 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
926 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
928 // calculate the destination memory address
929 sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
930 (rDestPos.getY()*aSurfaceDesc.lPitch) +
931 (4*rDestPos.getX()));
933 const sal_uInt32 nNumBytesToCopy(
934 static_cast<sal_uInt32>(
935 rSourceRect.getWidth())*
936 nSourceBytesPerPixel);
937 const sal_uInt64 nNumLines(rSourceRect.getHeight());
939 for(sal_uInt32 i=0; i<nNumLines; ++i)
941 rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
943 pDst += aSurfaceDesc.lPitch;
944 pImage += nSourcePitchInBytes;
947 break;
949 case ::canvas::IColorBuffer::FMT_R8G8B8:
951 const std::size_t nSourceBytesPerPixel(3);
952 const std::size_t nSourcePitchInBytes(rSource.getStride());
953 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
954 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
956 // calculate the destination memory address
957 sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
958 (rDestPos.getY()*aSurfaceDesc.lPitch) +
959 (4*rDestPos.getX()));
961 const sal_uInt64 nNumColumns(rSourceRect.getWidth());
962 const sal_uInt64 nNumLines(rSourceRect.getHeight());
963 for(sal_uInt32 i=0; i<nNumLines; ++i)
965 sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
966 sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
967 for(sal_uInt32 x=0; x<nNumColumns; ++x)
969 sal_uInt32 color(0xFF000000);
970 color |= pSrcScanline[2]<<16;
971 color |= pSrcScanline[1]<<8;
972 color |= pSrcScanline[0];
973 pSrcScanline += 3;
974 *pDstScanline++ = color;
977 pDst += aSurfaceDesc.lPitch;
978 pImage += nSourcePitchInBytes;
981 break;
983 case ::canvas::IColorBuffer::FMT_X8R8G8B8:
985 const std::size_t nSourceBytesPerPixel(4);
986 const std::size_t nSourcePitchInBytes(rSource.getStride());
987 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
988 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
990 // calculate the destination memory address
991 sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
992 (rDestPos.getY()*aSurfaceDesc.lPitch) +
993 (4*rDestPos.getX()));
995 const sal_uInt64 nNumLines(rSourceRect.getHeight());
997 for(sal_uInt32 i=0; i<nNumLines; ++i)
999 sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
1000 sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
1001 for(sal_uInt32 j=0; j<rSourceRect.getWidth(); ++j)
1002 pDst32[j] = 0xFF000000 | pSrc32[j];
1004 pDst += aSurfaceDesc.lPitch;
1005 pImage += nSourcePitchInBytes;
1008 break;
1010 default:
1011 ENSURE_OR_RETURN(false,
1012 "DXSurface::update(): Unknown/unimplemented buffer format" );
1013 break;
1016 rSource.unlock();
1019 return SUCCEEDED(mpSurface->Unlock(NULL));
1022 //////////////////////////////////////////////////////////////////////////////////
1023 // DXSurface::getSize
1024 //////////////////////////////////////////////////////////////////////////////////
1026 ::basegfx::B2IVector DXSurface::getSize()
1028 return maSize;
1031 //////////////////////////////////////////////////////////////////////////////////
1032 // DXRenderModule::DXRenderModule
1033 //////////////////////////////////////////////////////////////////////////////////
1035 DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
1036 mhWnd(0),
1037 mpWindow(),
1038 maSize(),
1039 maSelectedFullscreenMode(),
1040 maTextureFormat(),
1041 maMonitorInfo(),
1042 mpDirectDraw(),
1043 mpPrimarySurface(),
1044 mpBackBufferSurface(),
1045 mpDirect3D(),
1046 mpDirect3DDevice(),
1047 maLastUpdate(),
1048 maDeviceDesc(),
1049 maVertexCache(),
1050 mnCount(0),
1051 mnBeginSceneCount(0),
1052 mbPageFlipping( false ),
1053 mbHasNoTearingBlt( false ),
1054 mbError( false ),
1055 meType( PRIMITIVE_TYPE_UNKNOWN ),
1056 mpTexture(),
1057 maPageSize()
1059 // TODO(P2): get rid of those fine-grained locking
1060 ::osl::MutexGuard aGuard( maMutex );
1062 if(!(create(rWindow)))
1064 throw lang::NoSupportException(
1065 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1066 "Could not create DirectX device!") ),NULL);
1069 // allocate a single texture surface which can be used later.
1070 // we also use this to calibrate the page size.
1071 ::basegfx::B2IVector aPageSize(
1072 ::std::min(
1073 static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureWidth),
1074 static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)),
1075 ::std::min(
1076 static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureHeight),
1077 static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)));
1078 while(true)
1080 mpTexture = ::canvas::ISurfaceSharedPtr(
1081 new DXSurface(*this,aPageSize));
1082 if(mpTexture->isValid())
1083 break;
1085 aPageSize.setX(aPageSize.getX()>>1);
1086 aPageSize.setY(aPageSize.getY()>>1);
1087 if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
1088 (aPageSize.getY() < MIN_TEXTURE_SIZE))
1090 throw lang::NoSupportException(
1091 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1092 "Could not create DirectX device!") ),NULL);
1095 maPageSize=aPageSize;
1098 //////////////////////////////////////////////////////////////////////////////////
1099 // DXRenderModule::create
1100 //////////////////////////////////////////////////////////////////////////////////
1102 bool DXRenderModule::create( const ::Window& rWindow )
1104 // TODO(P2): get rid of those fine-grained locking
1105 ::osl::MutexGuard aGuard( maMutex );
1107 maVertexCache.reserve(1024);
1109 mpWindow.reset(
1110 new SystemChildWindow(
1111 const_cast<Window *>(&rWindow), 0) );
1113 // system child window must not receive mouse events
1114 mpWindow->SetMouseTransparent( TRUE );
1116 // parent should receive paint messages as well
1117 // [PARENTCLIPMODE_NOCLIP], the argument is here
1118 // passed as plain numeric value since the stupid
1119 // define utilizes a USHORT cast.
1120 mpWindow->SetParentClipMode(0x0002);
1122 // the system child window must not clear its background
1123 mpWindow->EnableEraseBackground( FALSE );
1125 mpWindow->SetControlForeground();
1126 mpWindow->SetControlBackground();
1127 mpWindow->EnablePaint(FALSE);
1129 const SystemEnvData *pData = mpWindow->GetSystemData();
1130 const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
1131 mhWnd = const_cast<HWND>(hwnd);
1133 ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
1134 "DXRenderModuleDXRenderModuleWin32() No valid HWND given." );
1136 // retrieve position and size of the parent window
1137 const ::Size &rSizePixel(rWindow.GetSizePixel());
1139 // remember the size of the parent window, since we
1140 // need to use this for our child window.
1141 maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
1142 maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
1144 // let the child window cover the same size as the parent window.
1145 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1147 MonitorList aMonitorList;
1148 fillMonitorList( aMonitorList );
1150 mpDirectDraw = COMReference<IDirectDraw2>(
1151 createDirectDraw(aMonitorList, maMonitorInfo, mhWnd));
1153 if(!mpDirectDraw.is())
1154 return false;
1156 if( !queryCaps() )
1158 // go defunct, and exit
1159 VERBOSE_TRACE( "Device::Device(): GetCaps failed" );
1160 mpDirectDraw.reset();
1161 return false;
1164 if( !validateCaps() )
1166 // go defunct, and exit
1167 VERBOSE_TRACE( "Device::Device(): Insufficient DirectX capabilities, failed" );
1168 mpDirectDraw.reset();
1169 return false;
1172 if( FAILED( mpDirectDraw->SetCooperativeLevel( mhWnd,
1173 DDSCL_NORMAL|DDSCL_MULTITHREADED|DDSCL_FPUPRESERVE ) ) )
1175 // go defunct, and exit
1176 VERBOSE_TRACE( "Device::Device(): SetCooperativeLevel failed" );
1177 mpDirectDraw.reset();
1178 return false;
1181 // setup query struct
1182 rtl_fillMemory( &maSelectedFullscreenMode.selectedDesc,
1183 sizeof(DDSURFACEDESC), 0 );
1184 maSelectedFullscreenMode.selectedDesc.dwSize = sizeof(DDSURFACEDESC);
1186 // read current display mode, e.g. for screen dimension
1187 if( FAILED( mpDirectDraw->GetDisplayMode( &maSelectedFullscreenMode.selectedDesc )) )
1189 // go defunct, and exit
1190 VERBOSE_TRACE( "Device::Device(): GetDisplayMode failed" );
1191 mpDirectDraw.reset();
1192 return false;
1195 // check for supported primary surface formats...
1196 unsigned int nDisplayFormat = getDisplayFormat() & 0x00000FFF;
1197 if(nDisplayFormat != 0x888 && nDisplayFormat != 0x565)
1199 // go defunct, and exit
1200 VERBOSE_TRACE( "Device::Device(): Unsupported DisplayFormat" );
1201 mpDirectDraw.reset();
1202 return false;
1205 // create primary surface reference
1206 DDSURFACEDESC aSurfaceDesc;
1207 IDirectDrawSurface* pPrimarySurface;
1209 rtl_fillMemory( &aSurfaceDesc,
1210 sizeof(DDSURFACEDESC), 0 );
1211 aSurfaceDesc.dwSize = sizeof(aSurfaceDesc);
1212 aSurfaceDesc.dwFlags = DDSD_CAPS;
1213 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
1215 if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pPrimarySurface, NULL)) )
1217 // go defunct, and exit
1218 VERBOSE_TRACE( "Device::Device(): CreateSurface failed" );
1219 mpDirectDraw.reset();
1220 return false;
1223 mpPrimarySurface = COMReference< IDirectDrawSurface >(pPrimarySurface);
1225 // create a Clipper and associate it with the primary surface
1226 // and the render window
1227 LPDIRECTDRAWCLIPPER pClipper;
1228 if( FAILED(mpDirectDraw->CreateClipper( 0, &pClipper, NULL )) )
1230 // go defunct, and exit
1231 VERBOSE_TRACE( "Device::Device(): CreateClipper failed" );
1232 mpPrimarySurface.reset();
1233 mpDirectDraw.reset();
1234 return false;
1236 if( FAILED(pClipper->SetHWnd(0, mhWnd)) )
1238 // go defunct, and exit
1239 VERBOSE_TRACE( "Device::Device(): Clipper->SetHWnd failed" );
1240 pClipper->Release();
1241 mpPrimarySurface.reset();
1242 mpDirectDraw.reset();
1243 return false;
1245 if( FAILED(mpPrimarySurface->SetClipper( pClipper )) )
1247 // go defunct, and exit
1248 VERBOSE_TRACE( "Device::Device(): SetClipper failed" );
1249 pClipper->Release();
1250 mpPrimarySurface.reset();
1251 mpDirectDraw.reset();
1252 return false;
1255 // clipper is now owned by mpPrimarySurface, release our reference
1256 pClipper->Release();
1258 // TODO(F3): Check whether palette needs any setup here
1260 // get us a backbuffer for simulated flipping
1261 IDirectDrawSurface* pSurface;
1263 // Strictly speaking, we don't need a full screen worth of
1264 // backbuffer here. We could also scale dynamically with
1265 // the current window size, but this will make it
1266 // necessary to temporarily have two buffers while copying
1267 // from the old to the new one. What's more, at the time
1268 // we need a larger buffer, DX might not have sufficient
1269 // resources available, and we're then left with too small
1270 // a back buffer, and no way of falling back to a
1271 // different canvas implementation.
1272 const ::basegfx::B2ISize aSize( getFramebufferSize() );
1274 rtl_fillMemory( &aSurfaceDesc,
1275 sizeof(DDSURFACEDESC), 0 );
1276 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1277 aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1278 aSurfaceDesc.dwHeight= aSize.getY();
1279 aSurfaceDesc.dwWidth = aSize.getX();
1281 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1283 HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1285 if( FAILED( nRes ) )
1287 if( nRes == DDERR_OUTOFVIDEOMEMORY )
1289 // local vid mem failed. Maybe AGP mem works?
1290 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1291 if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) )
1293 // no chance, go defunct, and exit
1294 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1295 mpPrimarySurface.reset();
1296 mpDirectDraw.reset();
1297 return false;
1300 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1302 else
1304 // no chance, go defunct, and exit
1305 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1306 mpPrimarySurface.reset();
1307 mpDirectDraw.reset();
1308 return false;
1312 VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel",
1313 aSurfaceDesc.dwWidth,
1314 aSurfaceDesc.dwHeight );
1316 mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface);
1317 clearSurface(mpBackBufferSurface);
1319 if( !setup3DDevice() )
1321 // go defunct, and exit
1322 VERBOSE_TRACE( "Device::Device(): setup3DDevice failed" );
1323 mpBackBufferSurface.reset();
1324 mpPrimarySurface.reset();
1325 mpDirectDraw.reset();
1326 return false;
1329 mpWindow->Show();
1331 return true;
1334 //////////////////////////////////////////////////////////////////////////////////
1335 // DXRenderModule::getSize
1336 //////////////////////////////////////////////////////////////////////////////////
1338 ::basegfx::B2ISize DXRenderModule::getFramebufferSize() const
1340 return mpDirectDraw.is() ?
1341 ::basegfx::B2ISize( maSelectedFullscreenMode.selectedDesc.dwWidth,
1342 maSelectedFullscreenMode.selectedDesc.dwHeight ) :
1343 ::basegfx::B2ISize();
1346 //////////////////////////////////////////////////////////////////////////////////
1347 // DXRenderModule::setup3DDevice
1348 //////////////////////////////////////////////////////////////////////////////////
1350 bool DXRenderModule::setup3DDevice()
1352 // create and setup 3D device
1353 // ==========================
1354 LPDIRECT3D2 pDirect3D;
1355 if( FAILED( mpDirectDraw->QueryInterface( IID_IDirect3D2, (LPVOID*)&pDirect3D ) ) )
1357 // go defunct, and exit
1358 VERBOSE_TRACE( "Device::setup3DDevice(): QueryInterface() for Direct3D failed" );
1359 return false;
1362 mpDirect3D = COMReference< IDirect3D2 >(pDirect3D);
1364 LPDIRECT3DDEVICE2 pDirect3DDevice;
1365 // try HW-accelerated device first
1366 if( FAILED(mpDirect3D->CreateDevice( IID_IDirect3DHALDevice,
1367 mpBackBufferSurface.get(),
1368 &pDirect3DDevice )) )
1370 // no HW 3D support - go defunct, and exit
1371 VERBOSE_TRACE( "Device::setup3DDevice(): CreateDevice() for HW Direct3D rendering failed" );
1372 mpDirect3D.reset();
1373 return false;
1376 D3DDEVICEDESC aHELDeviceDesc;
1377 rtl_fillMemory(&maDeviceDesc,sizeof(maDeviceDesc),0);
1378 rtl_fillMemory(&aHELDeviceDesc,sizeof(aHELDeviceDesc),0);
1379 maDeviceDesc.dwSize = sizeof(maDeviceDesc);
1380 aHELDeviceDesc.dwSize = sizeof(aHELDeviceDesc);
1381 if(FAILED(pDirect3DDevice->GetCaps(&maDeviceDesc,&aHELDeviceDesc)))
1383 // go defunct, and exit
1384 VERBOSE_TRACE( "Device::setup3DDevice(): GetCaps() for Direct3DDevice failed" );
1385 mpDirect3D.reset();
1386 return false;
1389 mpDirect3DDevice = COMReference< IDirect3DDevice2 >(pDirect3DDevice);
1391 // select appropriate texture format (_need_ alpha channel here)
1392 rtl_fillMemory( &maTextureFormat,
1393 sizeof(DDPIXELFORMAT), 0 );
1394 maTextureFormat.dwSize = sizeof(DDPIXELFORMAT);
1395 if( SUCCEEDED(mpDirect3DDevice->EnumTextureFormats( EnumTextureFormatsCallback, &maTextureFormat )) )
1397 bool bSupportedFormat = true;
1398 if((maTextureFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) != (DDPF_ALPHAPIXELS | DDPF_RGB))
1399 bSupportedFormat = false;
1400 else if(maTextureFormat.dwRGBAlphaBitMask != 0xFF000000)
1401 bSupportedFormat = false;
1402 else if(maTextureFormat.dwRBitMask != 0x00FF0000)
1403 bSupportedFormat = false;
1404 else if(maTextureFormat.dwGBitMask != 0x0000FF00)
1405 bSupportedFormat = false;
1406 else if(maTextureFormat.dwBBitMask != 0x000000FF)
1407 bSupportedFormat = false;
1409 if(bSupportedFormat)
1411 VERBOSE_TRACE( "Device::setup3DDevice(): chose texture format dwRGBBitCount %d, dwRBitMask %x, "
1412 "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The texture uses %s alpha.",
1413 maTextureFormat.dwRGBBitCount,
1414 maTextureFormat.dwRBitMask,
1415 maTextureFormat.dwGBitMask,
1416 maTextureFormat.dwBBitMask,
1417 maTextureFormat.dwRGBAlphaBitMask,
1418 maTextureFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" );
1420 // setup the device (with as much as we can possibly do here)
1421 // ==========================================================
1423 LPDIRECT3DVIEWPORT2 pViewport;
1425 if( SUCCEEDED(mpDirect3D->CreateViewport( &pViewport, NULL )) )
1427 if( SUCCEEDED(mpDirect3DDevice->AddViewport( pViewport )) )
1429 // setup viewport (to whole backbuffer)
1430 D3DVIEWPORT2 aViewport;
1432 aViewport.dwSize = sizeof(D3DVIEWPORT2);
1433 aViewport.dwX = 0;
1434 aViewport.dwY = 0;
1435 aViewport.dwWidth = maSelectedFullscreenMode.selectedDesc.dwWidth;
1436 aViewport.dwHeight = maSelectedFullscreenMode.selectedDesc.dwHeight;
1437 aViewport.dvClipX = -1.0;
1438 aViewport.dvClipY = -1.0;
1439 aViewport.dvClipWidth = 2.0;
1440 aViewport.dvClipHeight = 2.0;
1441 aViewport.dvMinZ = 0.0;
1442 aViewport.dvMaxZ = 1.0;
1444 if( SUCCEEDED(pViewport->SetViewport2( &aViewport )) )
1446 if( SUCCEEDED(mpDirect3DDevice->SetCurrentViewport( pViewport )) )
1448 // Viewport was handed over to 3DDevice, thus we can release now
1449 pViewport->Release();
1451 // currently, no need for any
1452 // matrix or light source
1453 // setup, since we only render
1454 // transformed&lighted
1455 // vertices
1457 // done; successfully
1458 return true;
1460 else
1462 VERBOSE_TRACE( "Device::setup3DDevice(): SetCurrentViewport failed" );
1465 else
1467 VERBOSE_TRACE( "Device::setup3DDevice(): SetViewport2 failed" );
1470 else
1472 VERBOSE_TRACE( "Device::setup3DDevice(): AddViewport failed" );
1475 pViewport->Release();
1477 else
1479 VERBOSE_TRACE( "Device::setup3DDevice(): CreateViewport failed" );
1482 else
1484 VERBOSE_TRACE( "Device::setup3DDevice(): No supported pixelformat" );
1487 else
1489 VERBOSE_TRACE( "Device::setup3DDevice(): EnumTextureFormats failed" );
1492 // go defunct, and exit
1493 mpDirect3DDevice.reset();
1494 mpDirect3D.reset();
1496 return false;
1499 //////////////////////////////////////////////////////////////////////////////////
1500 // DXRenderModule::queryCaps
1501 //////////////////////////////////////////////////////////////////////////////////
1503 bool DXRenderModule::queryCaps()
1505 DDCAPS aHWCaps;
1506 DDCAPS aHELCaps;
1508 rtl_fillMemory( &aHWCaps,
1509 sizeof(aHWCaps), 0 );
1510 rtl_fillMemory( &aHELCaps,
1511 sizeof(aHELCaps), 0 );
1512 aHWCaps.dwSize = sizeof( aHWCaps );
1513 aHELCaps.dwSize = sizeof( aHELCaps );
1515 if( FAILED( mpDirectDraw->GetCaps( &aHWCaps,
1516 &aHELCaps ) ) )
1518 return false;
1521 mbHasNoTearingBlt = aHWCaps.dwFXCaps & DDBLTFX_NOTEARING;
1523 VERBOSE_TRACE( "dxcanvas initialization: %d bytes VRAM free for surfaces (%d with AGP mem), "
1524 "%d bytes VRAM free for textures (%d with AGP mem)",
1525 getAvailableSurfaceMem( false ),
1526 getAvailableSurfaceMem( true ),
1527 getAvailableTextureMem( false ),
1528 getAvailableTextureMem( true ) );
1530 return true;
1533 //////////////////////////////////////////////////////////////////////////////////
1534 // DXRenderModule::validateCaps
1535 //////////////////////////////////////////////////////////////////////////////////
1537 bool DXRenderModule::validateCaps()
1539 // TODO(E3): Validate HW capabilities. Depending on primary
1540 // surface size, reject HW e.g. on the grounds of insufficient
1541 // VRAM.
1543 // setup query struct
1544 DDSURFACEDESC desc;
1545 rtl_fillMemory(&desc,sizeof(DDSURFACEDESC),0);
1546 desc.dwSize = sizeof(DDSURFACEDESC);
1548 // read current display mode, e.g. for screen dimension
1549 if(FAILED( mpDirectDraw->GetDisplayMode(&desc)))
1550 return false;
1552 // simple heuristic: we need at least 3 times the desktop
1553 // resolution based on ARGB color values...
1554 std::size_t nMinimumVRAMSize = ((desc.dwWidth*desc.dwHeight)<<2)*3;
1555 if(getAvailableSurfaceMem() < nMinimumVRAMSize)
1556 return false;
1558 return true;
1561 //////////////////////////////////////////////////////////////////////////////////
1562 // DXRenderModule::getDisplayFormat
1563 //////////////////////////////////////////////////////////////////////////////////
1565 unsigned int DXRenderModule::getDisplayFormat() const
1567 unsigned int nFormat;
1568 nFormat = ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
1569 nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRBitMask)<<8;
1570 nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwGBitMask)<<4;
1571 nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwBBitMask);
1572 return nFormat;
1575 //////////////////////////////////////////////////////////////////////////////////
1576 // DXRenderModule::getAvailableSurfaceMem
1577 //////////////////////////////////////////////////////////////////////////////////
1579 std::size_t DXRenderModule::getAvailableSurfaceMem( bool bWithAGPMem ) const
1581 if( !mpDirectDraw.is() )
1582 return 0;
1584 std::size_t nRes( 0 );
1586 DDSCAPS aSurfaceCaps;
1587 DWORD nTotal, nFree;
1589 // real VRAM (const_cast, since GetAvailableVidMem is non-const)
1590 aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1591 if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1592 return 0;
1594 nRes += nFree;
1596 if( bWithAGPMem )
1598 // AGP RAM (const_cast, since GetAvailableVidMem is non-const)
1599 aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1600 if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1601 return 0;
1603 nRes += nFree;
1606 return nRes;
1609 //////////////////////////////////////////////////////////////////////////////////
1610 // DXRenderModule::getAvailableTextureMem
1611 //////////////////////////////////////////////////////////////////////////////////
1613 std::size_t DXRenderModule::getAvailableTextureMem( bool bWithAGPMem ) const
1615 if( !mpDirectDraw.is() )
1616 return 0;
1618 std::size_t nRes( 0 );
1620 DDSCAPS aSurfaceCaps;
1621 DWORD nTotal, nFree;
1623 // TODO(F1): Check if flags are applicable
1625 // real VRAM (const_cast, since GetAvailableVidMem is non-const)
1626 aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1627 if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1628 return 0;
1630 nRes += nFree;
1632 if( bWithAGPMem )
1634 // AGP RAM (const_cast, since GetAvailableVidMem is non-const)
1635 aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1636 if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1637 return 0;
1639 nRes += nFree;
1642 // TODO(F1): Add pool mem
1644 return nRes;
1647 //////////////////////////////////////////////////////////////////////////////////
1648 // DXRenderModule::convert2Screen
1649 //////////////////////////////////////////////////////////////////////////////////
1651 void DXRenderModule::convert2Screen( ::basegfx::B2IPoint& io_rDestPos,
1652 ::basegfx::B2IRange& io_rDestArea )
1654 POINT aPoint = { 0, 0 };
1655 ClientToScreen( mhWnd, &aPoint );
1657 // i52230 make sure given screen coordinate is relative to
1658 // this monitor's area (the device rendering is always
1659 // contained to a single monitor)
1660 aPoint.x -= maMonitorInfo.rcMonitor.left;
1661 aPoint.y -= maMonitorInfo.rcMonitor.top;
1663 io_rDestPos.setX( io_rDestPos.getX() + aPoint.x );
1664 io_rDestPos.setY( io_rDestPos.getY() + aPoint.y );
1666 const ::basegfx::B2ISize& rSize( getFramebufferSize() );
1668 // calc output bounds (clip against framebuffer bounds)
1669 io_rDestArea = ::basegfx::B2IRange(
1670 ::std::max( sal_Int32(0),
1671 ::std::min( sal_Int32(rSize.getX()),
1672 sal_Int32(io_rDestArea.getMinX() + aPoint.x) ) ),
1673 ::std::max( sal_Int32(0),
1674 ::std::min( sal_Int32(rSize.getY()),
1675 sal_Int32(io_rDestArea.getMinY() + aPoint.y) ) ),
1676 ::std::max( sal_Int32(0),
1677 ::std::min( sal_Int32(rSize.getX()),
1678 sal_Int32(io_rDestArea.getMaxX() + aPoint.x) ) ),
1679 ::std::max( sal_Int32(0),
1680 ::std::min( sal_Int32(rSize.getY()),
1681 sal_Int32(io_rDestArea.getMaxY() + aPoint.y) ) ) );
1684 //////////////////////////////////////////////////////////////////////////////////
1685 // DXRenderModule::createSystemMemorySurface
1686 //////////////////////////////////////////////////////////////////////////////////
1688 COMReference<IDirectDrawSurface> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
1690 DDSURFACEDESC aSurfaceDesc;
1691 IDirectDrawSurface* pSurface;
1693 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1694 aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;;
1695 aSurfaceDesc.dwWidth = rSize.getX();
1696 aSurfaceDesc.dwHeight= rSize.getY();
1698 rtl_copyMemory( &aSurfaceDesc.ddpfPixelFormat, &maTextureFormat, sizeof(DDPIXELFORMAT) );
1700 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
1702 HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1703 if(FAILED(nRes))
1704 return COMReference<IDirectDrawSurface>(NULL);
1706 return COMReference<IDirectDrawSurface>(pSurface);
1709 //////////////////////////////////////////////////////////////////////////////////
1710 // DXRenderModule::flip
1711 //////////////////////////////////////////////////////////////////////////////////
1713 bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
1714 const ::basegfx::B2IRectangle& rCurrWindowArea )
1716 // TODO(P2): get rid of those fine-grained locking
1717 ::osl::MutexGuard aGuard( maMutex );
1719 // see if the main surfaces got lost. if so, try to
1720 // restore them. bail out if this operation fails.
1721 if(!(validateMainSurfaces()))
1722 return false;
1724 flushVertexCache();
1726 ENSURE_OR_THROW( !mnBeginSceneCount,
1727 "Device::flip(): within 3D scene" );
1729 // TODO(E3): handle DX errors more thoroughly. For fullscreen
1730 // exclusive mode, actually even our primary surface can get
1731 // lost and needs restore!
1733 if( mpDirectDraw.is() &&
1734 mpPrimarySurface.is() &&
1735 mpBackBufferSurface.is() )
1737 // ignore area and offset for page flipping device
1738 if( mbPageFlipping )
1740 #if defined(VERBOSE) && defined(DBG_UTIL)
1741 renderFPSCounter();
1742 renderMemAvailable();
1743 #endif
1744 VERBOSE_TRACE( "Device::flip(): Using true page flipping" );
1746 // use true page flipping. Hopefully, the 3D hardware
1747 // is flushed on this flip call (rumours have it that
1748 // way), otherwise, perform the Lock hack as for the
1749 // Blt below.
1750 if( SUCCEEDED(mpPrimarySurface->Flip( NULL, DDFLIP_WAIT )) )
1751 return true;
1753 else
1755 VERBOSE_TRACE( "Device::flip(): Using blt for page flipping" );
1757 // determine actual window position
1758 ::basegfx::B2IPoint aDestPoint( rUpdateArea.getMinimum() );
1759 ::basegfx::B2IRange aSourceArea( rUpdateArea );
1760 ::basegfx::B2IRange aDestArea( 0,0,
1761 static_cast<sal_Int32>(rCurrWindowArea.getWidth()),
1762 static_cast<sal_Int32>(rCurrWindowArea.getHeight()) );
1763 convert2Screen( aDestPoint, aDestArea );
1765 // perform clipping
1766 if( !::canvas::tools::clipBlit( aSourceArea,
1767 aDestPoint,
1768 rUpdateArea,
1769 aDestArea ) )
1770 return true; // fully clipped, but still, in a way,
1771 // successful.
1773 // TODO(P1): Rumours have it that the 3D hardware
1774 // _might_ still be rendering with flaky drivers,
1775 // which don't flush properly on Blt(). It was said,
1776 // that 'usually', it works to lock the 3D render
1777 // target (the backbuffer in this case). OTOH, I've
1778 // found that this tends to degrade performance
1779 // significantly on complying cards...
1781 // TODO(P1): Up until rev. 1.3, this method contained
1782 // code to make sure the blit will start _immediately_
1783 // after the Blt call. If this is not warranted, wait
1784 // for the next vsync. As this case was found to be
1785 // extremely seldom, kicked out (what's more, there's
1786 // simply no guarantee that the blitter will be
1787 // available at any point in the code - Windows still
1788 // is a preemptive multi-processing environment. And
1789 // _if_ we're competing with someone over the blitter,
1790 // we will do so the next VBLANK interval, and the
1791 // following...)
1793 // screen update seems to be smoother when waiting
1794 // for vblank in every case - even when blitter
1795 // supports the DDBLTFX_NOTEARING flag.
1796 if( FAILED(mpDirectDraw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,
1797 NULL)) )
1798 return false;
1800 DDBLTFX aBltFx;
1801 DDBLTFX* pBltFX = NULL;
1802 if( mbHasNoTearingBlt )
1804 // Blt can internally schedule for no-tearing
1805 // ===========================================
1807 rtl_fillMemory( &aBltFx,
1808 sizeof(aBltFx), 0 );
1809 aBltFx.dwSize = sizeof(aBltFx);
1810 aBltFx.dwDDFX = DDBLTFX_NOTEARING;
1812 pBltFX = &aBltFx;
1815 if( doBlit( aDestPoint,
1816 *mpPrimarySurface,
1817 aSourceArea,
1818 *mpBackBufferSurface,
1819 pBltFX,false ) )
1821 #if defined(VERBOSE) && defined(DBG_UTIL)
1822 renderFPSCounter();
1823 renderMemAvailable();
1824 #endif
1825 return true;
1829 return false;
1832 //////////////////////////////////////////////////////////////////////////////////
1833 // DXRenderModule::disposing
1834 //////////////////////////////////////////////////////////////////////////////////
1836 void DXRenderModule::disposing()
1838 if(!(mhWnd))
1839 return;
1841 mpTexture.reset();
1842 mpWindow.reset();
1843 mhWnd=NULL;
1845 // refrain from releasing the DX5 objects - deleting the
1846 // DX5 device seems to kill the whole engine, including
1847 // all objects we might still hold references to
1848 // (surfaces, e.g.)
1851 //////////////////////////////////////////////////////////////////////////////////
1852 // DXRenderModule::screenshot
1853 //////////////////////////////////////////////////////////////////////////////////
1855 void DXRenderModule::screenShot()
1857 if(!(mpBackBufferSurface.get()))
1858 return;
1859 char filename[256];
1860 static sal_uInt32 counter = 0;
1861 sprintf(filename,"c:\\shot%d.bmp",counter++);
1862 dumpSurface(mpBackBufferSurface,filename);
1865 //////////////////////////////////////////////////////////////////////////////////
1866 // DXRenderModule::validateMainSurfaces
1867 //////////////////////////////////////////////////////////////////////////////////
1869 bool DXRenderModule::validateMainSurfaces()
1871 if(mpPrimarySurface.get()) {
1872 if(mpPrimarySurface->IsLost() == DDERR_SURFACELOST) {
1873 if(FAILED(mpPrimarySurface->Restore()))
1874 return false;
1878 if(mpBackBufferSurface.get()) {
1879 if(mpBackBufferSurface->IsLost() == DDERR_SURFACELOST)
1881 // TODO(F1): simply restoring the backbuffer does not
1882 // work as expected, we need to re-create everything
1883 // from scratch. find out why...
1884 //if(SUCCEEDED(mpBackBufferSurface->Restore()))
1885 // return setup3DDevice();
1887 mpBackBufferSurface.reset();
1889 // get us a backbuffer for simulated flipping
1890 IDirectDrawSurface* pSurface;
1892 // TODO(P2): Strictly speaking, we don't need a full screen worth of
1893 // backbuffer here. We could also scale dynamically with the current
1894 // window size, but this will make it necessary to temporarily have two
1895 // buffers while copying from the old to the new one. YMMV.
1896 const ::basegfx::B2ISize aSize( getFramebufferSize() );
1898 DDSURFACEDESC aSurfaceDesc;
1899 rtl_fillMemory( &aSurfaceDesc, sizeof(DDSURFACEDESC), 0 );
1900 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1901 aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1902 aSurfaceDesc.dwHeight= aSize.getY();
1903 aSurfaceDesc.dwWidth = aSize.getX();
1905 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1907 HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1909 if( FAILED( nRes ) )
1911 if( nRes == DDERR_OUTOFVIDEOMEMORY )
1913 // local vid mem failed. Maybe AGP mem works?
1914 aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1915 if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) )
1917 // no chance
1918 return false;
1921 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1923 else
1925 // no chance
1926 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1927 return false;
1931 VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel",
1932 aSurfaceDesc.dwWidth,
1933 aSurfaceDesc.dwHeight );
1935 mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface);
1937 return setup3DDevice();
1941 return true;
1944 void DXRenderModule::renderInfoText( const ::rtl::OUString& rStr,
1945 const Gdiplus::PointF& rPos ) const
1947 ENSURE_OR_THROW( !mnBeginSceneCount,
1948 "Device::renderInfoText(): within 3D scene" );
1950 // render text directly to primary surface
1951 GraphicsSharedPtr pGraphics;
1953 if( mbPageFlipping )
1955 // render on top of backbuffer. We have
1956 // page flipping, anyway, thus this will
1957 // cost us nothing.
1958 pGraphics = createSurfaceGraphics( mpBackBufferSurface );
1960 else
1962 // render FPS directly to front buffer.
1963 // That saves us another explicit blit,
1964 // and for me, the FPS counter can blink,
1965 // if it likes to...
1966 pGraphics = createSurfaceGraphics( mpPrimarySurface );
1969 if( !mbPageFlipping )
1971 // clear background. We might be doing optimized redraws,
1972 // and the background under the FPS count will then not be
1973 // cleared.
1974 Gdiplus::SolidBrush aBrush(
1975 Gdiplus::Color( 255, 255, 255 ) );
1977 pGraphics->FillRectangle( &aBrush,
1978 rPos.X, rPos.Y, 80.0, 20.0 );
1981 Gdiplus::SolidBrush aBrush(
1982 Gdiplus::Color( 255, 0, 255 ) );
1983 Gdiplus::Font aFont( NULL,
1985 Gdiplus::FontStyleRegular,
1986 Gdiplus::UnitWorld,
1987 NULL );
1988 pGraphics->DrawString( reinterpret_cast<LPCWSTR>(rStr.getStr()),
1989 rStr.getLength(),
1990 &aFont,
1991 rPos,
1992 &aBrush );
1995 //////////////////////////////////////////////////////////////////////////////////
1996 // DXRenderModule::renderMemAvailable
1997 //////////////////////////////////////////////////////////////////////////////////
1999 void DXRenderModule::renderMemAvailable() const
2001 ENSURE_OR_THROW( !mnBeginSceneCount,
2002 "DXRenderModule::renderMemAvailable(): within 3D scene" );
2004 const double nSurfaceMem( getAvailableSurfaceMem()/1024 );
2006 ::rtl::OUString text( ::rtl::math::doubleToUString( nSurfaceMem,
2007 rtl_math_StringFormat_F,
2008 2,'.',NULL,' ') );
2010 // pad with leading space
2011 while( text.getLength() < 6 )
2012 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2014 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("S: ")) + text;
2016 renderInfoText( text,
2017 Gdiplus::PointF( 0.0, 20) );
2020 const double nTexMem( getAvailableTextureMem()/1024 );
2022 text = ::rtl::math::doubleToUString( nTexMem,
2023 rtl_math_StringFormat_F,
2024 2,'.',NULL,' ');
2025 // pad with leading space
2026 while( text.getLength() < 6 )
2027 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2029 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("T: ")) + text;
2031 renderInfoText( text,
2032 Gdiplus::PointF( 0.0, 40) );
2034 VERBOSE_TRACE( "dxcanvas: %f free surface mem, %f free texture mem",
2035 nSurfaceMem, nTexMem );
2038 //////////////////////////////////////////////////////////////////////////////////
2039 // DXRenderModule::renderFPSCounter
2040 //////////////////////////////////////////////////////////////////////////////////
2042 void DXRenderModule::renderFPSCounter() const
2044 ENSURE_OR_THROW( !mnBeginSceneCount,
2045 "DXRenderModule::ren derFPSCounter(): within 3D scene" );
2047 const double denominator( maLastUpdate.getElapsedTime() );
2048 maLastUpdate.reset();
2050 ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator,
2051 rtl_math_StringFormat_F,
2052 2,'.',NULL,' ') );
2054 // pad with leading space
2055 while( text.getLength() < 6 )
2056 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2058 text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps"));
2060 renderInfoText( text,
2061 Gdiplus::PointF() );
2063 VERBOSE_TRACE( "dxcanvas: %f FPS",
2064 denominator == 0.0 ? 100.0 : 1.0/denominator );
2067 //////////////////////////////////////////////////////////////////////////////////
2068 // DXRenderModule::resize
2069 //////////////////////////////////////////////////////////////////////////////////
2071 void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
2073 // TODO(P2): get rid of those fine-grained locking
2074 ::osl::MutexGuard aGuard( maMutex );
2076 if( mhWnd==0 )
2077 return;
2079 // don't do anything if the size didn't change.
2080 if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
2081 maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
2082 return;
2084 // TODO(Q2): use numeric cast to prevent overflow
2085 maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
2086 maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
2088 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
2091 //////////////////////////////////////////////////////////////////////////////////
2092 // DXRenderModule::getPageSize
2093 //////////////////////////////////////////////////////////////////////////////////
2095 ::basegfx::B2IVector DXRenderModule::getPageSize()
2097 // TODO(P2): get rid of those fine-grained locking
2098 ::osl::MutexGuard aGuard( maMutex );
2099 return maPageSize;
2102 ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
2104 // TODO(P2): get rid of those fine-grained locking
2105 ::osl::MutexGuard aGuard( maMutex );
2107 const ::basegfx::B2IVector& rPageSize( getPageSize() );
2108 ::basegfx::B2ISize aSize(surfaceSize);
2109 if(!(aSize.getX()))
2110 aSize.setX(rPageSize.getX());
2111 if(!(aSize.getY()))
2112 aSize.setY(rPageSize.getY());
2114 if(mpTexture.use_count() == 1)
2115 return mpTexture;
2117 return ::canvas::ISurfaceSharedPtr(
2118 new DXSurface(*this,
2119 aSize) );
2122 void DXRenderModule::beginPrimitive( PrimitiveType eType )
2124 // TODO(P2): get rid of those fine-grained locking
2125 ::osl::MutexGuard aGuard( maMutex );
2127 ENSURE_OR_THROW( !mnBeginSceneCount,
2128 "DXRenderModule::beginPrimitive(): nested call" );
2130 ++mnBeginSceneCount;
2131 meType=eType;
2132 mnCount=0;
2135 void DXRenderModule::endPrimitive()
2137 // TODO(P2): get rid of those fine-grained locking
2138 ::osl::MutexGuard aGuard( maMutex );
2140 --mnBeginSceneCount;
2141 meType=PRIMITIVE_TYPE_UNKNOWN;
2142 mnCount=0;
2145 void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
2147 // TODO(P2): get rid of those fine-grained locking
2148 ::osl::MutexGuard aGuard( maMutex );
2150 switch(meType)
2152 case PRIMITIVE_TYPE_TRIANGLE:
2154 maVertexCache.push_back(vertex);
2155 ++mnCount;
2156 mnCount &= 3;
2157 break;
2160 case PRIMITIVE_TYPE_QUAD:
2162 if(mnCount == 3)
2164 const std::size_t size(maVertexCache.size());
2165 ::canvas::Vertex v0(maVertexCache[size-1]);
2166 ::canvas::Vertex v2(maVertexCache[size-3]);
2167 maVertexCache.push_back(v0);
2168 maVertexCache.push_back(vertex);
2169 maVertexCache.push_back(v2);
2170 mnCount=0;
2172 else
2174 maVertexCache.push_back(vertex);
2175 ++mnCount;
2177 break;
2180 default:
2181 OSL_ENSURE( false,
2182 "DXRenderModule::pushVertex(): unexpected primitive types" );
2183 break;
2187 bool DXRenderModule::isError()
2189 // TODO(P2): get rid of those fine-grained locking
2190 ::osl::MutexGuard aGuard( maMutex );
2192 return mbError;
2195 void DXRenderModule::flushVertexCache()
2197 if(!(maVertexCache.size()))
2198 return;
2200 mbError=true;
2202 if( FAILED(mpDirect3DDevice->BeginScene()) )
2203 return;
2205 // enable texture alpha blending
2206 if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE)))
2207 return;
2209 // enable texture alpha modulation, for honoring fAlpha
2210 if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND,
2211 D3DTBLEND_MODULATEALPHA)) )
2212 return;
2214 // enable texture magnification filtering (don't care if this
2215 // fails, it's just visually more pleasant)
2216 mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG,
2217 D3DFILTER_LINEAR);
2219 // enable texture minification filtering (don't care if this
2220 // fails, it's just visually more pleasant)
2221 mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN,
2222 D3DFILTER_LINEAR);
2224 // enable subpixel texture output (don't care if this
2225 // fails, it's just visually more pleasant)
2226 mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SUBPIXEL,
2227 TRUE);
2229 // normal combination of object...
2230 if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,
2231 D3DBLEND_SRCALPHA)) )
2232 return;
2234 // ..and background color
2235 if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,
2236 D3DBLEND_INVSRCALPHA)) )
2237 return;
2239 // disable backface culling; this enables us to mirror sprites
2240 // by simply reverting the triangles, which, with enabled
2241 // culling, would be invisible otherwise
2242 if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE,
2243 D3DCULL_NONE)) )
2244 return;
2246 mbError=false;
2248 const float nHalfPixelSizeX(0.5f/maPageSize.getX());
2249 const float nHalfPixelSizeY(0.5f/maPageSize.getY());
2250 sal_uInt32 nIndex(0);
2251 const std::size_t size(maVertexCache.size());
2252 D3DTLVERTEX *vertices = static_cast<D3DTLVERTEX *>(_alloca(sizeof(D3DTLVERTEX)*size));
2253 vertexCache_t::const_iterator it(maVertexCache.begin());
2254 while(it != maVertexCache.end())
2256 vertices[nIndex++] = D3DTLVERTEX(
2257 D3DVECTOR(static_cast<D3DVALUE>(it->x),
2258 static_cast<D3DVALUE>(it->y),
2259 static_cast<D3DVALUE>(it->z)),
2261 D3DRGBA(1,1,1,it->a),
2262 D3DRGBA(0,0,0,0),
2263 static_cast<float>(it->u + nHalfPixelSizeX),
2264 static_cast<float>(it->v + nHalfPixelSizeY));
2265 ++it;
2268 maVertexCache.clear();
2270 mbError |= FAILED(mpDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
2271 D3DVT_TLVERTEX,
2272 (LPVOID)vertices,
2273 size,
2274 0));
2276 mbError |= FAILED(mpDirect3DDevice->EndScene());
2280 IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
2282 return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
2286 #endif