xref: /trunk/main/canvas/source/directx/dx_9rm.cxx (revision 4772a777d4d7463276afbb9669636e78e1126302)
125ea7f45SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
325ea7f45SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
425ea7f45SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
525ea7f45SAndrew Rist  * distributed with this work for additional information
625ea7f45SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
725ea7f45SAndrew Rist  * to you under the Apache License, Version 2.0 (the
825ea7f45SAndrew Rist  * "License"); you may not use this file except in compliance
925ea7f45SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
1125ea7f45SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
1325ea7f45SAndrew Rist  * Unless required by applicable law or agreed to in writing,
1425ea7f45SAndrew Rist  * software distributed under the License is distributed on an
1525ea7f45SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1625ea7f45SAndrew Rist  * KIND, either express or implied.  See the License for the
1725ea7f45SAndrew Rist  * specific language governing permissions and limitations
1825ea7f45SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
2025ea7f45SAndrew Rist  *************************************************************/
2125ea7f45SAndrew Rist 
2225ea7f45SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_canvas.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #if DIRECTX_VERSION == 0x0900
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #define MAX_TEXTURE_SIZE (2048)
30cdf0e10cSrcweir #define MIN_TEXTURE_SIZE (32)
31cdf0e10cSrcweir //#define FAKE_MAX_NUMBER_TEXTURES (2)
32cdf0e10cSrcweir //#define FAKE_MAX_TEXTURE_SIZE (4096)
33cdf0e10cSrcweir 
34cdf0e10cSrcweir #define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal
35cdf0e10cSrcweir                                    // vertex buffer (must be divisable
36cdf0e10cSrcweir                                    // by 3, as each triangle primitive
37cdf0e10cSrcweir                                    // has 3 vertices)
38cdf0e10cSrcweir 
39cdf0e10cSrcweir 
40cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////////
41cdf0e10cSrcweir // includes
42cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////////
43cdf0e10cSrcweir #include <vcl/syschild.hxx>
44cdf0e10cSrcweir #include <vcl/window.hxx>
45cdf0e10cSrcweir 
46cdf0e10cSrcweir #include <canvas/debug.hxx>
47cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
48cdf0e10cSrcweir #include <tools/diagnose_ex.h>
49cdf0e10cSrcweir 
50cdf0e10cSrcweir #include <canvas/elapsedtime.hxx>
51cdf0e10cSrcweir #include <canvas/canvastools.hxx>
52cdf0e10cSrcweir #include <canvas/rendering/icolorbuffer.hxx>
53cdf0e10cSrcweir #include <canvas/rendering/isurface.hxx>
54cdf0e10cSrcweir #include <canvas/rendering/irendermodule.hxx>
55cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
56cdf0e10cSrcweir #include <basegfx/vector/b2dsize.hxx>
57cdf0e10cSrcweir #include <basegfx/vector/b2isize.hxx>
58cdf0e10cSrcweir #include <basegfx/point/b2ipoint.hxx>
59cdf0e10cSrcweir #include <basegfx/range/b2irectangle.hxx>
60cdf0e10cSrcweir #include <boost/scoped_ptr.hpp>
61cdf0e10cSrcweir #include <com/sun/star/lang/NoSupportException.hpp>
62cdf0e10cSrcweir 
63cdf0e10cSrcweir #include "dx_rendermodule.hxx"
64cdf0e10cSrcweir #include "dx_config.hxx"
65cdf0e10cSrcweir 
66cdf0e10cSrcweir #undef WB_LEFT
67cdf0e10cSrcweir #undef WB_RIGHT
68cdf0e10cSrcweir 
69cdf0e10cSrcweir #include "dx_impltools.hxx"
70cdf0e10cSrcweir #include <vcl/sysdata.hxx>
71cdf0e10cSrcweir 
72cdf0e10cSrcweir #if defined(DX_DEBUG_IMAGES)
73cdf0e10cSrcweir # if OSL_DEBUG_LEVEL > 0
74cdf0e10cSrcweir #  include <imdebug.h>
75cdf0e10cSrcweir #  undef min
76cdf0e10cSrcweir #  undef max
77cdf0e10cSrcweir # endif
78cdf0e10cSrcweir #endif
79cdf0e10cSrcweir 
80cdf0e10cSrcweir using namespace ::com::sun::star;
81cdf0e10cSrcweir 
82cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////////
83cdf0e10cSrcweir // 'dxcanvas' namespace
84cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////////
85cdf0e10cSrcweir 
86cdf0e10cSrcweir namespace dxcanvas
87cdf0e10cSrcweir {
88cdf0e10cSrcweir     namespace
89cdf0e10cSrcweir     {
90cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
91cdf0e10cSrcweir         // monitorSupport
92cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
93cdf0e10cSrcweir 
94cdf0e10cSrcweir         class monitorSupport
95cdf0e10cSrcweir         {
96cdf0e10cSrcweir         public:
97cdf0e10cSrcweir 
monitorSupport()98cdf0e10cSrcweir             monitorSupport() :
99cdf0e10cSrcweir                 mhLibrary(LoadLibrary("user32.dll")),
100cdf0e10cSrcweir                 mpMonitorFromWindow(NULL)
101cdf0e10cSrcweir             {
102cdf0e10cSrcweir                 if(mhLibrary)
103cdf0e10cSrcweir                     mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>(
104cdf0e10cSrcweir                         GetProcAddress(
105cdf0e10cSrcweir                             mhLibrary,"MonitorFromWindow"));
106cdf0e10cSrcweir             }
107cdf0e10cSrcweir 
~monitorSupport()108cdf0e10cSrcweir             ~monitorSupport()
109cdf0e10cSrcweir             {
110cdf0e10cSrcweir                 if(mhLibrary)
111cdf0e10cSrcweir                     FreeLibrary(mhLibrary);
112cdf0e10cSrcweir                 mhLibrary=0;
113cdf0e10cSrcweir             }
114cdf0e10cSrcweir 
MonitorFromWindow(HWND hwnd)115cdf0e10cSrcweir             HMONITOR MonitorFromWindow( HWND hwnd )
116cdf0e10cSrcweir             {
117cdf0e10cSrcweir                 // return adapter_default in case something went wrong...
118cdf0e10cSrcweir                 if(!(mpMonitorFromWindow))
119cdf0e10cSrcweir                     return HMONITOR(0);
120cdf0e10cSrcweir                 // MONITOR_DEFAULTTONEAREST
121cdf0e10cSrcweir                 const DWORD dwFlags(0x00000002);
122cdf0e10cSrcweir                 return mpMonitorFromWindow(hwnd,dwFlags);
123cdf0e10cSrcweir             }
124cdf0e10cSrcweir         private:
125cdf0e10cSrcweir 
126cdf0e10cSrcweir             HINSTANCE mhLibrary;
127cdf0e10cSrcweir             typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags );
128cdf0e10cSrcweir             fMonitorFromWindow mpMonitorFromWindow;
129cdf0e10cSrcweir         };
130cdf0e10cSrcweir 
131cdf0e10cSrcweir         monitorSupport aMonitorSupport;
132cdf0e10cSrcweir 
133cdf0e10cSrcweir 
134cdf0e10cSrcweir         class DXRenderModule;
135cdf0e10cSrcweir 
136cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
137cdf0e10cSrcweir         // DXSurface
138cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
139cdf0e10cSrcweir 
140*4772a777SJohn Bampton         /** ISurface implementation.
141cdf0e10cSrcweir 
142cdf0e10cSrcweir             @attention holds the DXRenderModule via non-refcounted
143cdf0e10cSrcweir             reference! This is safe with current state of affairs, since
144cdf0e10cSrcweir             the canvas::PageManager holds surface and render module via
145cdf0e10cSrcweir             shared_ptr (and makes sure all surfaces are deleted before its
146cdf0e10cSrcweir             render module member goes out of scope).
147cdf0e10cSrcweir         */
148cdf0e10cSrcweir         class DXSurface : public canvas::ISurface
149cdf0e10cSrcweir         {
150cdf0e10cSrcweir         public:
151cdf0e10cSrcweir             DXSurface( DXRenderModule&           rRenderModule,
152cdf0e10cSrcweir                        const ::basegfx::B2ISize& rSize );
153cdf0e10cSrcweir             ~DXSurface();
154cdf0e10cSrcweir 
155cdf0e10cSrcweir             virtual bool selectTexture();
156cdf0e10cSrcweir             virtual bool isValid();
157cdf0e10cSrcweir             virtual bool update( const ::basegfx::B2IPoint& rDestPos,
158cdf0e10cSrcweir                                 const ::basegfx::B2IRange& rSourceRect,
159cdf0e10cSrcweir                                 ::canvas::IColorBuffer&    rSource );
160cdf0e10cSrcweir             virtual ::basegfx::B2IVector getSize();
161cdf0e10cSrcweir             COMReference<IDirect3DTexture9> getTexture() const;
162cdf0e10cSrcweir 
163cdf0e10cSrcweir         private:
16430acf5e8Spfg             /// Guard local methods against concurrent access to RenderModule
165cdf0e10cSrcweir             class ImplRenderModuleGuard : private ::boost::noncopyable
166cdf0e10cSrcweir             {
167cdf0e10cSrcweir             public:
168cdf0e10cSrcweir                 explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
169cdf0e10cSrcweir                 inline ~ImplRenderModuleGuard();
170cdf0e10cSrcweir 
171cdf0e10cSrcweir             private:
172cdf0e10cSrcweir                 DXRenderModule& mrRenderModule;
173cdf0e10cSrcweir             };
174cdf0e10cSrcweir 
175cdf0e10cSrcweir             DXRenderModule&                  mrRenderModule;
176cdf0e10cSrcweir             COMReference<IDirect3DTexture9>  mpTexture;
177cdf0e10cSrcweir 
178cdf0e10cSrcweir             ::basegfx::B2IVector             maSize;
179cdf0e10cSrcweir         };
180cdf0e10cSrcweir 
181cdf0e10cSrcweir 
182cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
183cdf0e10cSrcweir         // DXRenderModule
184cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
185cdf0e10cSrcweir 
186cdf0e10cSrcweir         /// Default implementation of IDXRenderModule
187cdf0e10cSrcweir         class DXRenderModule : public IDXRenderModule
188cdf0e10cSrcweir         {
189cdf0e10cSrcweir         public:
190cdf0e10cSrcweir             explicit DXRenderModule( const ::Window& rWindow );
191cdf0e10cSrcweir             ~DXRenderModule();
192cdf0e10cSrcweir 
lock() const193cdf0e10cSrcweir             virtual void lock() const { maMutex.acquire(); }
unlock() const194cdf0e10cSrcweir             virtual void unlock() const { maMutex.release(); }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir             virtual COMReference<IDirect3DSurface9>
197cdf0e10cSrcweir                 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
198cdf0e10cSrcweir             virtual void disposing();
getHWND() const199cdf0e10cSrcweir             virtual HWND getHWND() const { return mhWnd; }
200cdf0e10cSrcweir             virtual void screenShot();
201cdf0e10cSrcweir 
202cdf0e10cSrcweir             virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
203cdf0e10cSrcweir                                const ::basegfx::B2IRectangle& rCurrWindowArea );
204cdf0e10cSrcweir 
205cdf0e10cSrcweir             virtual void resize( const ::basegfx::B2IRange& rect );
206cdf0e10cSrcweir             virtual ::basegfx::B2IVector getPageSize();
207cdf0e10cSrcweir             virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
208cdf0e10cSrcweir             virtual void beginPrimitive( PrimitiveType eType );
209cdf0e10cSrcweir             virtual void endPrimitive();
210cdf0e10cSrcweir             virtual void pushVertex( const ::canvas::Vertex& vertex );
211cdf0e10cSrcweir             virtual bool isError();
212cdf0e10cSrcweir 
getDevice()213cdf0e10cSrcweir             COMReference<IDirect3DDevice9> getDevice() { return mpDevice; }
214cdf0e10cSrcweir 
215cdf0e10cSrcweir             void flushVertexCache();
216cdf0e10cSrcweir             void commitVertexCache();
217cdf0e10cSrcweir 
218cdf0e10cSrcweir         private:
219cdf0e10cSrcweir 
220cdf0e10cSrcweir             bool create( const ::Window& rWindow );
221cdf0e10cSrcweir             bool createDevice();
222cdf0e10cSrcweir             bool verifyDevice( const UINT nAdapter );
223cdf0e10cSrcweir             UINT getAdapterFromWindow();
224cdf0e10cSrcweir 
225cdf0e10cSrcweir             /** This object represents the DirectX state machine.  In order
226cdf0e10cSrcweir                 to serialize access to DirectX's global state, a global
227cdf0e10cSrcweir                 mutex is required.
228cdf0e10cSrcweir             */
229cdf0e10cSrcweir             static ::osl::Mutex                         maMutex;
230cdf0e10cSrcweir 
231cdf0e10cSrcweir             HWND                                        mhWnd;
232cdf0e10cSrcweir             COMReference<IDirect3DDevice9>              mpDevice;
233cdf0e10cSrcweir             COMReference<IDirect3D9>                    mpDirect3D9;
234cdf0e10cSrcweir             COMReference<IDirect3DSwapChain9>           mpSwapChain;
235cdf0e10cSrcweir             COMReference<IDirect3DVertexBuffer9>        mpVertexBuffer;
236cdf0e10cSrcweir             ::canvas::ISurfaceSharedPtr                 mpTexture;
237cdf0e10cSrcweir             ::boost::scoped_ptr<SystemChildWindow>      mpWindow;
238cdf0e10cSrcweir             ::basegfx::B2IVector                        maSize;
239cdf0e10cSrcweir             typedef std::vector<canvas::Vertex>         vertexCache_t;
240cdf0e10cSrcweir             vertexCache_t                               maVertexCache;
241cdf0e10cSrcweir             std::size_t                                 mnCount;
242cdf0e10cSrcweir             int                                         mnBeginSceneCount;
243cdf0e10cSrcweir             bool                                        mbCanUseDynamicTextures;
244cdf0e10cSrcweir             bool                                        mbError;
245cdf0e10cSrcweir             PrimitiveType                               meType;
246cdf0e10cSrcweir             ::basegfx::B2IVector                        maPageSize;
247cdf0e10cSrcweir             D3DPRESENT_PARAMETERS                       mad3dpp;
248cdf0e10cSrcweir 
isDisposed() const249cdf0e10cSrcweir             inline bool isDisposed() const { return (mhWnd==NULL); }
250cdf0e10cSrcweir 
251cdf0e10cSrcweir             struct dxvertex
252cdf0e10cSrcweir             {
253cdf0e10cSrcweir                 float x,y,z,rhw;
254cdf0e10cSrcweir                 DWORD diffuse;
255cdf0e10cSrcweir                 float u,v;
256cdf0e10cSrcweir             };
257cdf0e10cSrcweir 
258cdf0e10cSrcweir             std::size_t                                 maNumVertices;
259cdf0e10cSrcweir             std::size_t                                 maWriteIndex;
260cdf0e10cSrcweir             std::size_t                                 maReadIndex;
261cdf0e10cSrcweir         };
262cdf0e10cSrcweir 
263cdf0e10cSrcweir         ::osl::Mutex DXRenderModule::maMutex;
264cdf0e10cSrcweir 
265cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
266cdf0e10cSrcweir         // DXSurface::ImplRenderModuleGuard
267cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
268cdf0e10cSrcweir 
ImplRenderModuleGuard(DXRenderModule & rRenderModule)269cdf0e10cSrcweir         inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
270cdf0e10cSrcweir             DXRenderModule& rRenderModule ) :
271cdf0e10cSrcweir             mrRenderModule( rRenderModule )
272cdf0e10cSrcweir         {
273cdf0e10cSrcweir             mrRenderModule.lock();
274cdf0e10cSrcweir         }
275cdf0e10cSrcweir 
~ImplRenderModuleGuard()276cdf0e10cSrcweir         inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
277cdf0e10cSrcweir         {
278cdf0e10cSrcweir             mrRenderModule.unlock();
279cdf0e10cSrcweir         }
280cdf0e10cSrcweir 
281cdf0e10cSrcweir #ifdef FAKE_MAX_NUMBER_TEXTURES
282cdf0e10cSrcweir         static sal_uInt32 gNumSurfaces = 0;
283cdf0e10cSrcweir #endif
284cdf0e10cSrcweir 
fillRect(sal_uInt32 * pDest,sal_uInt32 dwWidth,sal_uInt32 dwHeight,sal_uInt32 dwPitch,sal_uInt32 dwColor)285cdf0e10cSrcweir         void fillRect( sal_uInt32 *pDest,
286cdf0e10cSrcweir                        sal_uInt32 dwWidth,
287cdf0e10cSrcweir                        sal_uInt32 dwHeight,
288cdf0e10cSrcweir                        sal_uInt32 dwPitch,
289cdf0e10cSrcweir                        sal_uInt32 dwColor )
290cdf0e10cSrcweir         {
291cdf0e10cSrcweir             for(sal_uInt32 i=0; i<dwWidth; ++i)
292cdf0e10cSrcweir             {
293cdf0e10cSrcweir                 pDest[i]=dwColor;
294cdf0e10cSrcweir                 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
295cdf0e10cSrcweir             }
296cdf0e10cSrcweir 
297cdf0e10cSrcweir             for(sal_uInt32 j=0; j<dwHeight; ++j)
298cdf0e10cSrcweir             {
299cdf0e10cSrcweir                 pDest[0]=dwColor;
300cdf0e10cSrcweir                 pDest[dwWidth-1]=dwColor;
301cdf0e10cSrcweir                 pDest += dwPitch;
302cdf0e10cSrcweir             }
303cdf0e10cSrcweir         }
304cdf0e10cSrcweir 
305cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
306cdf0e10cSrcweir         // DXSurface::DXSurface
307cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
308cdf0e10cSrcweir 
DXSurface(DXRenderModule & rRenderModule,const::basegfx::B2ISize & rSize)309cdf0e10cSrcweir         DXSurface::DXSurface( DXRenderModule&           rRenderModule,
310cdf0e10cSrcweir                               const ::basegfx::B2ISize& rSize ) :
311cdf0e10cSrcweir             mrRenderModule(rRenderModule),
312cdf0e10cSrcweir             mpTexture(NULL),
313cdf0e10cSrcweir             maSize()
314cdf0e10cSrcweir         {
315cdf0e10cSrcweir             ImplRenderModuleGuard aGuard( mrRenderModule );
316cdf0e10cSrcweir 
317cdf0e10cSrcweir #ifdef FAKE_MAX_NUMBER_TEXTURES
318cdf0e10cSrcweir             ++gNumSurfaces;
319cdf0e10cSrcweir             if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
320cdf0e10cSrcweir                 return;
321cdf0e10cSrcweir #endif
322cdf0e10cSrcweir 
323cdf0e10cSrcweir #ifdef FAKE_MAX_TEXTURE_SIZE
324cdf0e10cSrcweir             if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
325cdf0e10cSrcweir                 return;
326cdf0e10cSrcweir             if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
327cdf0e10cSrcweir                 return;
328cdf0e10cSrcweir #endif
329cdf0e10cSrcweir 
330cdf0e10cSrcweir             ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
331cdf0e10cSrcweir                             "DXSurface::DXSurface(): request for zero-sized surface");
332cdf0e10cSrcweir 
333cdf0e10cSrcweir             COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
334cdf0e10cSrcweir 
335cdf0e10cSrcweir             IDirect3DTexture9 *pTexture(NULL);
336cdf0e10cSrcweir             if(FAILED(pDevice->CreateTexture(
337cdf0e10cSrcweir                 rSize.getX(),
338cdf0e10cSrcweir                 rSize.getY(),
339cdf0e10cSrcweir                 1,0,D3DFMT_A8R8G8B8,
340cdf0e10cSrcweir                 D3DPOOL_MANAGED,
341cdf0e10cSrcweir                 &pTexture,NULL)))
342cdf0e10cSrcweir                 return;
343cdf0e10cSrcweir 
344cdf0e10cSrcweir             mpTexture=COMReference<IDirect3DTexture9>(pTexture);
345cdf0e10cSrcweir             maSize = rSize;
346cdf0e10cSrcweir         }
347cdf0e10cSrcweir 
348cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
349cdf0e10cSrcweir         // DXSurface::~DXSurface
350cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
351cdf0e10cSrcweir 
~DXSurface()352cdf0e10cSrcweir         DXSurface::~DXSurface()
353cdf0e10cSrcweir         {
354cdf0e10cSrcweir             ImplRenderModuleGuard aGuard( mrRenderModule );
355cdf0e10cSrcweir 
356cdf0e10cSrcweir #ifdef FAKE_MAX_NUMBER_TEXTURES
357cdf0e10cSrcweir             gNumSurfaces--;
358cdf0e10cSrcweir #endif
359cdf0e10cSrcweir         }
360cdf0e10cSrcweir 
361cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
362cdf0e10cSrcweir         // DXSurface::selectTexture
363cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
364cdf0e10cSrcweir 
selectTexture()365cdf0e10cSrcweir         bool DXSurface::selectTexture()
366cdf0e10cSrcweir         {
367cdf0e10cSrcweir             ImplRenderModuleGuard aGuard( mrRenderModule );
368cdf0e10cSrcweir             mrRenderModule.flushVertexCache();
369cdf0e10cSrcweir             COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice());
370cdf0e10cSrcweir 
371cdf0e10cSrcweir             if( FAILED(pDevice->SetTexture(0,mpTexture.get())) )
372cdf0e10cSrcweir                 return false;
373cdf0e10cSrcweir 
374cdf0e10cSrcweir             return true;
375cdf0e10cSrcweir         }
376cdf0e10cSrcweir 
377cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
378cdf0e10cSrcweir         // DXSurface::isValid
379cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
380cdf0e10cSrcweir 
isValid()381cdf0e10cSrcweir         bool DXSurface::isValid()
382cdf0e10cSrcweir         {
383cdf0e10cSrcweir             ImplRenderModuleGuard aGuard( mrRenderModule );
384cdf0e10cSrcweir 
385cdf0e10cSrcweir             if(!(mpTexture.is()))
386cdf0e10cSrcweir                 return false;
387cdf0e10cSrcweir             return true;
388cdf0e10cSrcweir         }
389cdf0e10cSrcweir 
390cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
391cdf0e10cSrcweir         // DXSurface::update
392cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
393cdf0e10cSrcweir 
update(const::basegfx::B2IPoint & rDestPos,const::basegfx::B2IRange & rSourceRect,::canvas::IColorBuffer & rSource)394cdf0e10cSrcweir         bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
395cdf0e10cSrcweir                                 const ::basegfx::B2IRange& rSourceRect,
396cdf0e10cSrcweir                                 ::canvas::IColorBuffer&    rSource )
397cdf0e10cSrcweir         {
398cdf0e10cSrcweir             ImplRenderModuleGuard aGuard( mrRenderModule );
399cdf0e10cSrcweir 
400cdf0e10cSrcweir             // can't update if surface is not valid, that means
401cdf0e10cSrcweir             // either not existent nor restored...
402cdf0e10cSrcweir             if(!(isValid()))
403cdf0e10cSrcweir                 return false;
404cdf0e10cSrcweir 
405cdf0e10cSrcweir             D3DLOCKED_RECT aLockedRect;
406cdf0e10cSrcweir             RECT rect;
407cdf0e10cSrcweir             rect.left = std::max(sal_Int32(0),rDestPos.getX());
408cdf0e10cSrcweir             rect.top =  std::max(sal_Int32(0),rDestPos.getY());
409cdf0e10cSrcweir             // to avoid interpolation artifacts from other textures,
410cdf0e10cSrcweir             // the surface manager allocates one pixel gap between
411cdf0e10cSrcweir             // them. Clear that to transparent.
412cdf0e10cSrcweir             rect.right = std::min(maSize.getX(),
413cdf0e10cSrcweir                                   rect.left + sal_Int32(rSourceRect.getWidth()+1));
414cdf0e10cSrcweir             rect.bottom = std::min(maSize.getY(),
415cdf0e10cSrcweir                                    rect.top + sal_Int32(rSourceRect.getHeight()+1));
416cdf0e10cSrcweir             const bool bClearRightColumn( rect.right < maSize.getX() );
417cdf0e10cSrcweir             const bool bClearBottomRow( rect.bottom < maSize.getY() );
418cdf0e10cSrcweir 
419cdf0e10cSrcweir             if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
420cdf0e10cSrcweir             {
421cdf0e10cSrcweir                 if(sal_uInt8* pImage = rSource.lock())
422cdf0e10cSrcweir                 {
423cdf0e10cSrcweir                     switch( rSource.getFormat() )
424cdf0e10cSrcweir                     {
425cdf0e10cSrcweir                         case ::canvas::IColorBuffer::FMT_A8R8G8B8:
426cdf0e10cSrcweir                         {
427cdf0e10cSrcweir                             const std::size_t nSourceBytesPerPixel(4);
428cdf0e10cSrcweir                             const std::size_t nSourcePitchInBytes(rSource.getStride());
429cdf0e10cSrcweir                             pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
430cdf0e10cSrcweir                             pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
431cdf0e10cSrcweir 
432cdf0e10cSrcweir                             // calculate the destination memory address
433cdf0e10cSrcweir                             sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
434cdf0e10cSrcweir 
435cdf0e10cSrcweir                             const sal_uInt32 nNumBytesToCopy(
436cdf0e10cSrcweir                                 static_cast<sal_uInt32>(
437cdf0e10cSrcweir                                     rSourceRect.getWidth())*
438cdf0e10cSrcweir                                 nSourceBytesPerPixel);
439cdf0e10cSrcweir                             const sal_uInt64 nNumLines(rSourceRect.getHeight());
440cdf0e10cSrcweir 
441cdf0e10cSrcweir                             for(sal_uInt32 i=0; i<nNumLines; ++i)
442cdf0e10cSrcweir                             {
443cdf0e10cSrcweir                                 rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
444cdf0e10cSrcweir 
445cdf0e10cSrcweir                                 if( bClearRightColumn )
446cdf0e10cSrcweir                                 {
447cdf0e10cSrcweir                                     // to avoid interpolation artifacts
448cdf0e10cSrcweir                                     // from other textures, the surface
449cdf0e10cSrcweir                                     // manager allocates one pixel gap
450cdf0e10cSrcweir                                     // between them. Clear that to
451cdf0e10cSrcweir                                     // transparent.
452cdf0e10cSrcweir                                     pDst[nNumBytesToCopy] =
453cdf0e10cSrcweir                                         pDst[nNumBytesToCopy+1] =
454cdf0e10cSrcweir                                         pDst[nNumBytesToCopy+2] =
455cdf0e10cSrcweir                                         pDst[nNumBytesToCopy+3] = 0x00;
456cdf0e10cSrcweir                                 }
457cdf0e10cSrcweir                                 pDst += aLockedRect.Pitch;
458cdf0e10cSrcweir                                 pImage += nSourcePitchInBytes;
459cdf0e10cSrcweir                             }
460cdf0e10cSrcweir 
461cdf0e10cSrcweir                             if( bClearBottomRow )
462cdf0e10cSrcweir                                 rtl_zeroMemory(pDst,nNumBytesToCopy+4);
463cdf0e10cSrcweir                         }
464cdf0e10cSrcweir                         break;
465cdf0e10cSrcweir 
466cdf0e10cSrcweir                         case ::canvas::IColorBuffer::FMT_R8G8B8:
467cdf0e10cSrcweir                         {
468cdf0e10cSrcweir                             const std::size_t nSourceBytesPerPixel(3);
469cdf0e10cSrcweir                             const std::size_t nSourcePitchInBytes(rSource.getStride());
470cdf0e10cSrcweir                             pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
471cdf0e10cSrcweir                             pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
472cdf0e10cSrcweir 
473cdf0e10cSrcweir                             // calculate the destination memory address
474cdf0e10cSrcweir                             sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
475cdf0e10cSrcweir 
476cdf0e10cSrcweir                             const sal_Int32 nNumColumns(
477cdf0e10cSrcweir                                 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
478cdf0e10cSrcweir                             const sal_Int32 nNumLines(
479cdf0e10cSrcweir                                 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
480cdf0e10cSrcweir                             for(sal_Int32 i=0; i<nNumLines; ++i)
481cdf0e10cSrcweir                             {
482cdf0e10cSrcweir                                 sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
483cdf0e10cSrcweir                                 sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
484cdf0e10cSrcweir 
485cdf0e10cSrcweir                                 for(sal_Int32 x=0; x<nNumColumns; ++x)
486cdf0e10cSrcweir                                 {
487cdf0e10cSrcweir                                     sal_uInt32 color(0xFF000000);
488cdf0e10cSrcweir                                     color |= pSrcScanline[2]<<16;
489cdf0e10cSrcweir                                     color |= pSrcScanline[1]<<8;
490cdf0e10cSrcweir                                     color |= pSrcScanline[0];
491cdf0e10cSrcweir                                     pSrcScanline += 3;
492cdf0e10cSrcweir                                     *pDstScanline++ = color;
493cdf0e10cSrcweir                                 }
494cdf0e10cSrcweir                                 if( bClearRightColumn )
495cdf0e10cSrcweir                                     *pDstScanline++ = 0xFF000000;
496cdf0e10cSrcweir 
497cdf0e10cSrcweir                                 pDst += aLockedRect.Pitch;
498cdf0e10cSrcweir                                 pImage += nSourcePitchInBytes;
499cdf0e10cSrcweir                             }
500cdf0e10cSrcweir 
501cdf0e10cSrcweir                             if( bClearBottomRow )
502cdf0e10cSrcweir                                 rtl_zeroMemory(pDst,4*(nNumColumns+1));
503cdf0e10cSrcweir                         }
504cdf0e10cSrcweir                         break;
505cdf0e10cSrcweir 
506cdf0e10cSrcweir                         case ::canvas::IColorBuffer::FMT_X8R8G8B8:
507cdf0e10cSrcweir                         {
508cdf0e10cSrcweir                             const std::size_t nSourceBytesPerPixel(4);
509cdf0e10cSrcweir                             const std::size_t nSourcePitchInBytes(rSource.getStride());
510cdf0e10cSrcweir                             pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
511cdf0e10cSrcweir                             pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
512cdf0e10cSrcweir 
513cdf0e10cSrcweir                             // calculate the destination memory address
514cdf0e10cSrcweir                             sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
515cdf0e10cSrcweir 
516cdf0e10cSrcweir                             const sal_Int32 nNumLines(
517cdf0e10cSrcweir                                 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
518cdf0e10cSrcweir                             const sal_Int32 nNumColumns(
519cdf0e10cSrcweir                                 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
520cdf0e10cSrcweir                             for(sal_Int32 i=0; i<nNumLines; ++i)
521cdf0e10cSrcweir                             {
522cdf0e10cSrcweir                                 sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
523cdf0e10cSrcweir                                 sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
524cdf0e10cSrcweir                                 for(sal_Int32 j=0; j<nNumColumns; ++j)
525cdf0e10cSrcweir                                     pDst32[j] = 0xFF000000 | pSrc32[j];
526cdf0e10cSrcweir 
527cdf0e10cSrcweir                                 if( bClearRightColumn )
528cdf0e10cSrcweir                                     pDst32[nNumColumns] = 0xFF000000;
529cdf0e10cSrcweir 
530cdf0e10cSrcweir                                 pDst += aLockedRect.Pitch;
531cdf0e10cSrcweir                                 pImage += nSourcePitchInBytes;
532cdf0e10cSrcweir                             }
533cdf0e10cSrcweir 
534cdf0e10cSrcweir                             if( bClearBottomRow )
535cdf0e10cSrcweir                                 rtl_zeroMemory(pDst,4*(nNumColumns+1));
536cdf0e10cSrcweir                         }
537cdf0e10cSrcweir                         break;
538cdf0e10cSrcweir 
539cdf0e10cSrcweir                         default:
540cdf0e10cSrcweir                             ENSURE_OR_RETURN_FALSE(false,
541cdf0e10cSrcweir                                             "DXSurface::update(): Unknown/unimplemented buffer format" );
542cdf0e10cSrcweir                             break;
543cdf0e10cSrcweir                     }
544cdf0e10cSrcweir 
545cdf0e10cSrcweir                     rSource.unlock();
546cdf0e10cSrcweir                 }
547cdf0e10cSrcweir 
548cdf0e10cSrcweir                 return SUCCEEDED(mpTexture->UnlockRect(0));
549cdf0e10cSrcweir             }
550cdf0e10cSrcweir 
551cdf0e10cSrcweir             return true;
552cdf0e10cSrcweir         }
553cdf0e10cSrcweir 
554cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
555cdf0e10cSrcweir         // DXSurface::getSize
556cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
557cdf0e10cSrcweir 
getSize()558cdf0e10cSrcweir         ::basegfx::B2IVector DXSurface::getSize()
559cdf0e10cSrcweir         {
560cdf0e10cSrcweir             return maSize;
561cdf0e10cSrcweir         }
562cdf0e10cSrcweir 
getTexture() const563cdf0e10cSrcweir         COMReference<IDirect3DTexture9> DXSurface::getTexture() const
564cdf0e10cSrcweir         {
565cdf0e10cSrcweir             return mpTexture;
566cdf0e10cSrcweir         }
567cdf0e10cSrcweir 
568cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
569cdf0e10cSrcweir         // DXRenderModule::DXRenderModule
570cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
571cdf0e10cSrcweir 
DXRenderModule(const::Window & rWindow)572cdf0e10cSrcweir         DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
573cdf0e10cSrcweir             mhWnd(0),
574cdf0e10cSrcweir             mpDevice(),
575cdf0e10cSrcweir             mpDirect3D9(),
576cdf0e10cSrcweir             mpSwapChain(),
577cdf0e10cSrcweir             mpVertexBuffer(),
578cdf0e10cSrcweir             mpTexture(),
579cdf0e10cSrcweir             maSize(),
580cdf0e10cSrcweir             maVertexCache(),
581cdf0e10cSrcweir             mnCount(0),
582cdf0e10cSrcweir             mnBeginSceneCount(0),
583cdf0e10cSrcweir             mbCanUseDynamicTextures(false),
584cdf0e10cSrcweir             mbError( false ),
585cdf0e10cSrcweir             meType( PRIMITIVE_TYPE_UNKNOWN ),
586cdf0e10cSrcweir             maPageSize(),
587cdf0e10cSrcweir             mad3dpp(),
588cdf0e10cSrcweir             maNumVertices( VERTEX_BUFFER_SIZE ),
589cdf0e10cSrcweir             maWriteIndex(0),
590cdf0e10cSrcweir             maReadIndex(0)
591cdf0e10cSrcweir         {
592cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
593cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
594cdf0e10cSrcweir 
595cdf0e10cSrcweir             if(!(create(rWindow)))
596cdf0e10cSrcweir             {
597cdf0e10cSrcweir                 throw lang::NoSupportException(
598cdf0e10cSrcweir                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
599cdf0e10cSrcweir                                          "Could not create DirectX device!") ),NULL);
600cdf0e10cSrcweir             }
601cdf0e10cSrcweir 
602cdf0e10cSrcweir             // allocate a single texture surface which can be used later.
603cdf0e10cSrcweir             // we also use this to calibrate the page size.
604cdf0e10cSrcweir             ::basegfx::B2IVector aPageSize(maPageSize);
605cdf0e10cSrcweir             while(true)
606cdf0e10cSrcweir             {
607cdf0e10cSrcweir                 mpTexture = ::canvas::ISurfaceSharedPtr(
608cdf0e10cSrcweir                     new DXSurface(*this,aPageSize));
609cdf0e10cSrcweir                 if(mpTexture->isValid())
610cdf0e10cSrcweir                     break;
611cdf0e10cSrcweir 
612cdf0e10cSrcweir                 aPageSize.setX(aPageSize.getX()>>1);
613cdf0e10cSrcweir                 aPageSize.setY(aPageSize.getY()>>1);
614cdf0e10cSrcweir                 if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
615cdf0e10cSrcweir                    (aPageSize.getY() < MIN_TEXTURE_SIZE))
616cdf0e10cSrcweir                 {
617cdf0e10cSrcweir                     throw lang::NoSupportException(
618cdf0e10cSrcweir                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
619cdf0e10cSrcweir                                             "Could not create DirectX device - "
620cdf0e10cSrcweir                                             "insufficient texture space!") ),NULL);
621cdf0e10cSrcweir                 }
622cdf0e10cSrcweir             }
623cdf0e10cSrcweir             maPageSize=aPageSize;
624cdf0e10cSrcweir 
625cdf0e10cSrcweir             IDirect3DVertexBuffer9 *pVB(NULL);
626cdf0e10cSrcweir             DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
627cdf0e10cSrcweir             if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
628cdf0e10cSrcweir                                                     D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
629cdf0e10cSrcweir                                                     aFVF,
630cdf0e10cSrcweir                                                     D3DPOOL_DEFAULT,
631cdf0e10cSrcweir                                                     &pVB,
632cdf0e10cSrcweir                                                     NULL)) )
633cdf0e10cSrcweir             {
634cdf0e10cSrcweir                 throw lang::NoSupportException(
635cdf0e10cSrcweir                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
636cdf0e10cSrcweir                                          "Could not create DirectX device - out of memory!")),NULL);
637cdf0e10cSrcweir             }
638cdf0e10cSrcweir 
639cdf0e10cSrcweir             mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
640cdf0e10cSrcweir         }
641cdf0e10cSrcweir 
642cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
643cdf0e10cSrcweir         // DXRenderModule::~DXRenderModule
644cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
645cdf0e10cSrcweir 
~DXRenderModule()646cdf0e10cSrcweir         DXRenderModule::~DXRenderModule()
647cdf0e10cSrcweir         {
648cdf0e10cSrcweir             disposing();
649cdf0e10cSrcweir         }
650cdf0e10cSrcweir 
651cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
652cdf0e10cSrcweir         // DXRenderModule::disposing
653cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
654cdf0e10cSrcweir 
disposing()655cdf0e10cSrcweir         void DXRenderModule::disposing()
656cdf0e10cSrcweir         {
657cdf0e10cSrcweir             if(!(mhWnd))
658cdf0e10cSrcweir                 return;
659cdf0e10cSrcweir 
660cdf0e10cSrcweir             mpTexture.reset();
661cdf0e10cSrcweir             mpWindow.reset();
662cdf0e10cSrcweir             mhWnd=NULL;
663cdf0e10cSrcweir 
664cdf0e10cSrcweir             // refrain from releasing the DX9 objects. We're the only
665cdf0e10cSrcweir             // ones holding references to them, and it might be
666cdf0e10cSrcweir             // dangerous to destroy the DX9 device, before all other
667cdf0e10cSrcweir             // objects are dead.
668cdf0e10cSrcweir         }
669cdf0e10cSrcweir 
670cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
671cdf0e10cSrcweir         // DXRenderModule::create
672cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
673cdf0e10cSrcweir 
create(const::Window & rWindow)674cdf0e10cSrcweir         bool DXRenderModule::create( const ::Window& rWindow )
675cdf0e10cSrcweir         {
676cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
677cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
678cdf0e10cSrcweir 
679cdf0e10cSrcweir             maVertexCache.reserve(1024);
680cdf0e10cSrcweir 
681cdf0e10cSrcweir             mpWindow.reset(
682cdf0e10cSrcweir                 new SystemChildWindow(
683cdf0e10cSrcweir                 const_cast<Window *>(&rWindow), 0) );
684cdf0e10cSrcweir 
685cdf0e10cSrcweir             // system child window must not receive mouse events
686cdf0e10cSrcweir             mpWindow->SetMouseTransparent( TRUE );
687cdf0e10cSrcweir 
688cdf0e10cSrcweir             // parent should receive paint messages as well
689cdf0e10cSrcweir             // [PARENTCLIPMODE_NOCLIP], the argument is here
690cdf0e10cSrcweir             // passed as plain numeric value since the stupid
691cdf0e10cSrcweir             // define utilizes a USHORT cast.
692cdf0e10cSrcweir             mpWindow->SetParentClipMode(0x0002);
693cdf0e10cSrcweir 
694cdf0e10cSrcweir             // the system child window must not clear its background
695cdf0e10cSrcweir             mpWindow->EnableEraseBackground( sal_False );
696cdf0e10cSrcweir 
697cdf0e10cSrcweir             mpWindow->SetControlForeground();
698cdf0e10cSrcweir             mpWindow->SetControlBackground();
699cdf0e10cSrcweir             mpWindow->EnablePaint(sal_False);
700cdf0e10cSrcweir 
701cdf0e10cSrcweir             const SystemEnvData *pData = mpWindow->GetSystemData();
702cdf0e10cSrcweir             const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
703cdf0e10cSrcweir             mhWnd = const_cast<HWND>(hwnd);
704cdf0e10cSrcweir 
705cdf0e10cSrcweir             ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
706cdf0e10cSrcweir                             "DXRenderModule::create() No valid HWND given." );
707cdf0e10cSrcweir 
708cdf0e10cSrcweir             // retrieve position and size of the parent window
709cdf0e10cSrcweir             const ::Size &rSizePixel(rWindow.GetSizePixel());
710cdf0e10cSrcweir 
711cdf0e10cSrcweir             // remember the size of the parent window, since we
712cdf0e10cSrcweir             // need to use this for our child window.
713cdf0e10cSrcweir             maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
714cdf0e10cSrcweir             maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
715cdf0e10cSrcweir 
716cdf0e10cSrcweir             // let the child window cover the same size as the parent window.
717cdf0e10cSrcweir             mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
718cdf0e10cSrcweir 
719cdf0e10cSrcweir             // TODO(F2): since we would like to share precious hardware
720cdf0e10cSrcweir             // resources, the direct3d9 object should be global. each new
721cdf0e10cSrcweir             // request for a canvas should only create a new swapchain.
722cdf0e10cSrcweir             mpDirect3D9 = COMReference<IDirect3D9>(
723cdf0e10cSrcweir                 Direct3DCreate9(D3D_SDK_VERSION));
724cdf0e10cSrcweir             if(!mpDirect3D9.is())
725cdf0e10cSrcweir                 return false;
726cdf0e10cSrcweir 
727cdf0e10cSrcweir             // create a device from the direct3d9 object.
728cdf0e10cSrcweir             if(!(createDevice()))
729cdf0e10cSrcweir                 return false;
730cdf0e10cSrcweir 
731cdf0e10cSrcweir             mpWindow->Show();
732cdf0e10cSrcweir 
733cdf0e10cSrcweir             return true;
734cdf0e10cSrcweir         }
735cdf0e10cSrcweir 
736cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
737cdf0e10cSrcweir         // DXRenderModule::verifyDevice
738cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
739cdf0e10cSrcweir 
verifyDevice(const UINT nAdapter)740cdf0e10cSrcweir         bool DXRenderModule::verifyDevice( const UINT nAdapter )
741cdf0e10cSrcweir         {
742cdf0e10cSrcweir             ENSURE_OR_THROW( mpDirect3D9.is(),
743cdf0e10cSrcweir                               "DXRenderModule::verifyDevice() No valid device." );
744cdf0e10cSrcweir 
745cdf0e10cSrcweir             // ask direct3d9 about the capabilities of hardware devices on a specific adapter.
746cdf0e10cSrcweir             // here we decide if the underlying hardware of the machine 'is good enough'.
747cdf0e10cSrcweir             // since we only need a tiny little fraction of what could be used, this
748cdf0e10cSrcweir             // is basically a no-op.
749cdf0e10cSrcweir             D3DCAPS9 aCaps;
750cdf0e10cSrcweir             if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
751cdf0e10cSrcweir                 return false;
752cdf0e10cSrcweir             if(!(aCaps.MaxTextureWidth))
753cdf0e10cSrcweir                 return false;
754cdf0e10cSrcweir             if(!(aCaps.MaxTextureHeight))
755cdf0e10cSrcweir                 return false;
756cdf0e10cSrcweir             maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight);
757cdf0e10cSrcweir 
758cdf0e10cSrcweir             // check device against white & blacklist entries
759cdf0e10cSrcweir             D3DADAPTER_IDENTIFIER9 aIdent;
760cdf0e10cSrcweir             if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
761cdf0e10cSrcweir                 return false;
762cdf0e10cSrcweir 
763cdf0e10cSrcweir             DXCanvasItem aConfigItem;
764cdf0e10cSrcweir             DXCanvasItem::DeviceInfo aInfo;
765cdf0e10cSrcweir             aInfo.nVendorId = aIdent.VendorId;
766cdf0e10cSrcweir             aInfo.nDeviceId = aIdent.DeviceId;
767cdf0e10cSrcweir             aInfo.nDeviceSubSysId = aIdent.SubSysId;
768cdf0e10cSrcweir             aInfo.nDeviceRevision = aIdent.Revision;
769cdf0e10cSrcweir 
770cdf0e10cSrcweir             aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
771cdf0e10cSrcweir             aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
772cdf0e10cSrcweir             aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
773cdf0e10cSrcweir             aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
774cdf0e10cSrcweir 
775cdf0e10cSrcweir             if( !aConfigItem.isDeviceUsable(aInfo) )
776cdf0e10cSrcweir                 return false;
777cdf0e10cSrcweir 
778cdf0e10cSrcweir             if( aConfigItem.isBlacklistCurrentDevice() )
779cdf0e10cSrcweir             {
780cdf0e10cSrcweir                 aConfigItem.blacklistDevice(aInfo);
781cdf0e10cSrcweir                 return false;
782cdf0e10cSrcweir             }
783cdf0e10cSrcweir 
784cdf0e10cSrcweir             aConfigItem.adaptMaxTextureSize(maPageSize);
785cdf0e10cSrcweir 
786cdf0e10cSrcweir             mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0;
787cdf0e10cSrcweir 
788cdf0e10cSrcweir             return true;
789cdf0e10cSrcweir         }
790cdf0e10cSrcweir 
791cdf0e10cSrcweir 
792cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
793cdf0e10cSrcweir         // DXRenderModule::createDevice
794cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
795cdf0e10cSrcweir 
createDevice()796cdf0e10cSrcweir         bool DXRenderModule::createDevice()
797cdf0e10cSrcweir         {
798cdf0e10cSrcweir             // we expect that the caller provides us with a valid HWND
799cdf0e10cSrcweir             ENSURE_OR_THROW( IsWindow(mhWnd),
800cdf0e10cSrcweir                               "DXRenderModule::createDevice() No valid HWND given." );
801cdf0e10cSrcweir 
802cdf0e10cSrcweir             // we expect that the caller already created the direct3d9 object.
803cdf0e10cSrcweir             ENSURE_OR_THROW( mpDirect3D9.is(),
804cdf0e10cSrcweir                               "DXRenderModule::createDevice() no direct3d?." );
805cdf0e10cSrcweir 
806cdf0e10cSrcweir             // find the adapter identifier from the window.
807cdf0e10cSrcweir             const UINT aAdapter(getAdapterFromWindow());
808cdf0e10cSrcweir             if(aAdapter == static_cast<UINT>(-1))
809cdf0e10cSrcweir                 return false;
810cdf0e10cSrcweir 
811cdf0e10cSrcweir             // verify that device possibly works
812cdf0e10cSrcweir             if( !verifyDevice(aAdapter) )
813cdf0e10cSrcweir                 return false;
814cdf0e10cSrcweir 
815cdf0e10cSrcweir             // query the display mode from the selected adapter.
816cdf0e10cSrcweir             // we'll later request the backbuffer format to be same
817cdf0e10cSrcweir             // same as the display format.
818cdf0e10cSrcweir             D3DDISPLAYMODE d3ddm;
819cdf0e10cSrcweir             mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
820cdf0e10cSrcweir 
821cdf0e10cSrcweir             // we need to use D3DSWAPEFFECT_COPY here since the canvas-api has
822cdf0e10cSrcweir             // basically nothing to do with efficient resource handling. it tries
823cdf0e10cSrcweir             // to avoid drawing whenevery possible, which is simply not the most
824cdf0e10cSrcweir             // efficient way we could leverage the hardware in this case. it would
825cdf0e10cSrcweir             // be far better to redraw the backbuffer each time we would like to
826cdf0e10cSrcweir             // display the content of the backbuffer, but we need to face reality
827cdf0e10cSrcweir             // here and follow how the canvas was designed.
828cdf0e10cSrcweir 
829cdf0e10cSrcweir             // Strictly speaking, we don't need a full screen worth of
830cdf0e10cSrcweir             // backbuffer here. We could also scale dynamically with
831cdf0e10cSrcweir             // the current window size, but this will make it
832cdf0e10cSrcweir             // necessary to temporarily have two buffers while copying
833cdf0e10cSrcweir             // from the old to the new one. What's more, at the time
834cdf0e10cSrcweir             // we need a larger buffer, DX might not have sufficient
835cdf0e10cSrcweir             // resources available, and we're then left with too small
836cdf0e10cSrcweir             // a back buffer, and no way of falling back to a
837cdf0e10cSrcweir             // different canvas implementation.
838cdf0e10cSrcweir             ZeroMemory( &mad3dpp, sizeof(mad3dpp) );
839cdf0e10cSrcweir             mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()),
840cdf0e10cSrcweir                                                sal_Int32(d3ddm.Width));
841cdf0e10cSrcweir             mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()),
842cdf0e10cSrcweir                                                 sal_Int32(d3ddm.Height));
843cdf0e10cSrcweir             mad3dpp.BackBufferCount = 1;
844cdf0e10cSrcweir             mad3dpp.Windowed = TRUE;
845cdf0e10cSrcweir             mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
846cdf0e10cSrcweir             mad3dpp.BackBufferFormat = d3ddm.Format;
847cdf0e10cSrcweir             mad3dpp.EnableAutoDepthStencil = FALSE;
848cdf0e10cSrcweir             mad3dpp.hDeviceWindow = mhWnd;
849cdf0e10cSrcweir             mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
850cdf0e10cSrcweir 
851cdf0e10cSrcweir             // now create the device, first try hardware vertex processing,
852cdf0e10cSrcweir             // then software vertex processing. if both queries fail, we give up
853cdf0e10cSrcweir             // and indicate failure.
854cdf0e10cSrcweir             IDirect3DDevice9 *pDevice(NULL);
855cdf0e10cSrcweir             if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
856cdf0e10cSrcweir                                                 D3DDEVTYPE_HAL,
857cdf0e10cSrcweir                                                 mhWnd,
858cdf0e10cSrcweir                                                 D3DCREATE_HARDWARE_VERTEXPROCESSING|
859cdf0e10cSrcweir                                                 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
860cdf0e10cSrcweir                                                 &mad3dpp,
861cdf0e10cSrcweir                                                 &pDevice)))
862cdf0e10cSrcweir                 if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
863cdf0e10cSrcweir                                                     D3DDEVTYPE_HAL,
864cdf0e10cSrcweir                                                     mhWnd,
865cdf0e10cSrcweir                                                     D3DCREATE_SOFTWARE_VERTEXPROCESSING|
866cdf0e10cSrcweir                                                     D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
867cdf0e10cSrcweir                                                     &mad3dpp,
868cdf0e10cSrcweir                                                     &pDevice)))
869cdf0e10cSrcweir                     return false;
870cdf0e10cSrcweir 
871cdf0e10cSrcweir             // got it, store it in a safe place...
872cdf0e10cSrcweir             mpDevice=COMReference<IDirect3DDevice9>(pDevice);
873cdf0e10cSrcweir 
874cdf0e10cSrcweir             // After CreateDevice, the first swap chain already exists, so just get it...
875cdf0e10cSrcweir             IDirect3DSwapChain9 *pSwapChain(NULL);
876cdf0e10cSrcweir             pDevice->GetSwapChain(0,&pSwapChain);
877cdf0e10cSrcweir             mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
878cdf0e10cSrcweir             if( !mpSwapChain.is() )
879cdf0e10cSrcweir                 return false;
880cdf0e10cSrcweir 
881cdf0e10cSrcweir             // clear the render target [which is the backbuffer in this case].
882cdf0e10cSrcweir             // we are forced to do this once, and furthermore right now.
883cdf0e10cSrcweir             // please note that this is only possible since we created the
884cdf0e10cSrcweir             // backbuffer with copy semantics [the content is preserved after
885cdf0e10cSrcweir             // calls to Present()], which is an unnecessarily expensive operation.
886cdf0e10cSrcweir             LPDIRECT3DSURFACE9 pBackBuffer = NULL;
887cdf0e10cSrcweir             mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
888cdf0e10cSrcweir             mpDevice->SetRenderTarget( 0, pBackBuffer );
889cdf0e10cSrcweir             mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
890cdf0e10cSrcweir             pBackBuffer->Release();
891cdf0e10cSrcweir 
892cdf0e10cSrcweir             return true;
893cdf0e10cSrcweir         }
894cdf0e10cSrcweir 
895cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
896cdf0e10cSrcweir         // DXRenderModule::createSystemMemorySurface
897cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
898cdf0e10cSrcweir 
createSystemMemorySurface(const::basegfx::B2IVector & rSize)899cdf0e10cSrcweir         COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
900cdf0e10cSrcweir         {
901cdf0e10cSrcweir             if(isDisposed())
902cdf0e10cSrcweir                 return COMReference<IDirect3DSurface9>(NULL);
903cdf0e10cSrcweir 
904cdf0e10cSrcweir             // please note that D3DFMT_X8R8G8B8 is the only format we're
905cdf0e10cSrcweir             // able to choose here, since GetDC() doesn't support any
906cdf0e10cSrcweir             // other 32bit-format.
907cdf0e10cSrcweir             IDirect3DSurface9 *pSurface(NULL);
908cdf0e10cSrcweir             if( FAILED(mpDevice->CreateOffscreenPlainSurface(
909cdf0e10cSrcweir                            rSize.getX(),
910cdf0e10cSrcweir                            rSize.getY(),
911cdf0e10cSrcweir                            D3DFMT_X8R8G8B8,
912cdf0e10cSrcweir                            D3DPOOL_SYSTEMMEM,
913cdf0e10cSrcweir                            &pSurface,
914cdf0e10cSrcweir                            NULL)) )
915cdf0e10cSrcweir             {
916cdf0e10cSrcweir                 throw lang::NoSupportException(
917cdf0e10cSrcweir                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
918cdf0e10cSrcweir                                          "Could not create offscreen surface - out of mem!") ),NULL);
919cdf0e10cSrcweir             }
920cdf0e10cSrcweir 
921cdf0e10cSrcweir             return COMReference<IDirect3DSurface9>(pSurface);
922cdf0e10cSrcweir         }
923cdf0e10cSrcweir 
924cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
925cdf0e10cSrcweir         // DXRenderModule::flip
926cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
927cdf0e10cSrcweir 
flip(const::basegfx::B2IRectangle & rUpdateArea,const::basegfx::B2IRectangle &)928cdf0e10cSrcweir         bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
929cdf0e10cSrcweir                                    const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ )
930cdf0e10cSrcweir         {
931cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
932cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
933cdf0e10cSrcweir 
934cdf0e10cSrcweir             if(isDisposed() || !mpSwapChain.is())
935cdf0e10cSrcweir                 return false;
936cdf0e10cSrcweir 
937cdf0e10cSrcweir             flushVertexCache();
938cdf0e10cSrcweir 
939cdf0e10cSrcweir             // TODO(P2): Might be faster to actually pass update area here
940cdf0e10cSrcweir             RECT aRect =
941cdf0e10cSrcweir                 {
942cdf0e10cSrcweir                     rUpdateArea.getMinX(),
943cdf0e10cSrcweir                     rUpdateArea.getMinY(),
944cdf0e10cSrcweir                     rUpdateArea.getMaxX(),
945cdf0e10cSrcweir                     rUpdateArea.getMaxY()
946cdf0e10cSrcweir                 };
947cdf0e10cSrcweir             HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0));
948cdf0e10cSrcweir             if(FAILED(hr))
949cdf0e10cSrcweir             {
950cdf0e10cSrcweir                 if(hr != D3DERR_DEVICELOST)
951cdf0e10cSrcweir                     return false;
952cdf0e10cSrcweir 
953cdf0e10cSrcweir                 // interestingly enough, sometimes the Reset() below
954cdf0e10cSrcweir                 // *still* causes DeviceLost errors. So, cycle until
955cdf0e10cSrcweir                 // DX was kind enough to really reset the device...
956cdf0e10cSrcweir                 do
957cdf0e10cSrcweir                 {
958cdf0e10cSrcweir                     mpVertexBuffer.reset();
959cdf0e10cSrcweir                     hr = mpDevice->Reset(&mad3dpp);
960cdf0e10cSrcweir                     if(SUCCEEDED(hr))
961cdf0e10cSrcweir                     {
962cdf0e10cSrcweir                         IDirect3DVertexBuffer9 *pVB(NULL);
963cdf0e10cSrcweir                         DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
964cdf0e10cSrcweir                         if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
965cdf0e10cSrcweir                                                                 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
966cdf0e10cSrcweir                                                                 aFVF,
967cdf0e10cSrcweir                                                                 D3DPOOL_DEFAULT,
968cdf0e10cSrcweir                                                                 &pVB,
969cdf0e10cSrcweir                                                                 NULL)) )
970cdf0e10cSrcweir                         {
971cdf0e10cSrcweir                             throw lang::NoSupportException(
972cdf0e10cSrcweir                                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
973cdf0e10cSrcweir                                                      "Could not create DirectX device - out of memory!")),NULL);
974cdf0e10cSrcweir                         }
975cdf0e10cSrcweir                         mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
976cdf0e10cSrcweir 
977cdf0e10cSrcweir                         // retry after the restore
978cdf0e10cSrcweir                         if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)))
979cdf0e10cSrcweir                             return true;
980cdf0e10cSrcweir                     }
981cdf0e10cSrcweir 
982cdf0e10cSrcweir                     TimeValue aTimeout;
983cdf0e10cSrcweir                     aTimeout.Seconds=1;
984cdf0e10cSrcweir                     aTimeout.Nanosec=0;
985cdf0e10cSrcweir                     osl_waitThread(&aTimeout);
986cdf0e10cSrcweir                 }
987cdf0e10cSrcweir                 while(hr == D3DERR_DEVICELOST);
988cdf0e10cSrcweir 
989cdf0e10cSrcweir                 return false;
990cdf0e10cSrcweir             }
991cdf0e10cSrcweir 
992cdf0e10cSrcweir             return true;
993cdf0e10cSrcweir         }
994cdf0e10cSrcweir 
995cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
996cdf0e10cSrcweir         // DXRenderModule::screenShot
997cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
998cdf0e10cSrcweir 
screenShot()999cdf0e10cSrcweir         void DXRenderModule::screenShot()
1000cdf0e10cSrcweir         {
1001cdf0e10cSrcweir         }
1002cdf0e10cSrcweir 
1003cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1004cdf0e10cSrcweir         // DXRenderModule::resize
1005cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1006cdf0e10cSrcweir 
resize(const::basegfx::B2IRange & rect)1007cdf0e10cSrcweir         void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
1008cdf0e10cSrcweir         {
1009cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1010cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1011cdf0e10cSrcweir 
1012cdf0e10cSrcweir             if(isDisposed())
1013cdf0e10cSrcweir                 return;
1014cdf0e10cSrcweir 
1015cdf0e10cSrcweir             // don't do anything if the size didn't change.
1016cdf0e10cSrcweir             if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
1017cdf0e10cSrcweir                maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
1018cdf0e10cSrcweir                return;
1019cdf0e10cSrcweir 
1020cdf0e10cSrcweir             // TODO(Q2): use numeric cast to prevent overflow
1021cdf0e10cSrcweir             maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
1022cdf0e10cSrcweir             maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
1023cdf0e10cSrcweir 
1024cdf0e10cSrcweir             mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1025cdf0e10cSrcweir 
1026cdf0e10cSrcweir             // resize back buffer, if necessary
1027cdf0e10cSrcweir             // -------------------------------------------------------------
1028cdf0e10cSrcweir 
1029cdf0e10cSrcweir             // don't attempt to create anything if the
1030cdf0e10cSrcweir             // requested size is NULL.
1031cdf0e10cSrcweir             if(!(maSize.getX()))
1032cdf0e10cSrcweir                 return;
1033cdf0e10cSrcweir             if(!(maSize.getY()))
1034cdf0e10cSrcweir                 return;
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir             // backbuffer too small (might happen, if window is
1037cdf0e10cSrcweir             // maximized across multiple monitors)
1038cdf0e10cSrcweir             if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() ||
1039cdf0e10cSrcweir                 sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() )
1040cdf0e10cSrcweir             {
1041cdf0e10cSrcweir                 mad3dpp.BackBufferWidth = maSize.getX();
1042cdf0e10cSrcweir                 mad3dpp.BackBufferHeight = maSize.getY();
1043cdf0e10cSrcweir 
1044cdf0e10cSrcweir                 // clear before, save resources
1045cdf0e10cSrcweir                 mpSwapChain.reset();
1046cdf0e10cSrcweir 
1047cdf0e10cSrcweir                 IDirect3DSwapChain9 *pSwapChain(NULL);
1048cdf0e10cSrcweir                 if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain)))
1049cdf0e10cSrcweir                     return;
1050cdf0e10cSrcweir                 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
1051cdf0e10cSrcweir 
1052cdf0e10cSrcweir                 // clear the render target [which is the backbuffer in this case].
1053cdf0e10cSrcweir                 // we are forced to do this once, and furthermore right now.
1054cdf0e10cSrcweir                 // please note that this is only possible since we created the
1055cdf0e10cSrcweir                 // backbuffer with copy semantics [the content is preserved after
1056cdf0e10cSrcweir                 // calls to Present()], which is an unnecessarily expensive operation.
1057cdf0e10cSrcweir                 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
1058cdf0e10cSrcweir                 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
1059cdf0e10cSrcweir                 mpDevice->SetRenderTarget( 0, pBackBuffer );
1060cdf0e10cSrcweir                 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
1061cdf0e10cSrcweir                 pBackBuffer->Release();
1062cdf0e10cSrcweir             }
1063cdf0e10cSrcweir         }
1064cdf0e10cSrcweir 
1065cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1066cdf0e10cSrcweir         // DXRenderModule::getPageSize
1067cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1068cdf0e10cSrcweir 
getPageSize()1069cdf0e10cSrcweir         ::basegfx::B2IVector DXRenderModule::getPageSize()
1070cdf0e10cSrcweir         {
1071cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1072cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1073cdf0e10cSrcweir             return maPageSize;
1074cdf0e10cSrcweir         }
1075cdf0e10cSrcweir 
1076cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1077cdf0e10cSrcweir         // DXRenderModule::createSurface
1078cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1079cdf0e10cSrcweir 
createSurface(const::basegfx::B2IVector & surfaceSize)1080cdf0e10cSrcweir         ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
1081cdf0e10cSrcweir         {
1082cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1083cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1084cdf0e10cSrcweir 
1085cdf0e10cSrcweir             if(isDisposed())
1086cdf0e10cSrcweir                 return ::canvas::ISurfaceSharedPtr();
1087cdf0e10cSrcweir 
1088cdf0e10cSrcweir             const ::basegfx::B2IVector& rPageSize( getPageSize() );
1089cdf0e10cSrcweir             ::basegfx::B2ISize aSize(surfaceSize);
1090cdf0e10cSrcweir             if(!(aSize.getX()))
1091cdf0e10cSrcweir                 aSize.setX(rPageSize.getX());
1092cdf0e10cSrcweir             if(!(aSize.getY()))
1093cdf0e10cSrcweir                 aSize.setY(rPageSize.getY());
1094cdf0e10cSrcweir 
1095cdf0e10cSrcweir             if(mpTexture.use_count() == 1)
1096cdf0e10cSrcweir                 return mpTexture;
1097cdf0e10cSrcweir 
1098cdf0e10cSrcweir             return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) );
1099cdf0e10cSrcweir         }
1100cdf0e10cSrcweir 
1101cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1102cdf0e10cSrcweir         // DXRenderModule::beginPrimitive
1103cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1104cdf0e10cSrcweir 
beginPrimitive(PrimitiveType eType)1105cdf0e10cSrcweir         void DXRenderModule::beginPrimitive( PrimitiveType eType )
1106cdf0e10cSrcweir         {
1107cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1108cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1109cdf0e10cSrcweir 
1110cdf0e10cSrcweir             if(isDisposed())
1111cdf0e10cSrcweir                 return;
1112cdf0e10cSrcweir 
1113cdf0e10cSrcweir             ENSURE_OR_THROW( !mnBeginSceneCount,
1114cdf0e10cSrcweir                               "DXRenderModule::beginPrimitive(): nested call" );
1115cdf0e10cSrcweir 
1116cdf0e10cSrcweir             ++mnBeginSceneCount;
1117cdf0e10cSrcweir             meType=eType;
1118cdf0e10cSrcweir             mnCount=0;
1119cdf0e10cSrcweir         }
1120cdf0e10cSrcweir 
1121cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1122cdf0e10cSrcweir         // DXRenderModule::endPrimitive
1123cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1124cdf0e10cSrcweir 
endPrimitive()1125cdf0e10cSrcweir         void DXRenderModule::endPrimitive()
1126cdf0e10cSrcweir         {
1127cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1128cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1129cdf0e10cSrcweir 
1130cdf0e10cSrcweir             if(isDisposed())
1131cdf0e10cSrcweir                 return;
1132cdf0e10cSrcweir 
1133cdf0e10cSrcweir             --mnBeginSceneCount;
1134cdf0e10cSrcweir             meType=PRIMITIVE_TYPE_UNKNOWN;
1135cdf0e10cSrcweir             mnCount=0;
1136cdf0e10cSrcweir         }
1137cdf0e10cSrcweir 
1138cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1139cdf0e10cSrcweir         // DXRenderModule::pushVertex
1140cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1141cdf0e10cSrcweir 
pushVertex(const::canvas::Vertex & vertex)1142cdf0e10cSrcweir         void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
1143cdf0e10cSrcweir         {
1144cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1145cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1146cdf0e10cSrcweir 
1147cdf0e10cSrcweir             if(isDisposed())
1148cdf0e10cSrcweir                 return;
1149cdf0e10cSrcweir 
1150cdf0e10cSrcweir             switch(meType)
1151cdf0e10cSrcweir             {
1152cdf0e10cSrcweir                 case PRIMITIVE_TYPE_TRIANGLE:
1153cdf0e10cSrcweir                 {
1154cdf0e10cSrcweir                     maVertexCache.push_back(vertex);
1155cdf0e10cSrcweir                     ++mnCount;
1156cdf0e10cSrcweir                     mnCount &= 3;
1157cdf0e10cSrcweir                     break;
1158cdf0e10cSrcweir                 }
1159cdf0e10cSrcweir 
1160cdf0e10cSrcweir                 case PRIMITIVE_TYPE_QUAD:
1161cdf0e10cSrcweir                 {
1162cdf0e10cSrcweir                     if(mnCount == 3)
1163cdf0e10cSrcweir                     {
1164cdf0e10cSrcweir                         const std::size_t size(maVertexCache.size());
1165cdf0e10cSrcweir                         ::canvas::Vertex v0(maVertexCache[size-1]);
1166cdf0e10cSrcweir                         ::canvas::Vertex v2(maVertexCache[size-3]);
1167cdf0e10cSrcweir                         maVertexCache.push_back(v0);
1168cdf0e10cSrcweir                         maVertexCache.push_back(vertex);
1169cdf0e10cSrcweir                         maVertexCache.push_back(v2);
1170cdf0e10cSrcweir                         mnCount=0;
1171cdf0e10cSrcweir                     }
1172cdf0e10cSrcweir                     else
1173cdf0e10cSrcweir                     {
1174cdf0e10cSrcweir                         maVertexCache.push_back(vertex);
1175cdf0e10cSrcweir                         ++mnCount;
1176cdf0e10cSrcweir                     }
1177cdf0e10cSrcweir                     break;
1178cdf0e10cSrcweir                 }
1179cdf0e10cSrcweir 
1180cdf0e10cSrcweir                 default:
1181cdf0e10cSrcweir                     OSL_ENSURE(false,
1182cdf0e10cSrcweir                                "DXRenderModule::pushVertex(): unexpected primitive type");
1183cdf0e10cSrcweir                     break;
1184cdf0e10cSrcweir             }
1185cdf0e10cSrcweir         }
1186cdf0e10cSrcweir 
1187cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1188cdf0e10cSrcweir         // DXRenderModule::isError
1189cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1190cdf0e10cSrcweir 
isError()1191cdf0e10cSrcweir         bool DXRenderModule::isError()
1192cdf0e10cSrcweir         {
1193cdf0e10cSrcweir             // TODO(P2): get rid of those fine-grained locking
1194cdf0e10cSrcweir             ::osl::MutexGuard aGuard( maMutex );
1195cdf0e10cSrcweir 
1196cdf0e10cSrcweir             return mbError;
1197cdf0e10cSrcweir         }
1198cdf0e10cSrcweir 
1199cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1200cdf0e10cSrcweir         // DXRenderModule::getAdapterFromWindow
1201cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1202cdf0e10cSrcweir 
getAdapterFromWindow()1203cdf0e10cSrcweir         UINT DXRenderModule::getAdapterFromWindow()
1204cdf0e10cSrcweir         {
1205cdf0e10cSrcweir             HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd));
1206cdf0e10cSrcweir             UINT aAdapterCount(mpDirect3D9->GetAdapterCount());
1207cdf0e10cSrcweir             for(UINT i=0; i<aAdapterCount; ++i)
1208cdf0e10cSrcweir                 if(hMonitor == mpDirect3D9->GetAdapterMonitor(i))
1209cdf0e10cSrcweir                     return i;
1210cdf0e10cSrcweir             return static_cast<UINT>(-1);
1211cdf0e10cSrcweir         }
1212cdf0e10cSrcweir 
1213cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1214cdf0e10cSrcweir         // DXRenderModule::commitVertexCache
1215cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1216cdf0e10cSrcweir 
commitVertexCache()1217cdf0e10cSrcweir         void DXRenderModule::commitVertexCache()
1218cdf0e10cSrcweir         {
1219cdf0e10cSrcweir             if(maReadIndex != maWriteIndex)
1220cdf0e10cSrcweir             {
1221cdf0e10cSrcweir                 const std::size_t nVertexStride = sizeof(dxvertex);
1222cdf0e10cSrcweir                 const unsigned int nNumVertices = maWriteIndex-maReadIndex;
1223cdf0e10cSrcweir                 const unsigned int nNumPrimitives = nNumVertices / 3;
1224cdf0e10cSrcweir 
1225cdf0e10cSrcweir                 if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride)))
1226cdf0e10cSrcweir                     return;
1227cdf0e10cSrcweir 
1228cdf0e10cSrcweir                 if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1229cdf0e10cSrcweir                     return;
1230cdf0e10cSrcweir 
1231cdf0e10cSrcweir                 if(FAILED(mpDevice->BeginScene()))
1232cdf0e10cSrcweir                     return;
1233cdf0e10cSrcweir 
1234cdf0e10cSrcweir                 mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives));
1235cdf0e10cSrcweir                 mbError |= FAILED(mpDevice->EndScene());
1236cdf0e10cSrcweir 
1237cdf0e10cSrcweir                 maReadIndex += nNumVertices;
1238cdf0e10cSrcweir             }
1239cdf0e10cSrcweir         }
1240cdf0e10cSrcweir 
1241cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1242cdf0e10cSrcweir         // DXRenderModule::flushVertexCache
1243cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////////
1244cdf0e10cSrcweir 
flushVertexCache()1245cdf0e10cSrcweir         void DXRenderModule::flushVertexCache()
1246cdf0e10cSrcweir         {
1247cdf0e10cSrcweir             if(!(maVertexCache.size()))
1248cdf0e10cSrcweir                 return;
1249cdf0e10cSrcweir 
1250cdf0e10cSrcweir             mbError=true;
1251cdf0e10cSrcweir 
1252cdf0e10cSrcweir             if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1253cdf0e10cSrcweir                 return;
1254cdf0e10cSrcweir 
1255cdf0e10cSrcweir             // enable texture alpha blending
1256cdf0e10cSrcweir             if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1257cdf0e10cSrcweir                 return;
1258cdf0e10cSrcweir 
1259cdf0e10cSrcweir             mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1260cdf0e10cSrcweir             mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1261cdf0e10cSrcweir             mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1262cdf0e10cSrcweir             mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1263cdf0e10cSrcweir 
1264cdf0e10cSrcweir             // configure the fixed-function pipeline.
1265cdf0e10cSrcweir             // the only 'feature' we need here is to modulate the alpha-channels
1266cdf0e10cSrcweir             // from the texture and the interpolated diffuse color. the result
1267cdf0e10cSrcweir             // will then be blended with the backbuffer.
1268cdf0e10cSrcweir             // fragment color = texture color * diffuse.alpha.
1269cdf0e10cSrcweir             mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1270cdf0e10cSrcweir             mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1271cdf0e10cSrcweir             mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1272cdf0e10cSrcweir 
1273cdf0e10cSrcweir             // normal combination of object...
1274cdf0e10cSrcweir             if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1275cdf0e10cSrcweir                 return;
1276cdf0e10cSrcweir 
1277cdf0e10cSrcweir             // ..and background color
1278cdf0e10cSrcweir             if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1279cdf0e10cSrcweir                 return;
1280cdf0e10cSrcweir 
1281cdf0e10cSrcweir             // disable backface culling; this enables us to mirror sprites
1282cdf0e10cSrcweir             // by simply reverting the triangles, which, with enabled
1283cdf0e10cSrcweir             // culling, would be invisible otherwise
1284cdf0e10cSrcweir             if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1285cdf0e10cSrcweir                 return;
1286cdf0e10cSrcweir 
1287cdf0e10cSrcweir             mbError=false;
1288cdf0e10cSrcweir 
1289cdf0e10cSrcweir             std::size_t nSize(maVertexCache.size());
1290cdf0e10cSrcweir             const std::size_t nVertexStride = sizeof(dxvertex);
1291cdf0e10cSrcweir 
1292cdf0e10cSrcweir             const ::basegfx::B2IVector aPageSize(getPageSize());
1293cdf0e10cSrcweir             const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1294cdf0e10cSrcweir             const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1295cdf0e10cSrcweir             vertexCache_t::const_iterator it(maVertexCache.begin());
1296cdf0e10cSrcweir 
1297cdf0e10cSrcweir             while( nSize )
1298cdf0e10cSrcweir             {
1299cdf0e10cSrcweir                 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1300cdf0e10cSrcweir 
1301cdf0e10cSrcweir                 // Check to see if there's space for the current set of
1302cdf0e10cSrcweir                 // vertices in the buffer.
1303cdf0e10cSrcweir                 if( maNumVertices - maWriteIndex < nSize )
1304cdf0e10cSrcweir                 {
1305cdf0e10cSrcweir                     commitVertexCache();
1306cdf0e10cSrcweir                     dwLockFlags = D3DLOCK_DISCARD;
1307cdf0e10cSrcweir                     maWriteIndex = 0;
1308cdf0e10cSrcweir                     maReadIndex = 0;
1309cdf0e10cSrcweir                 }
1310cdf0e10cSrcweir 
1311cdf0e10cSrcweir                 dxvertex *vertices(NULL);
1312cdf0e10cSrcweir                 const std::size_t nNumVertices(
1313cdf0e10cSrcweir                     std::min(maNumVertices - maWriteIndex,
1314cdf0e10cSrcweir                              nSize));
1315cdf0e10cSrcweir                 if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride,
1316cdf0e10cSrcweir                                                nNumVertices*nVertexStride,
1317cdf0e10cSrcweir                                                (void **)&vertices,
1318cdf0e10cSrcweir                                                dwLockFlags)))
1319cdf0e10cSrcweir                     return;
1320cdf0e10cSrcweir 
1321cdf0e10cSrcweir                 std::size_t nIndex(0);
1322cdf0e10cSrcweir                 while( nIndex < nNumVertices )
1323cdf0e10cSrcweir                 {
1324cdf0e10cSrcweir                     dxvertex &dest = vertices[nIndex++];
1325cdf0e10cSrcweir                     dest.x=it->x;
1326cdf0e10cSrcweir                     dest.y=it->y;
1327cdf0e10cSrcweir                     dest.z=it->z;
1328cdf0e10cSrcweir                     dest.rhw=1;
1329cdf0e10cSrcweir                     const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f));
1330cdf0e10cSrcweir                     dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1331cdf0e10cSrcweir                     dest.u=static_cast<float>(it->u + nHalfPixelSizeX);
1332cdf0e10cSrcweir                     dest.v=static_cast<float>(it->v + nHalfPixelSizeY);
1333cdf0e10cSrcweir                     ++it;
1334cdf0e10cSrcweir                 }
1335cdf0e10cSrcweir 
1336cdf0e10cSrcweir                 mpVertexBuffer->Unlock();
1337cdf0e10cSrcweir 
1338cdf0e10cSrcweir                 // Advance to the next position in the vertex buffer.
1339cdf0e10cSrcweir                 maWriteIndex += nNumVertices;
1340cdf0e10cSrcweir                 nSize -= nNumVertices;
1341cdf0e10cSrcweir 
1342cdf0e10cSrcweir                 commitVertexCache();
1343cdf0e10cSrcweir             }
1344cdf0e10cSrcweir 
1345cdf0e10cSrcweir             maVertexCache.clear();
1346cdf0e10cSrcweir         }
1347cdf0e10cSrcweir     }
1348cdf0e10cSrcweir 
1349cdf0e10cSrcweir     //////////////////////////////////////////////////////////////////////////////////
1350cdf0e10cSrcweir     // createRenderModule
1351cdf0e10cSrcweir     //////////////////////////////////////////////////////////////////////////////////
1352cdf0e10cSrcweir 
createRenderModule(const::Window & rParent)1353cdf0e10cSrcweir     IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
1354cdf0e10cSrcweir     {
1355cdf0e10cSrcweir         return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
1356cdf0e10cSrcweir     }
1357cdf0e10cSrcweir }
1358cdf0e10cSrcweir 
1359cdf0e10cSrcweir #endif
1360