CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / canvas / source / directx / dx_9rm.cxx
blob6a2d218e936c2d261d1c33920f23ede910ac10f6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
31 #if DIRECTX_VERSION == 0x0900
33 #define MAX_TEXTURE_SIZE (2048)
34 #define MIN_TEXTURE_SIZE (32)
35 //#define FAKE_MAX_NUMBER_TEXTURES (2)
36 //#define FAKE_MAX_TEXTURE_SIZE (4096)
38 #define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal
39 // vertex buffer (must be divisable
40 // by 3, as each triangle primitive
41 // has 3 vertices)
44 //////////////////////////////////////////////////////////////////////////////////
45 // includes
46 //////////////////////////////////////////////////////////////////////////////////
47 #include <vcl/syschild.hxx>
48 #include <vcl/window.hxx>
50 #include <canvas/debug.hxx>
51 #include <canvas/verbosetrace.hxx>
52 #include <tools/diagnose_ex.h>
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 <basegfx/numeric/ftools.hxx>
60 #include <basegfx/vector/b2dsize.hxx>
61 #include <basegfx/vector/b2isize.hxx>
62 #include <basegfx/point/b2ipoint.hxx>
63 #include <basegfx/range/b2irectangle.hxx>
64 #include <boost/scoped_ptr.hpp>
65 #include <com/sun/star/lang/NoSupportException.hpp>
67 #include "dx_rendermodule.hxx"
68 #include "dx_config.hxx"
70 #undef WB_LEFT
71 #undef WB_RIGHT
73 #include "dx_impltools.hxx"
74 #include <vcl/sysdata.hxx>
76 #if defined(DX_DEBUG_IMAGES)
77 # if OSL_DEBUG_LEVEL > 0
78 # include <imdebug.h>
79 # undef min
80 # undef max
81 # endif
82 #endif
84 using namespace ::com::sun::star;
86 //////////////////////////////////////////////////////////////////////////////////
87 // 'dxcanvas' namespace
88 //////////////////////////////////////////////////////////////////////////////////
90 namespace dxcanvas
92 namespace
94 //////////////////////////////////////////////////////////////////////////////////
95 // monitorSupport
96 //////////////////////////////////////////////////////////////////////////////////
98 class monitorSupport
100 public:
102 monitorSupport() :
103 mhLibrary(LoadLibrary("user32.dll")),
104 mpMonitorFromWindow(NULL)
106 if(mhLibrary)
107 mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>(
108 GetProcAddress(
109 mhLibrary,"MonitorFromWindow"));
112 ~monitorSupport()
114 if(mhLibrary)
115 FreeLibrary(mhLibrary);
116 mhLibrary=0;
119 HMONITOR MonitorFromWindow( HWND hwnd )
121 // return adapter_default in case something went wrong...
122 if(!(mpMonitorFromWindow))
123 return HMONITOR(0);
124 // MONITOR_DEFAULTTONEAREST
125 const DWORD dwFlags(0x00000002);
126 return mpMonitorFromWindow(hwnd,dwFlags);
128 private:
130 HINSTANCE mhLibrary;
131 typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags );
132 fMonitorFromWindow mpMonitorFromWindow;
135 monitorSupport aMonitorSupport;
138 class DXRenderModule;
140 //////////////////////////////////////////////////////////////////////////////////
141 // DXSurface
142 //////////////////////////////////////////////////////////////////////////////////
144 /** ISurface implemenation.
146 @attention holds the DXRenderModule via non-refcounted
147 reference! This is safe with current state of affairs, since
148 the canvas::PageManager holds surface and render module via
149 shared_ptr (and makes sure all surfaces are deleted before its
150 render module member goes out of scope).
152 class DXSurface : public canvas::ISurface
154 public:
155 DXSurface( DXRenderModule& rRenderModule,
156 const ::basegfx::B2ISize& rSize );
157 ~DXSurface();
159 virtual bool selectTexture();
160 virtual bool isValid();
161 virtual bool update( const ::basegfx::B2IPoint& rDestPos,
162 const ::basegfx::B2IRange& rSourceRect,
163 ::canvas::IColorBuffer& rSource );
164 virtual ::basegfx::B2IVector getSize();
165 COMReference<IDirect3DTexture9> getTexture() const;
167 private:
168 /// Guard local methods against concurrent acces to RenderModule
169 class ImplRenderModuleGuard : private ::boost::noncopyable
171 public:
172 explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
173 inline ~ImplRenderModuleGuard();
175 private:
176 DXRenderModule& mrRenderModule;
179 DXRenderModule& mrRenderModule;
180 COMReference<IDirect3DTexture9> mpTexture;
182 ::basegfx::B2IVector maSize;
186 //////////////////////////////////////////////////////////////////////////////////
187 // DXRenderModule
188 //////////////////////////////////////////////////////////////////////////////////
190 /// Default implementation of IDXRenderModule
191 class DXRenderModule : public IDXRenderModule
193 public:
194 explicit DXRenderModule( const ::Window& rWindow );
195 ~DXRenderModule();
197 virtual void lock() const { maMutex.acquire(); }
198 virtual void unlock() const { maMutex.release(); }
200 virtual COMReference<IDirect3DSurface9>
201 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
202 virtual void disposing();
203 virtual HWND getHWND() const { return mhWnd; }
204 virtual void screenShot();
206 virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
207 const ::basegfx::B2IRectangle& rCurrWindowArea );
209 virtual void resize( const ::basegfx::B2IRange& rect );
210 virtual ::basegfx::B2IVector getPageSize();
211 virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
212 virtual void beginPrimitive( PrimitiveType eType );
213 virtual void endPrimitive();
214 virtual void pushVertex( const ::canvas::Vertex& vertex );
215 virtual bool isError();
217 COMReference<IDirect3DDevice9> getDevice() { return mpDevice; }
219 void flushVertexCache();
220 void commitVertexCache();
222 private:
224 bool create( const ::Window& rWindow );
225 bool createDevice();
226 bool verifyDevice( const UINT nAdapter );
227 UINT getAdapterFromWindow();
229 /** This object represents the DirectX state machine. In order
230 to serialize access to DirectX's global state, a global
231 mutex is required.
233 static ::osl::Mutex maMutex;
235 HWND mhWnd;
236 COMReference<IDirect3DDevice9> mpDevice;
237 COMReference<IDirect3D9> mpDirect3D9;
238 COMReference<IDirect3DSwapChain9> mpSwapChain;
239 COMReference<IDirect3DVertexBuffer9> mpVertexBuffer;
240 ::canvas::ISurfaceSharedPtr mpTexture;
241 ::boost::scoped_ptr<SystemChildWindow> mpWindow;
242 ::basegfx::B2IVector maSize;
243 typedef std::vector<canvas::Vertex> vertexCache_t;
244 vertexCache_t maVertexCache;
245 std::size_t mnCount;
246 int mnBeginSceneCount;
247 bool mbCanUseDynamicTextures;
248 bool mbError;
249 PrimitiveType meType;
250 ::basegfx::B2IVector maPageSize;
251 D3DPRESENT_PARAMETERS mad3dpp;
253 inline bool isDisposed() const { return (mhWnd==NULL); }
255 struct dxvertex
257 float x,y,z,rhw;
258 DWORD diffuse;
259 float u,v;
262 std::size_t maNumVertices;
263 std::size_t maWriteIndex;
264 std::size_t maReadIndex;
267 ::osl::Mutex DXRenderModule::maMutex;
269 //////////////////////////////////////////////////////////////////////////////////
270 // DXSurface::ImplRenderModuleGuard
271 //////////////////////////////////////////////////////////////////////////////////
273 inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
274 DXRenderModule& rRenderModule ) :
275 mrRenderModule( rRenderModule )
277 mrRenderModule.lock();
280 inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
282 mrRenderModule.unlock();
285 #ifdef FAKE_MAX_NUMBER_TEXTURES
286 static sal_uInt32 gNumSurfaces = 0;
287 #endif
289 void fillRect( sal_uInt32 *pDest,
290 sal_uInt32 dwWidth,
291 sal_uInt32 dwHeight,
292 sal_uInt32 dwPitch,
293 sal_uInt32 dwColor )
295 for(sal_uInt32 i=0; i<dwWidth; ++i)
297 pDest[i]=dwColor;
298 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
301 for(sal_uInt32 j=0; j<dwHeight; ++j)
303 pDest[0]=dwColor;
304 pDest[dwWidth-1]=dwColor;
305 pDest += dwPitch;
309 //////////////////////////////////////////////////////////////////////////////////
310 // DXSurface::DXSurface
311 //////////////////////////////////////////////////////////////////////////////////
313 DXSurface::DXSurface( DXRenderModule& rRenderModule,
314 const ::basegfx::B2ISize& rSize ) :
315 mrRenderModule(rRenderModule),
316 mpTexture(NULL),
317 maSize()
319 ImplRenderModuleGuard aGuard( mrRenderModule );
321 #ifdef FAKE_MAX_NUMBER_TEXTURES
322 ++gNumSurfaces;
323 if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
324 return;
325 #endif
327 #ifdef FAKE_MAX_TEXTURE_SIZE
328 if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
329 return;
330 if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
331 return;
332 #endif
334 ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
335 "DXSurface::DXSurface(): request for zero-sized surface");
337 COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
339 IDirect3DTexture9 *pTexture(NULL);
340 if(FAILED(pDevice->CreateTexture(
341 rSize.getX(),
342 rSize.getY(),
343 1,0,D3DFMT_A8R8G8B8,
344 D3DPOOL_MANAGED,
345 &pTexture,NULL)))
346 return;
348 mpTexture=COMReference<IDirect3DTexture9>(pTexture);
349 maSize = rSize;
352 //////////////////////////////////////////////////////////////////////////////////
353 // DXSurface::~DXSurface
354 //////////////////////////////////////////////////////////////////////////////////
356 DXSurface::~DXSurface()
358 ImplRenderModuleGuard aGuard( mrRenderModule );
360 #ifdef FAKE_MAX_NUMBER_TEXTURES
361 gNumSurfaces--;
362 #endif
365 //////////////////////////////////////////////////////////////////////////////////
366 // DXSurface::selectTexture
367 //////////////////////////////////////////////////////////////////////////////////
369 bool DXSurface::selectTexture()
371 ImplRenderModuleGuard aGuard( mrRenderModule );
372 mrRenderModule.flushVertexCache();
373 COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice());
375 if( FAILED(pDevice->SetTexture(0,mpTexture.get())) )
376 return false;
378 return true;
381 //////////////////////////////////////////////////////////////////////////////////
382 // DXSurface::isValid
383 //////////////////////////////////////////////////////////////////////////////////
385 bool DXSurface::isValid()
387 ImplRenderModuleGuard aGuard( mrRenderModule );
389 if(!(mpTexture.is()))
390 return false;
391 return true;
394 //////////////////////////////////////////////////////////////////////////////////
395 // DXSurface::update
396 //////////////////////////////////////////////////////////////////////////////////
398 bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
399 const ::basegfx::B2IRange& rSourceRect,
400 ::canvas::IColorBuffer& rSource )
402 ImplRenderModuleGuard aGuard( mrRenderModule );
404 // can't update if surface is not valid, that means
405 // either not existent nor restored...
406 if(!(isValid()))
407 return false;
409 D3DLOCKED_RECT aLockedRect;
410 RECT rect;
411 rect.left = std::max(sal_Int32(0),rDestPos.getX());
412 rect.top = std::max(sal_Int32(0),rDestPos.getY());
413 // to avoid interpolation artifacts from other textures,
414 // the surface manager allocates one pixel gap between
415 // them. Clear that to transparent.
416 rect.right = std::min(maSize.getX(),
417 rect.left + sal_Int32(rSourceRect.getWidth()+1));
418 rect.bottom = std::min(maSize.getY(),
419 rect.top + sal_Int32(rSourceRect.getHeight()+1));
420 const bool bClearRightColumn( rect.right < maSize.getX() );
421 const bool bClearBottomRow( rect.bottom < maSize.getY() );
423 if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
425 if(sal_uInt8* pImage = rSource.lock())
427 switch( rSource.getFormat() )
429 case ::canvas::IColorBuffer::FMT_A8R8G8B8:
431 const std::size_t nSourceBytesPerPixel(4);
432 const std::size_t nSourcePitchInBytes(rSource.getStride());
433 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
434 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
436 // calculate the destination memory address
437 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
439 const sal_uInt32 nNumBytesToCopy(
440 static_cast<sal_uInt32>(
441 rSourceRect.getWidth())*
442 nSourceBytesPerPixel);
443 const sal_uInt64 nNumLines(rSourceRect.getHeight());
445 for(sal_uInt32 i=0; i<nNumLines; ++i)
447 rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
449 if( bClearRightColumn )
451 // to avoid interpolation artifacts
452 // from other textures, the surface
453 // manager allocates one pixel gap
454 // between them. Clear that to
455 // transparent.
456 pDst[nNumBytesToCopy] =
457 pDst[nNumBytesToCopy+1] =
458 pDst[nNumBytesToCopy+2] =
459 pDst[nNumBytesToCopy+3] = 0x00;
461 pDst += aLockedRect.Pitch;
462 pImage += nSourcePitchInBytes;
465 if( bClearBottomRow )
466 rtl_zeroMemory(pDst,nNumBytesToCopy+4);
468 break;
470 case ::canvas::IColorBuffer::FMT_R8G8B8:
472 const std::size_t nSourceBytesPerPixel(3);
473 const std::size_t nSourcePitchInBytes(rSource.getStride());
474 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
475 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
477 // calculate the destination memory address
478 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
480 const sal_Int32 nNumColumns(
481 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
482 const sal_Int32 nNumLines(
483 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
484 for(sal_Int32 i=0; i<nNumLines; ++i)
486 sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
487 sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
489 for(sal_Int32 x=0; x<nNumColumns; ++x)
491 sal_uInt32 color(0xFF000000);
492 color |= pSrcScanline[2]<<16;
493 color |= pSrcScanline[1]<<8;
494 color |= pSrcScanline[0];
495 pSrcScanline += 3;
496 *pDstScanline++ = color;
498 if( bClearRightColumn )
499 *pDstScanline++ = 0xFF000000;
501 pDst += aLockedRect.Pitch;
502 pImage += nSourcePitchInBytes;
505 if( bClearBottomRow )
506 rtl_zeroMemory(pDst,4*(nNumColumns+1));
508 break;
510 case ::canvas::IColorBuffer::FMT_X8R8G8B8:
512 const std::size_t nSourceBytesPerPixel(4);
513 const std::size_t nSourcePitchInBytes(rSource.getStride());
514 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
515 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
517 // calculate the destination memory address
518 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
520 const sal_Int32 nNumLines(
521 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
522 const sal_Int32 nNumColumns(
523 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
524 for(sal_Int32 i=0; i<nNumLines; ++i)
526 sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
527 sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
528 for(sal_Int32 j=0; j<nNumColumns; ++j)
529 pDst32[j] = 0xFF000000 | pSrc32[j];
531 if( bClearRightColumn )
532 pDst32[nNumColumns] = 0xFF000000;
534 pDst += aLockedRect.Pitch;
535 pImage += nSourcePitchInBytes;
538 if( bClearBottomRow )
539 rtl_zeroMemory(pDst,4*(nNumColumns+1));
541 break;
543 default:
544 ENSURE_OR_RETURN_FALSE(false,
545 "DXSurface::update(): Unknown/unimplemented buffer format" );
546 break;
549 rSource.unlock();
552 return SUCCEEDED(mpTexture->UnlockRect(0));
555 return true;
558 //////////////////////////////////////////////////////////////////////////////////
559 // DXSurface::getSize
560 //////////////////////////////////////////////////////////////////////////////////
562 ::basegfx::B2IVector DXSurface::getSize()
564 return maSize;
567 COMReference<IDirect3DTexture9> DXSurface::getTexture() const
569 return mpTexture;
572 //////////////////////////////////////////////////////////////////////////////////
573 // DXRenderModule::DXRenderModule
574 //////////////////////////////////////////////////////////////////////////////////
576 DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
577 mhWnd(0),
578 mpDevice(),
579 mpDirect3D9(),
580 mpSwapChain(),
581 mpVertexBuffer(),
582 mpTexture(),
583 maSize(),
584 maVertexCache(),
585 mnCount(0),
586 mnBeginSceneCount(0),
587 mbCanUseDynamicTextures(false),
588 mbError( false ),
589 meType( PRIMITIVE_TYPE_UNKNOWN ),
590 maPageSize(),
591 mad3dpp(),
592 maNumVertices( VERTEX_BUFFER_SIZE ),
593 maWriteIndex(0),
594 maReadIndex(0)
596 // TODO(P2): get rid of those fine-grained locking
597 ::osl::MutexGuard aGuard( maMutex );
599 if(!(create(rWindow)))
601 throw lang::NoSupportException(
602 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
603 "Could not create DirectX device!") ),NULL);
606 // allocate a single texture surface which can be used later.
607 // we also use this to calibrate the page size.
608 ::basegfx::B2IVector aPageSize(maPageSize);
609 while(true)
611 mpTexture = ::canvas::ISurfaceSharedPtr(
612 new DXSurface(*this,aPageSize));
613 if(mpTexture->isValid())
614 break;
616 aPageSize.setX(aPageSize.getX()>>1);
617 aPageSize.setY(aPageSize.getY()>>1);
618 if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
619 (aPageSize.getY() < MIN_TEXTURE_SIZE))
621 throw lang::NoSupportException(
622 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
623 "Could not create DirectX device - "
624 "insufficient texture space!") ),NULL);
627 maPageSize=aPageSize;
629 IDirect3DVertexBuffer9 *pVB(NULL);
630 DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
631 if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
632 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
633 aFVF,
634 D3DPOOL_DEFAULT,
635 &pVB,
636 NULL)) )
638 throw lang::NoSupportException(
639 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
640 "Could not create DirectX device - out of memory!")),NULL);
643 mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
646 //////////////////////////////////////////////////////////////////////////////////
647 // DXRenderModule::~DXRenderModule
648 //////////////////////////////////////////////////////////////////////////////////
650 DXRenderModule::~DXRenderModule()
652 disposing();
655 //////////////////////////////////////////////////////////////////////////////////
656 // DXRenderModule::disposing
657 //////////////////////////////////////////////////////////////////////////////////
659 void DXRenderModule::disposing()
661 if(!(mhWnd))
662 return;
664 mpTexture.reset();
665 mpWindow.reset();
666 mhWnd=NULL;
668 // refrain from releasing the DX9 objects. We're the only
669 // ones holding references to them, and it might be
670 // dangerous to destroy the DX9 device, before all other
671 // objects are dead.
674 //////////////////////////////////////////////////////////////////////////////////
675 // DXRenderModule::create
676 //////////////////////////////////////////////////////////////////////////////////
678 bool DXRenderModule::create( const ::Window& rWindow )
680 // TODO(P2): get rid of those fine-grained locking
681 ::osl::MutexGuard aGuard( maMutex );
683 maVertexCache.reserve(1024);
685 mpWindow.reset(
686 new SystemChildWindow(
687 const_cast<Window *>(&rWindow), 0) );
689 // system child window must not receive mouse events
690 mpWindow->SetMouseTransparent( TRUE );
692 // parent should receive paint messages as well
693 // [PARENTCLIPMODE_NOCLIP], the argument is here
694 // passed as plain numeric value since the stupid
695 // define utilizes a USHORT cast.
696 mpWindow->SetParentClipMode(0x0002);
698 // the system child window must not clear its background
699 mpWindow->EnableEraseBackground( sal_False );
701 mpWindow->SetControlForeground();
702 mpWindow->SetControlBackground();
703 mpWindow->EnablePaint(sal_False);
705 const SystemEnvData *pData = mpWindow->GetSystemData();
706 const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
707 mhWnd = const_cast<HWND>(hwnd);
709 ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
710 "DXRenderModule::create() No valid HWND given." );
712 // retrieve position and size of the parent window
713 const ::Size &rSizePixel(rWindow.GetSizePixel());
715 // remember the size of the parent window, since we
716 // need to use this for our child window.
717 maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
718 maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
720 // let the child window cover the same size as the parent window.
721 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
723 // TODO(F2): since we would like to share precious hardware
724 // resources, the direct3d9 object should be global. each new
725 // request for a canvas should only create a new swapchain.
726 mpDirect3D9 = COMReference<IDirect3D9>(
727 Direct3DCreate9(D3D_SDK_VERSION));
728 if(!mpDirect3D9.is())
729 return false;
731 // create a device from the direct3d9 object.
732 if(!(createDevice()))
733 return false;
735 mpWindow->Show();
737 return true;
740 //////////////////////////////////////////////////////////////////////////////////
741 // DXRenderModule::verifyDevice
742 //////////////////////////////////////////////////////////////////////////////////
744 bool DXRenderModule::verifyDevice( const UINT nAdapter )
746 ENSURE_OR_THROW( mpDirect3D9.is(),
747 "DXRenderModule::verifyDevice() No valid device." );
749 // ask direct3d9 about the capabilities of hardware devices on a specific adapter.
750 // here we decide if the underlying hardware of the machine 'is good enough'.
751 // since we only need a tiny little fraction of what could be used, this
752 // is basically a no-op.
753 D3DCAPS9 aCaps;
754 if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
755 return false;
756 if(!(aCaps.MaxTextureWidth))
757 return false;
758 if(!(aCaps.MaxTextureHeight))
759 return false;
760 maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight);
762 // check device against white & blacklist entries
763 D3DADAPTER_IDENTIFIER9 aIdent;
764 if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
765 return false;
767 DXCanvasItem aConfigItem;
768 DXCanvasItem::DeviceInfo aInfo;
769 aInfo.nVendorId = aIdent.VendorId;
770 aInfo.nDeviceId = aIdent.DeviceId;
771 aInfo.nDeviceSubSysId = aIdent.SubSysId;
772 aInfo.nDeviceRevision = aIdent.Revision;
774 aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
775 aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
776 aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
777 aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
779 if( !aConfigItem.isDeviceUsable(aInfo) )
780 return false;
782 if( aConfigItem.isBlacklistCurrentDevice() )
784 aConfigItem.blacklistDevice(aInfo);
785 return false;
788 aConfigItem.adaptMaxTextureSize(maPageSize);
790 mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0;
792 return true;
796 //////////////////////////////////////////////////////////////////////////////////
797 // DXRenderModule::createDevice
798 //////////////////////////////////////////////////////////////////////////////////
800 bool DXRenderModule::createDevice()
802 // we expect that the caller provides us with a valid HWND
803 ENSURE_OR_THROW( IsWindow(mhWnd),
804 "DXRenderModule::createDevice() No valid HWND given." );
806 // we expect that the caller already created the direct3d9 object.
807 ENSURE_OR_THROW( mpDirect3D9.is(),
808 "DXRenderModule::createDevice() no direct3d?." );
810 // find the adapter identifier from the window.
811 const UINT aAdapter(getAdapterFromWindow());
812 if(aAdapter == static_cast<UINT>(-1))
813 return false;
815 // verify that device possibly works
816 if( !verifyDevice(aAdapter) )
817 return false;
819 // query the display mode from the selected adapter.
820 // we'll later request the backbuffer format to be same
821 // same as the display format.
822 D3DDISPLAYMODE d3ddm;
823 mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
825 // we need to use D3DSWAPEFFECT_COPY here since the canvas-api has
826 // basically nothing to do with efficient resource handling. it tries
827 // to avoid drawing whenevery possible, which is simply not the most
828 // efficient way we could leverage the hardware in this case. it would
829 // be far better to redraw the backbuffer each time we would like to
830 // display the content of the backbuffer, but we need to face reality
831 // here and follow how the canvas was designed.
833 // Strictly speaking, we don't need a full screen worth of
834 // backbuffer here. We could also scale dynamically with
835 // the current window size, but this will make it
836 // necessary to temporarily have two buffers while copying
837 // from the old to the new one. What's more, at the time
838 // we need a larger buffer, DX might not have sufficient
839 // resources available, and we're then left with too small
840 // a back buffer, and no way of falling back to a
841 // different canvas implementation.
842 ZeroMemory( &mad3dpp, sizeof(mad3dpp) );
843 mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()),
844 sal_Int32(d3ddm.Width));
845 mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()),
846 sal_Int32(d3ddm.Height));
847 mad3dpp.BackBufferCount = 1;
848 mad3dpp.Windowed = TRUE;
849 mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
850 mad3dpp.BackBufferFormat = d3ddm.Format;
851 mad3dpp.EnableAutoDepthStencil = FALSE;
852 mad3dpp.hDeviceWindow = mhWnd;
853 mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
855 // now create the device, first try hardware vertex processing,
856 // then software vertex processing. if both queries fail, we give up
857 // and indicate failure.
858 IDirect3DDevice9 *pDevice(NULL);
859 if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
860 D3DDEVTYPE_HAL,
861 mhWnd,
862 D3DCREATE_HARDWARE_VERTEXPROCESSING|
863 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
864 &mad3dpp,
865 &pDevice)))
866 if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
867 D3DDEVTYPE_HAL,
868 mhWnd,
869 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
870 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
871 &mad3dpp,
872 &pDevice)))
873 return false;
875 // got it, store it in a safe place...
876 mpDevice=COMReference<IDirect3DDevice9>(pDevice);
878 // After CreateDevice, the first swap chain already exists, so just get it...
879 IDirect3DSwapChain9 *pSwapChain(NULL);
880 pDevice->GetSwapChain(0,&pSwapChain);
881 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
882 if( !mpSwapChain.is() )
883 return false;
885 // clear the render target [which is the backbuffer in this case].
886 // we are forced to do this once, and furthermore right now.
887 // please note that this is only possible since we created the
888 // backbuffer with copy semantics [the content is preserved after
889 // calls to Present()], which is an unnecessarily expensive operation.
890 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
891 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
892 mpDevice->SetRenderTarget( 0, pBackBuffer );
893 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
894 pBackBuffer->Release();
896 return true;
899 //////////////////////////////////////////////////////////////////////////////////
900 // DXRenderModule::createSystemMemorySurface
901 //////////////////////////////////////////////////////////////////////////////////
903 COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
905 if(isDisposed())
906 return COMReference<IDirect3DSurface9>(NULL);
908 // please note that D3DFMT_X8R8G8B8 is the only format we're
909 // able to choose here, since GetDC() doesn't support any
910 // other 32bit-format.
911 IDirect3DSurface9 *pSurface(NULL);
912 if( FAILED(mpDevice->CreateOffscreenPlainSurface(
913 rSize.getX(),
914 rSize.getY(),
915 D3DFMT_X8R8G8B8,
916 D3DPOOL_SYSTEMMEM,
917 &pSurface,
918 NULL)) )
920 throw lang::NoSupportException(
921 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
922 "Could not create offscreen surface - out of mem!") ),NULL);
925 return COMReference<IDirect3DSurface9>(pSurface);
928 //////////////////////////////////////////////////////////////////////////////////
929 // DXRenderModule::flip
930 //////////////////////////////////////////////////////////////////////////////////
932 bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
933 const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ )
935 // TODO(P2): get rid of those fine-grained locking
936 ::osl::MutexGuard aGuard( maMutex );
938 if(isDisposed() || !mpSwapChain.is())
939 return false;
941 flushVertexCache();
943 // TODO(P2): Might be faster to actually pass update area here
944 RECT aRect =
946 rUpdateArea.getMinX(),
947 rUpdateArea.getMinY(),
948 rUpdateArea.getMaxX(),
949 rUpdateArea.getMaxY()
951 HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0));
952 if(FAILED(hr))
954 if(hr != D3DERR_DEVICELOST)
955 return false;
957 // interestingly enough, sometimes the Reset() below
958 // *still* causes DeviceLost errors. So, cycle until
959 // DX was kind enough to really reset the device...
962 mpVertexBuffer.reset();
963 hr = mpDevice->Reset(&mad3dpp);
964 if(SUCCEEDED(hr))
966 IDirect3DVertexBuffer9 *pVB(NULL);
967 DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
968 if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
969 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
970 aFVF,
971 D3DPOOL_DEFAULT,
972 &pVB,
973 NULL)) )
975 throw lang::NoSupportException(
976 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
977 "Could not create DirectX device - out of memory!")),NULL);
979 mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
981 // retry after the restore
982 if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)))
983 return true;
986 TimeValue aTimeout;
987 aTimeout.Seconds=1;
988 aTimeout.Nanosec=0;
989 osl_waitThread(&aTimeout);
991 while(hr == D3DERR_DEVICELOST);
993 return false;
996 return true;
999 //////////////////////////////////////////////////////////////////////////////////
1000 // DXRenderModule::screenShot
1001 //////////////////////////////////////////////////////////////////////////////////
1003 void DXRenderModule::screenShot()
1007 //////////////////////////////////////////////////////////////////////////////////
1008 // DXRenderModule::resize
1009 //////////////////////////////////////////////////////////////////////////////////
1011 void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
1013 // TODO(P2): get rid of those fine-grained locking
1014 ::osl::MutexGuard aGuard( maMutex );
1016 if(isDisposed())
1017 return;
1019 // don't do anything if the size didn't change.
1020 if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
1021 maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
1022 return;
1024 // TODO(Q2): use numeric cast to prevent overflow
1025 maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
1026 maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
1028 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1030 // resize back buffer, if necessary
1031 // -------------------------------------------------------------
1033 // don't attempt to create anything if the
1034 // requested size is NULL.
1035 if(!(maSize.getX()))
1036 return;
1037 if(!(maSize.getY()))
1038 return;
1040 // backbuffer too small (might happen, if window is
1041 // maximized across multiple monitors)
1042 if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() ||
1043 sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() )
1045 mad3dpp.BackBufferWidth = maSize.getX();
1046 mad3dpp.BackBufferHeight = maSize.getY();
1048 // clear before, save resources
1049 mpSwapChain.reset();
1051 IDirect3DSwapChain9 *pSwapChain(NULL);
1052 if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain)))
1053 return;
1054 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
1056 // clear the render target [which is the backbuffer in this case].
1057 // we are forced to do this once, and furthermore right now.
1058 // please note that this is only possible since we created the
1059 // backbuffer with copy semantics [the content is preserved after
1060 // calls to Present()], which is an unnecessarily expensive operation.
1061 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
1062 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
1063 mpDevice->SetRenderTarget( 0, pBackBuffer );
1064 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
1065 pBackBuffer->Release();
1069 //////////////////////////////////////////////////////////////////////////////////
1070 // DXRenderModule::getPageSize
1071 //////////////////////////////////////////////////////////////////////////////////
1073 ::basegfx::B2IVector DXRenderModule::getPageSize()
1075 // TODO(P2): get rid of those fine-grained locking
1076 ::osl::MutexGuard aGuard( maMutex );
1077 return maPageSize;
1080 //////////////////////////////////////////////////////////////////////////////////
1081 // DXRenderModule::createSurface
1082 //////////////////////////////////////////////////////////////////////////////////
1084 ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
1086 // TODO(P2): get rid of those fine-grained locking
1087 ::osl::MutexGuard aGuard( maMutex );
1089 if(isDisposed())
1090 return ::canvas::ISurfaceSharedPtr();
1092 const ::basegfx::B2IVector& rPageSize( getPageSize() );
1093 ::basegfx::B2ISize aSize(surfaceSize);
1094 if(!(aSize.getX()))
1095 aSize.setX(rPageSize.getX());
1096 if(!(aSize.getY()))
1097 aSize.setY(rPageSize.getY());
1099 if(mpTexture.use_count() == 1)
1100 return mpTexture;
1102 return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) );
1105 //////////////////////////////////////////////////////////////////////////////////
1106 // DXRenderModule::beginPrimitive
1107 //////////////////////////////////////////////////////////////////////////////////
1109 void DXRenderModule::beginPrimitive( PrimitiveType eType )
1111 // TODO(P2): get rid of those fine-grained locking
1112 ::osl::MutexGuard aGuard( maMutex );
1114 if(isDisposed())
1115 return;
1117 ENSURE_OR_THROW( !mnBeginSceneCount,
1118 "DXRenderModule::beginPrimitive(): nested call" );
1120 ++mnBeginSceneCount;
1121 meType=eType;
1122 mnCount=0;
1125 //////////////////////////////////////////////////////////////////////////////////
1126 // DXRenderModule::endPrimitive
1127 //////////////////////////////////////////////////////////////////////////////////
1129 void DXRenderModule::endPrimitive()
1131 // TODO(P2): get rid of those fine-grained locking
1132 ::osl::MutexGuard aGuard( maMutex );
1134 if(isDisposed())
1135 return;
1137 --mnBeginSceneCount;
1138 meType=PRIMITIVE_TYPE_UNKNOWN;
1139 mnCount=0;
1142 //////////////////////////////////////////////////////////////////////////////////
1143 // DXRenderModule::pushVertex
1144 //////////////////////////////////////////////////////////////////////////////////
1146 void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
1148 // TODO(P2): get rid of those fine-grained locking
1149 ::osl::MutexGuard aGuard( maMutex );
1151 if(isDisposed())
1152 return;
1154 switch(meType)
1156 case PRIMITIVE_TYPE_TRIANGLE:
1158 maVertexCache.push_back(vertex);
1159 ++mnCount;
1160 mnCount &= 3;
1161 break;
1164 case PRIMITIVE_TYPE_QUAD:
1166 if(mnCount == 3)
1168 const std::size_t size(maVertexCache.size());
1169 ::canvas::Vertex v0(maVertexCache[size-1]);
1170 ::canvas::Vertex v2(maVertexCache[size-3]);
1171 maVertexCache.push_back(v0);
1172 maVertexCache.push_back(vertex);
1173 maVertexCache.push_back(v2);
1174 mnCount=0;
1176 else
1178 maVertexCache.push_back(vertex);
1179 ++mnCount;
1181 break;
1184 default:
1185 OSL_ENSURE(false,
1186 "DXRenderModule::pushVertex(): unexpected primitive type");
1187 break;
1191 //////////////////////////////////////////////////////////////////////////////////
1192 // DXRenderModule::isError
1193 //////////////////////////////////////////////////////////////////////////////////
1195 bool DXRenderModule::isError()
1197 // TODO(P2): get rid of those fine-grained locking
1198 ::osl::MutexGuard aGuard( maMutex );
1200 return mbError;
1203 //////////////////////////////////////////////////////////////////////////////////
1204 // DXRenderModule::getAdapterFromWindow
1205 //////////////////////////////////////////////////////////////////////////////////
1207 UINT DXRenderModule::getAdapterFromWindow()
1209 HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd));
1210 UINT aAdapterCount(mpDirect3D9->GetAdapterCount());
1211 for(UINT i=0; i<aAdapterCount; ++i)
1212 if(hMonitor == mpDirect3D9->GetAdapterMonitor(i))
1213 return i;
1214 return static_cast<UINT>(-1);
1217 //////////////////////////////////////////////////////////////////////////////////
1218 // DXRenderModule::commitVertexCache
1219 //////////////////////////////////////////////////////////////////////////////////
1221 void DXRenderModule::commitVertexCache()
1223 if(maReadIndex != maWriteIndex)
1225 const std::size_t nVertexStride = sizeof(dxvertex);
1226 const unsigned int nNumVertices = maWriteIndex-maReadIndex;
1227 const unsigned int nNumPrimitives = nNumVertices / 3;
1229 if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride)))
1230 return;
1232 if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1233 return;
1235 if(FAILED(mpDevice->BeginScene()))
1236 return;
1238 mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives));
1239 mbError |= FAILED(mpDevice->EndScene());
1241 maReadIndex += nNumVertices;
1245 //////////////////////////////////////////////////////////////////////////////////
1246 // DXRenderModule::flushVertexCache
1247 //////////////////////////////////////////////////////////////////////////////////
1249 void DXRenderModule::flushVertexCache()
1251 if(!(maVertexCache.size()))
1252 return;
1254 mbError=true;
1256 if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1257 return;
1259 // enable texture alpha blending
1260 if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1261 return;
1263 mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1264 mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1265 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1266 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1268 // configure the fixed-function pipeline.
1269 // the only 'feature' we need here is to modulate the alpha-channels
1270 // from the texture and the interpolated diffuse color. the result
1271 // will then be blended with the backbuffer.
1272 // fragment color = texture color * diffuse.alpha.
1273 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1274 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1275 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1277 // normal combination of object...
1278 if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1279 return;
1281 // ..and background color
1282 if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1283 return;
1285 // disable backface culling; this enables us to mirror sprites
1286 // by simply reverting the triangles, which, with enabled
1287 // culling, would be invisible otherwise
1288 if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1289 return;
1291 mbError=false;
1293 std::size_t nSize(maVertexCache.size());
1294 const std::size_t nVertexStride = sizeof(dxvertex);
1296 const ::basegfx::B2IVector aPageSize(getPageSize());
1297 const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1298 const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1299 vertexCache_t::const_iterator it(maVertexCache.begin());
1301 while( nSize )
1303 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1305 // Check to see if there's space for the current set of
1306 // vertices in the buffer.
1307 if( maNumVertices - maWriteIndex < nSize )
1309 commitVertexCache();
1310 dwLockFlags = D3DLOCK_DISCARD;
1311 maWriteIndex = 0;
1312 maReadIndex = 0;
1315 dxvertex *vertices(NULL);
1316 const std::size_t nNumVertices(
1317 std::min(maNumVertices - maWriteIndex,
1318 nSize));
1319 if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride,
1320 nNumVertices*nVertexStride,
1321 (void **)&vertices,
1322 dwLockFlags)))
1323 return;
1325 std::size_t nIndex(0);
1326 while( nIndex < nNumVertices )
1328 dxvertex &dest = vertices[nIndex++];
1329 dest.x=it->x;
1330 dest.y=it->y;
1331 dest.z=it->z;
1332 dest.rhw=1;
1333 const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f));
1334 dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1335 dest.u=static_cast<float>(it->u + nHalfPixelSizeX);
1336 dest.v=static_cast<float>(it->v + nHalfPixelSizeY);
1337 ++it;
1340 mpVertexBuffer->Unlock();
1342 // Advance to the next position in the vertex buffer.
1343 maWriteIndex += nNumVertices;
1344 nSize -= nNumVertices;
1346 commitVertexCache();
1349 maVertexCache.clear();
1353 //////////////////////////////////////////////////////////////////////////////////
1354 // createRenderModule
1355 //////////////////////////////////////////////////////////////////////////////////
1357 IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
1359 return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
1363 #endif