1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dx_5rm.cxx,v $
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 //////////////////////////////////////////////////////////////////////////////////
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>
77 #include "dx_impltools.hxx"
80 #if defined(DX_DEBUG_IMAGES)
81 # if OSL_DEBUG_LEVEL > 0
88 #undef COMPILE_MULTIMON_STUBS
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 //////////////////////////////////////////////////////////////////////////////////
106 bool doBlit( const ::basegfx::B2IPoint
& rDestPos
,
107 IDirectDrawSurface
& rOutSurface
,
108 const ::basegfx::B2IRange
& rSourceArea
,
109 IDirectDrawSurface
& rSourceSurface
,
111 bool bForceSoftware
)
113 if( !bForceSoftware
)
115 // blit surface to backbuffer
120 rDestPos
.getX() + static_cast<sal_Int32
>(rSourceArea
.getWidth()),
121 rDestPos
.getY() + static_cast<sal_Int32
>(rSourceArea
.getHeight()),
125 rSourceArea
.getMinX(),
126 rSourceArea
.getMinY(),
127 rSourceArea
.getMaxX(),
128 rSourceArea
.getMaxY()
131 if( SUCCEEDED(rOutSurface
.Blt( &aOutRect
,
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
|
152 if(SUCCEEDED(rSourceSurface
.Lock(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
|
165 if(SUCCEEDED(rOutSurface
.Lock(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.
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
++;
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.
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.
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
++;
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
);
277 void dumpSurface( const COMReference
<IDirectDrawSurface
> &pSurface
, const char *szFilename
)
279 if(!(pSurface
.get()))
282 DDSURFACEDESC aSurfaceDesc
;
283 rtl_fillMemory( &aSurfaceDesc
,sizeof(DDSURFACEDESC
),0 );
284 aSurfaceDesc
.dwSize
= sizeof(DDSURFACEDESC
);
286 if( FAILED(pSurface
->Lock( NULL
,
288 DDLOCK_NOSYSLOCK
|DDLOCK_SURFACEMEMORYPTR
|DDLOCK_WAIT
|DDLOCK_READONLY
,
292 const std::size_t dwBitmapSize(aSurfaceDesc
.dwWidth
*aSurfaceDesc
.dwHeight
*4);
293 sal_uInt8
*pBuffer
= static_cast<sal_uInt8
*>(_alloca(dwBitmapSize
));
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
);
340 pSurface
->Unlock(NULL
);
343 void clearSurface( const COMReference
<IDirectDrawSurface
>& pSurface
)
350 rtl_fillMemory( &aBltFx
,
351 sizeof(DDBLTFX
), 0 );
352 aBltFx
.dwSize
= sizeof(DDBLTFX
);
353 aBltFx
.dwFillColor
= 0;
358 DDBLT_COLORFILL
| DDBLT_WAIT
,
362 // Define struct for MonitorEntry
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*/,
382 MonitorList
* pMonitorList
= (MonitorList
*)lpContext
;
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
);
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");
407 LPDIRECTDRAWENUMERATEEX lpDDEnumEx
=
408 (LPDIRECTDRAWENUMERATEEX
)GetProcAddress(hInstance
,"DirectDrawEnumerateExA");
411 lpDDEnumEx( (LPDDENUMCALLBACKEXA
) EnumerateExA_Callback
,
413 DDENUM_ATTACHEDSECONDARYDEVICES
);
415 FreeLibrary(hInstance
);
419 IDirectDraw2
* createDirectDraw( const MonitorList
& rMonitorList
,
420 MONITORINFO
& rMonitorInfo
,
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
;
443 IDirectDraw
* pDirectDraw
;
444 if( FAILED( DirectDrawCreate( gpSelectedDriverGUID
, &pDirectDraw
, NULL
)))
447 IDirectDraw2
* pDirectDraw2
;
448 if( FAILED( pDirectDraw
->QueryInterface( IID_IDirectDraw2
, (LPVOID
*)&pDirectDraw2
)))
451 // queryInterface bumped up the refcount, so release the
452 // reference to the original IDirectDraw interface.
453 pDirectDraw
->Release();
458 HRESULT WINAPI
EnumTextureFormatsCallback( LPDDSURFACEDESC pSurfaceDesc
,
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
)
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
)
495 rtl_copyMemory( pResult
, &pSurfaceDesc
->ddpfPixelFormat
, sizeof(DDPIXELFORMAT
) );
504 class DXRenderModule
;
506 //////////////////////////////////////////////////////////////////////////////////
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
521 DXSurface( DXRenderModule
& rRenderModule
,
522 const ::basegfx::B2ISize
& rSize
);
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();
533 /// Guard local methods against concurrent acces to RenderModule
534 class ImplRenderModuleGuard
: private ::boost::noncopyable
537 explicit inline ImplRenderModuleGuard( DXRenderModule
& rRenderModule
);
538 inline ~ImplRenderModuleGuard();
541 DXRenderModule
& mrRenderModule
;
544 DXRenderModule
& mrRenderModule
;
546 COMReference
<IDirectDrawSurface
> mpSurface
;
547 COMReference
<IDirect3DTexture2
> mpTexture
;
549 ::basegfx::B2IVector maSize
;
552 //////////////////////////////////////////////////////////////////////////////////
554 //////////////////////////////////////////////////////////////////////////////////
556 /// Default implementation of IDXRenderModule
557 class DXRenderModule
: public IDXRenderModule
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()
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()
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;
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
648 static ::osl::Mutex maMutex
;
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
;
673 int mnBeginSceneCount
;
675 const bool mbPageFlipping
;
676 bool mbHasNoTearingBlt
;
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;
706 void fillRect( sal_uInt32
*pDest
,
712 for(sal_uInt32 i
=0; i
<dwWidth
; ++i
)
715 pDest
[((dwHeight
-1)*dwPitch
)+i
]=dwColor
;
718 for(sal_uInt32 j
=0; j
<dwHeight
; ++j
)
721 pDest
[dwWidth
-1]=dwColor
;
726 //////////////////////////////////////////////////////////////////////////////////
727 // DXSurface::DXSurface
728 //////////////////////////////////////////////////////////////////////////////////
730 DXSurface::DXSurface( DXRenderModule
& rRenderModule
,
731 const ::basegfx::B2ISize
& rSize
) :
732 mrRenderModule(rRenderModule
),
737 ImplRenderModuleGuard
aGuard( mrRenderModule
);
739 #ifdef FAKE_MAX_NUMBER_TEXTURES
741 if(gNumSurfaces
>= FAKE_MAX_NUMBER_TEXTURES
)
745 #ifdef FAKE_MAX_TEXTURE_SIZE
746 if(rSize
.getX() > FAKE_MAX_TEXTURE_SIZE
)
748 if(rSize
.getY() > FAKE_MAX_TEXTURE_SIZE
)
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
|
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
);
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
);
786 IDirect3DTexture2
* pTexture
;
787 if( FAILED(pSurface
->QueryInterface(IID_IDirect3DTexture2
, (LPVOID
*)&pTexture
)) )
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
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(),
837 // select texture for next primitive
838 if(FAILED(mrRenderModule
.getDevice()->SetRenderState(
839 D3DRENDERSTATE_TEXTUREHANDLE
,aTextureHandle
)))
844 #if defined(DX_DEBUG_IMAGES)
845 # if OSL_DEBUG_LEVEL > 0
848 DDSURFACEDESC aSurfaceDesc
;
849 rtl_fillMemory( &aSurfaceDesc
,sizeof(DDSURFACEDESC
),0 );
850 aSurfaceDesc
.dwSize
= sizeof(DDSURFACEDESC
);
852 if( SUCCEEDED(mpSurface
->Lock( NULL
,
854 DDLOCK_NOSYSLOCK
|DDLOCK_SURFACEMEMORYPTR
|DDLOCK_WAIT
|DDLOCK_READONLY
,
857 imdebug( "rgba w=%d h=%d %p",
858 aSurfaceDesc
.dwWidth
,
859 aSurfaceDesc
.dwHeight
,
860 aSurfaceDesc
.lpSurface
);
862 mpSurface
->Unlock(NULL
);
871 //////////////////////////////////////////////////////////////////////////////////
872 // DXSurface::isValid
873 //////////////////////////////////////////////////////////////////////////////////
875 bool DXSurface::isValid()
877 ImplRenderModuleGuard
aGuard( mrRenderModule
);
879 if(!(mpSurface
.is()))
882 if(mpSurface
->IsLost() == DDERR_SURFACELOST
)
884 mpSurface
->Restore();
891 //////////////////////////////////////////////////////////////////////////////////
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...
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
,
913 DDLOCK_NOSYSLOCK
|DDLOCK_SURFACEMEMORYPTR
|DDLOCK_WAIT
|DDLOCK_WRITEONLY
,
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
;
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];
974 *pDstScanline
++ = color
;
977 pDst
+= aSurfaceDesc
.lPitch
;
978 pImage
+= nSourcePitchInBytes
;
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
;
1011 ENSURE_OR_RETURN(false,
1012 "DXSurface::update(): Unknown/unimplemented buffer format" );
1019 return SUCCEEDED(mpSurface
->Unlock(NULL
));
1022 //////////////////////////////////////////////////////////////////////////////////
1023 // DXSurface::getSize
1024 //////////////////////////////////////////////////////////////////////////////////
1026 ::basegfx::B2IVector
DXSurface::getSize()
1031 //////////////////////////////////////////////////////////////////////////////////
1032 // DXRenderModule::DXRenderModule
1033 //////////////////////////////////////////////////////////////////////////////////
1035 DXRenderModule::DXRenderModule( const ::Window
& rWindow
) :
1039 maSelectedFullscreenMode(),
1044 mpBackBufferSurface(),
1051 mnBeginSceneCount(0),
1052 mbPageFlipping( false ),
1053 mbHasNoTearingBlt( false ),
1055 meType( PRIMITIVE_TYPE_UNKNOWN
),
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(
1073 static_cast<sal_uInt32
>(maDeviceDesc
.dwMaxTextureWidth
),
1074 static_cast<sal_uInt32
>(MAX_TEXTURE_SIZE
)),
1076 static_cast<sal_uInt32
>(maDeviceDesc
.dwMaxTextureHeight
),
1077 static_cast<sal_uInt32
>(MAX_TEXTURE_SIZE
)));
1080 mpTexture
= ::canvas::ISurfaceSharedPtr(
1081 new DXSurface(*this,aPageSize
));
1082 if(mpTexture
->isValid())
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);
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())
1158 // go defunct, and exit
1159 VERBOSE_TRACE( "Device::Device(): GetCaps failed" );
1160 mpDirectDraw
.reset();
1164 if( !validateCaps() )
1166 // go defunct, and exit
1167 VERBOSE_TRACE( "Device::Device(): Insufficient DirectX capabilities, failed" );
1168 mpDirectDraw
.reset();
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();
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();
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();
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();
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();
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();
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();
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();
1300 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1304 // no chance, go defunct, and exit
1305 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1306 mpPrimarySurface
.reset();
1307 mpDirectDraw
.reset();
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();
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" );
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" );
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" );
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
);
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
1457 // done; successfully
1462 VERBOSE_TRACE( "Device::setup3DDevice(): SetCurrentViewport failed" );
1467 VERBOSE_TRACE( "Device::setup3DDevice(): SetViewport2 failed" );
1472 VERBOSE_TRACE( "Device::setup3DDevice(): AddViewport failed" );
1475 pViewport
->Release();
1479 VERBOSE_TRACE( "Device::setup3DDevice(): CreateViewport failed" );
1484 VERBOSE_TRACE( "Device::setup3DDevice(): No supported pixelformat" );
1489 VERBOSE_TRACE( "Device::setup3DDevice(): EnumTextureFormats failed" );
1492 // go defunct, and exit
1493 mpDirect3DDevice
.reset();
1499 //////////////////////////////////////////////////////////////////////////////////
1500 // DXRenderModule::queryCaps
1501 //////////////////////////////////////////////////////////////////////////////////
1503 bool DXRenderModule::queryCaps()
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
,
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 ) );
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
1543 // setup query struct
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
)))
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
)
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
);
1575 //////////////////////////////////////////////////////////////////////////////////
1576 // DXRenderModule::getAvailableSurfaceMem
1577 //////////////////////////////////////////////////////////////////////////////////
1579 std::size_t DXRenderModule::getAvailableSurfaceMem( bool bWithAGPMem
) const
1581 if( !mpDirectDraw
.is() )
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
)) )
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
)) )
1609 //////////////////////////////////////////////////////////////////////////////////
1610 // DXRenderModule::getAvailableTextureMem
1611 //////////////////////////////////////////////////////////////////////////////////
1613 std::size_t DXRenderModule::getAvailableTextureMem( bool bWithAGPMem
) const
1615 if( !mpDirectDraw
.is() )
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
)) )
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
)) )
1642 // TODO(F1): Add pool mem
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
);
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()))
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)
1742 renderMemAvailable();
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
1750 if( SUCCEEDED(mpPrimarySurface
->Flip( NULL
, DDFLIP_WAIT
)) )
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
);
1766 if( !::canvas::tools::clipBlit( aSourceArea
,
1770 return true; // fully clipped, but still, in a way,
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
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
,
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
;
1815 if( doBlit( aDestPoint
,
1818 *mpBackBufferSurface
,
1821 #if defined(VERBOSE) && defined(DBG_UTIL)
1823 renderMemAvailable();
1832 //////////////////////////////////////////////////////////////////////////////////
1833 // DXRenderModule::disposing
1834 //////////////////////////////////////////////////////////////////////////////////
1836 void DXRenderModule::disposing()
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
1851 //////////////////////////////////////////////////////////////////////////////////
1852 // DXRenderModule::screenshot
1853 //////////////////////////////////////////////////////////////////////////////////
1855 void DXRenderModule::screenShot()
1857 if(!(mpBackBufferSurface
.get()))
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()))
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
)) )
1921 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1926 VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
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();
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
1958 pGraphics
= createSurfaceGraphics( mpBackBufferSurface
);
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
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
,
1988 pGraphics
->DrawString( reinterpret_cast<LPCWSTR
>(rStr
.getStr()),
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
,
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
,
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
,
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
);
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()))
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
);
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
);
2110 aSize
.setX(rPageSize
.getX());
2112 aSize
.setY(rPageSize
.getY());
2114 if(mpTexture
.use_count() == 1)
2117 return ::canvas::ISurfaceSharedPtr(
2118 new DXSurface(*this,
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
;
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
;
2145 void DXRenderModule::pushVertex( const ::canvas::Vertex
& vertex
)
2147 // TODO(P2): get rid of those fine-grained locking
2148 ::osl::MutexGuard
aGuard( maMutex
);
2152 case PRIMITIVE_TYPE_TRIANGLE
:
2154 maVertexCache
.push_back(vertex
);
2160 case PRIMITIVE_TYPE_QUAD
:
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
);
2174 maVertexCache
.push_back(vertex
);
2182 "DXRenderModule::pushVertex(): unexpected primitive types" );
2187 bool DXRenderModule::isError()
2189 // TODO(P2): get rid of those fine-grained locking
2190 ::osl::MutexGuard
aGuard( maMutex
);
2195 void DXRenderModule::flushVertexCache()
2197 if(!(maVertexCache
.size()))
2202 if( FAILED(mpDirect3DDevice
->BeginScene()) )
2205 // enable texture alpha blending
2206 if( FAILED(mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE
,TRUE
)))
2209 // enable texture alpha modulation, for honoring fAlpha
2210 if( FAILED(mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND
,
2211 D3DTBLEND_MODULATEALPHA
)) )
2214 // enable texture magnification filtering (don't care if this
2215 // fails, it's just visually more pleasant)
2216 mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_TEXTUREMAG
,
2219 // enable texture minification filtering (don't care if this
2220 // fails, it's just visually more pleasant)
2221 mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_TEXTUREMIN
,
2224 // enable subpixel texture output (don't care if this
2225 // fails, it's just visually more pleasant)
2226 mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_SUBPIXEL
,
2229 // normal combination of object...
2230 if( FAILED(mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_SRCBLEND
,
2231 D3DBLEND_SRCALPHA
)) )
2234 // ..and background color
2235 if( FAILED(mpDirect3DDevice
->SetRenderState(D3DRENDERSTATE_DESTBLEND
,
2236 D3DBLEND_INVSRCALPHA
)) )
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
,
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
),
2263 static_cast<float>(it
->u
+ nHalfPixelSizeX
),
2264 static_cast<float>(it
->v
+ nHalfPixelSizeY
));
2268 maVertexCache
.clear();
2270 mbError
|= FAILED(mpDirect3DDevice
->DrawPrimitive(D3DPT_TRIANGLELIST
,
2276 mbError
|= FAILED(mpDirect3DDevice
->EndScene());
2280 IDXRenderModuleSharedPtr
createRenderModule( const ::Window
& rParent
)
2282 return IDXRenderModuleSharedPtr( new DXRenderModule(rParent
) );