31#include <com/sun/star/lang/NoSupportException.hpp>
32#include <osl/thread.hxx>
49#define MIN_TEXTURE_SIZE (32)
53#define VERTEX_BUFFER_SIZE (341*3)
86 DXSurface( DXRenderModule& rRenderModule,
87 const ::basegfx::B2ISize& rSize );
88 ~DXSurface()
override;
90 virtual bool selectTexture()
override;
91 virtual bool isValid()
override;
92 virtual bool update( const ::basegfx::B2IPoint& rDestPos,
93 const ::basegfx::B2IRange& rSourceRect,
95 virtual ::basegfx::B2IVector getSize();
99 class ImplRenderModuleGuard
103 ImplRenderModuleGuard(
const ImplRenderModuleGuard&) =
delete;
104 const ImplRenderModuleGuard& operator=(
const ImplRenderModuleGuard&) =
delete;
106 explicit ImplRenderModuleGuard( DXRenderModule& rRenderModule );
107 ~ImplRenderModuleGuard();
114 sal::systools::COMReference<IDirect3DTexture9>
mpTexture;
124 class DXRenderModule final:
public IDXRenderModule
127 explicit DXRenderModule(
const vcl::Window& rWindow );
128 ~DXRenderModule()
override;
130 virtual void lock()
const override {
maMutex.acquire(); }
131 virtual void unlock()
const override {
maMutex.release(); }
133 virtual sal::systools::COMReference<IDirect3DSurface9>
134 createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
override;
135 virtual void disposing()
override;
136 virtual HWND getHWND()
const override {
return mhWnd; }
137 virtual void screenShot()
override;
139 virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
140 const ::basegfx::B2IRectangle& rCurrWindowArea )
override;
142 virtual void resize( const ::basegfx::B2IRange& rect )
override;
143 virtual ::basegfx::B2IVector getPageSize()
override;
144 virtual std::shared_ptr<canvas::ISurface> createSurface( const ::basegfx::B2IVector& surfaceSize )
override;
145 virtual void beginPrimitive( PrimitiveType eType )
override;
146 virtual void endPrimitive()
override;
147 virtual void pushVertex( const ::canvas::Vertex& vertex )
override;
148 virtual bool isError()
override;
150 sal::systools::COMReference<IDirect3DDevice9> getDevice() {
return mpDevice; }
152 void flushVertexCache();
153 void commitVertexCache();
159 bool verifyDevice(
const UINT nAdapter );
160 UINT getAdapterFromWindow();
169 sal::systools::COMReference<IDirect3DDevice9>
mpDevice;
173 std::shared_ptr<canvas::ISurface>
mpTexture;
176 typedef std::vector<canvas::Vertex> vertexCache_t;
186 bool isDisposed()
const {
return (
mhWnd==
nullptr); }
206 DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
207 DXRenderModule& rRenderModule ) :
213 DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
218#ifdef FAKE_MAX_NUMBER_TEXTURES
219 static sal_uInt32 gNumSurfaces = 0;
225 DXSurface::DXSurface( DXRenderModule& rRenderModule,
226 const ::basegfx::B2ISize& rSize ) :
233#ifdef FAKE_MAX_NUMBER_TEXTURES
235 if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
239#ifdef FAKE_MAX_TEXTURE_SIZE
240 if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
242 if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
247 "DXSurface::DXSurface(): request for zero-sized surface");
249 sal::systools::COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
251 IDirect3DTexture9 *pTexture(
nullptr);
252 if(FAILED(pDevice->CreateTexture(
260 mpTexture = sal::systools::COMReference<IDirect3DTexture9>(pTexture,
false);
268 DXSurface::~DXSurface()
272#ifdef FAKE_MAX_NUMBER_TEXTURES
281 bool DXSurface::selectTexture()
285 sal::systools::COMReference<IDirect3DDevice9> pDevice(
mrRenderModule.getDevice());
287 if( FAILED(pDevice->SetTexture(0,
mpTexture.get())) )
297 bool DXSurface::isValid()
310 bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
311 const ::basegfx::B2IRange& rSourceRect,
321 D3DLOCKED_RECT aLockedRect;
323 rect.left =
std::max(sal_Int32(0),rDestPos.getX());
324 rect.top =
std::max(sal_Int32(0),rDestPos.getY());
329 rect.left + sal_Int32(rSourceRect.getWidth()+1));
331 rect.top + sal_Int32(rSourceRect.getHeight()+1));
332 const bool bClearRightColumn( rect.right <
maSize.
getX() );
333 const bool bClearBottomRow( rect.bottom <
maSize.
getY() );
335 if(SUCCEEDED(
mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
341 case ::canvas::IColorBuffer::Format::A8R8G8B8:
343 const std::size_t nSourceBytesPerPixel(4);
344 const std::size_t nSourcePitchInBytes(rSource.
getStride());
345 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
346 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
351 const sal_uInt32 nNumBytesToCopy(
352 static_cast<sal_uInt32
>(
353 rSourceRect.getWidth())*
354 nSourceBytesPerPixel);
355 const sal_uInt64 nNumLines(rSourceRect.getHeight());
357 for(sal_uInt64 i=0;
i<nNumLines; ++
i)
359 memcpy(pDst,pImage,nNumBytesToCopy);
361 if( bClearRightColumn )
368 pDst[nNumBytesToCopy] =
369 pDst[nNumBytesToCopy+1] =
370 pDst[nNumBytesToCopy+2] =
371 pDst[nNumBytesToCopy+3] = 0x00;
373 pDst += aLockedRect.Pitch;
374 pImage += nSourcePitchInBytes;
377 if( bClearBottomRow )
378 memset(pDst, 0, nNumBytesToCopy+4);
382 case ::canvas::IColorBuffer::Format::X8R8G8B8:
384 const std::size_t nSourceBytesPerPixel(4);
385 const std::size_t nSourcePitchInBytes(rSource.
getStride());
386 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
387 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
392 const sal_Int32 nNumLines(
393 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
394 const sal_Int32 nNumColumns(
395 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
396 for(sal_Int32 i=0;
i<nNumLines; ++
i)
398 sal_uInt32 *pSrc32 =
reinterpret_cast<sal_uInt32 *
>(pImage);
399 sal_uInt32 *pDst32 =
reinterpret_cast<sal_uInt32 *
>(pDst);
400 for(sal_Int32 j=0; j<nNumColumns; ++j)
401 pDst32[j] = 0xFF000000 | pSrc32[j];
403 if( bClearRightColumn )
404 pDst32[nNumColumns] = 0xFF000000;
406 pDst += aLockedRect.Pitch;
407 pImage += nSourcePitchInBytes;
410 if( bClearBottomRow )
411 memset(pDst, 0, 4*(nNumColumns+1));
417 "DXSurface::update(): Unknown/unimplemented buffer format" );
424 return SUCCEEDED(
mpTexture->UnlockRect(0));
442 DXRenderModule::DXRenderModule(
const vcl::Window& rWindow ) :
463 ::osl::MutexGuard aGuard(
maMutex );
467 throw lang::NoSupportException(
"Could not create DirectX device!" );
475 mpTexture = std::make_shared<DXSurface>(*
this,aPageSize);
479 aPageSize.setX(aPageSize.getX()>>1);
480 aPageSize.setY(aPageSize.getY()>>1);
484 throw lang::NoSupportException(
485 "Could not create DirectX device - insufficient texture space!" );
490 IDirect3DVertexBuffer9 *pVB(
nullptr);
492 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
493 D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
498 throw lang::NoSupportException(
499 "Could not create DirectX device - out of memory!" );
502 mpVertexBuffer = sal::systools::COMReference<IDirect3DVertexBuffer9>(pVB,
false);
509 DXRenderModule::~DXRenderModule()
518 void DXRenderModule::disposing()
537 bool DXRenderModule::create(
const vcl::Window& rWindow )
540 ::osl::MutexGuard aGuard(
maMutex );
545 mpDirect3D9 = sal::systools::COMReference<IDirect3D9>(
546 Direct3DCreate9(D3D_SDK_VERSION),
false);
557 mpWindow->SetMouseTransparent(
true );
560 mpWindow->SetParentClipMode(ParentClipMode::NoClip);
563 mpWindow->EnableEraseBackground(
false );
569 const HWND hwnd(
reinterpret_cast<HWND
>(
pData->hWnd));
573 "DXRenderModule::create() No valid HWND given." );
580 maSize.
setX(
static_cast<sal_Int32
>(rSizePixel.Width()));
581 maSize.
setY(
static_cast<sal_Int32
>(rSizePixel.Height()));
587 if(!(createDevice()))
602 bool DXRenderModule::verifyDevice(
const UINT nAdapter )
605 "DXRenderModule::verifyDevice() No valid device." );
612 if(FAILED(
mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
614 if(!(aCaps.MaxTextureWidth))
616 if(!(aCaps.MaxTextureHeight))
621 D3DADAPTER_IDENTIFIER9 aIdent;
622 if(FAILED(
mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
625 DXCanvasItem aConfigItem;
626 DXCanvasItem::DeviceInfo aInfo;
627 aInfo.nVendorId = aIdent.VendorId;
628 aInfo.nDeviceId = aIdent.DeviceId;
629 aInfo.nDeviceSubSysId = aIdent.SubSysId;
630 aInfo.nDeviceRevision = aIdent.Revision;
632 aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
633 aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
634 aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
635 aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
637 if( !aConfigItem.isDeviceUsable(aInfo) )
640 if( aConfigItem.isDenylistCurrentDevice() )
642 aConfigItem.denylistDevice(aInfo);
657 bool DXRenderModule::createDevice()
661 "DXRenderModule::createDevice() No valid HWND given." );
665 "DXRenderModule::createDevice() no direct3d?." );
668 const UINT aAdapter(getAdapterFromWindow());
669 if(aAdapter ==
static_cast<UINT
>(-1))
673 if( !verifyDevice(aAdapter) )
679 D3DDISPLAYMODE d3ddm;
680 mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
701 sal_Int32(d3ddm.Width));
703 sal_Int32(d3ddm.Height));
706 mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
707 mad3dpp.BackBufferFormat = d3ddm.Format;
710 mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
715 IDirect3DDevice9 *pDevice(
nullptr);
719 D3DCREATE_HARDWARE_VERTEXPROCESSING|
720 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
726 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
727 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
733 mpDevice = sal::systools::COMReference<IDirect3DDevice9>(pDevice,
false);
736 IDirect3DSwapChain9 *pSwapChain(
nullptr);
737 pDevice->GetSwapChain(0,&pSwapChain);
738 mpSwapChain = sal::systools::COMReference<IDirect3DSwapChain9>(pSwapChain,
false);
747 LPDIRECT3DSURFACE9 pBackBuffer =
nullptr;
748 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
749 mpDevice->SetRenderTarget( 0, pBackBuffer );
750 mpDevice->Clear(0,
nullptr,D3DCLEAR_TARGET,0,1.0f,0);
751 pBackBuffer->Release();
760 sal::systools::COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
763 return sal::systools::COMReference<IDirect3DSurface9>(
nullptr);
768 IDirect3DSurface9 *pSurface(
nullptr);
769 if( FAILED(
mpDevice->CreateOffscreenPlainSurface(
777 throw lang::NoSupportException(
778 "Could not create offscreen surface - out of mem!" );
781 return sal::systools::COMReference<IDirect3DSurface9>(pSurface,
false);
788 bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
789 const ::basegfx::B2IRectangle& )
792 ::osl::MutexGuard aGuard(
maMutex );
802 rUpdateArea.getMinX(),
803 rUpdateArea.getMinY(),
804 rUpdateArea.getMaxX(),
805 rUpdateArea.getMaxY()
807 HRESULT
hr(
mpSwapChain->Present(&aRect,&aRect,
nullptr,
nullptr,0));
810 if(hr != D3DERR_DEVICELOST)
822 IDirect3DVertexBuffer9 *pVB(
nullptr);
824 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
825 D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
830 throw lang::NoSupportException(
831 "Could not create DirectX device - out of memory!" );
833 mpVertexBuffer = sal::systools::COMReference<IDirect3DVertexBuffer9>(pVB,
false);
836 if(SUCCEEDED(
mpSwapChain->Present(&aRect,&aRect,
nullptr,
nullptr,0)))
840 osl::Thread::wait(std::chrono::seconds(1));
842 while(hr == D3DERR_DEVICELOST);
854 void DXRenderModule::screenShot()
862 void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
865 ::osl::MutexGuard aGuard(
maMutex );
871 if(
maSize.
getX() ==
static_cast<sal_Int32
>(rect.getWidth()) &&
872 maSize.
getY() ==
static_cast<sal_Int32
>(rect.getHeight()))
876 maSize.
setX(
static_cast<sal_Int32
>(rect.getWidth()));
877 maSize.
setY(
static_cast<sal_Int32
>(rect.getHeight()));
902 IDirect3DSwapChain9 *pSwapChain(
nullptr);
905 mpSwapChain = sal::systools::COMReference<IDirect3DSwapChain9>(pSwapChain,
false);
912 LPDIRECT3DSURFACE9 pBackBuffer =
nullptr;
913 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
914 mpDevice->SetRenderTarget( 0, pBackBuffer );
915 mpDevice->Clear(0,
nullptr,D3DCLEAR_TARGET,0,1.0f,0);
916 pBackBuffer->Release();
927 ::osl::MutexGuard aGuard(
maMutex );
935 std::shared_ptr<canvas::ISurface> DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
938 ::osl::MutexGuard aGuard(
maMutex );
941 return std::shared_ptr<canvas::ISurface>();
943 const ::basegfx::B2IVector& rPageSize( getPageSize() );
946 aSize.setX(rPageSize.getX());
948 aSize.setY(rPageSize.getY());
953 return std::make_shared<DXSurface>(*
this,aSize);
960 void DXRenderModule::beginPrimitive( PrimitiveType eType )
963 ::osl::MutexGuard aGuard(
maMutex );
969 "DXRenderModule::beginPrimitive(): nested call" );
980 void DXRenderModule::endPrimitive()
983 ::osl::MutexGuard aGuard(
maMutex );
989 meType = PrimitiveType::Unknown;
997 void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
1000 ::osl::MutexGuard aGuard(
maMutex );
1007 case PrimitiveType::Triangle:
1015 case PrimitiveType::Quad:
1036 SAL_WARN(
"canvas.directx",
"DXRenderModule::pushVertex(): unexpected primitive type");
1045 bool DXRenderModule::isError()
1048 ::osl::MutexGuard aGuard(
maMutex );
1057 UINT DXRenderModule::getAdapterFromWindow()
1059 HMONITOR hMonitor(MonitorFromWindow(
mhWnd, MONITOR_DEFAULTTONEAREST));
1060 UINT aAdapterCount(
mpDirect3D9->GetAdapterCount());
1061 for(UINT i=0;
i<aAdapterCount; ++
i)
1064 return static_cast<UINT
>(-1);
1071 void DXRenderModule::commitVertexCache()
1075 const std::size_t nVertexStride =
sizeof(dxvertex);
1077 const unsigned int nNumPrimitives = nNumVertices / 3;
1082 if(FAILED(
mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1099 void DXRenderModule::flushVertexCache()
1106 if( FAILED(
mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1110 if( FAILED(
mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1113 mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1114 mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1115 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1116 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1123 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1124 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1125 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1128 if( FAILED(
mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1132 if( FAILED(
mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1138 if( FAILED(
mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1144 const std::size_t nVertexStride =
sizeof(dxvertex);
1146 const ::basegfx::B2IVector aPageSize(getPageSize());
1147 const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1148 const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1153 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1159 commitVertexCache();
1160 dwLockFlags = D3DLOCK_DISCARD;
1165 dxvertex *vertices(
nullptr);
1166 const std::size_t nNumVertices(
1170 nNumVertices*nVertexStride,
1171 reinterpret_cast<void **
>(&vertices),
1176 while( nIndex < nNumVertices )
1178 dxvertex &dest = vertices[
nIndex++];
1183 const sal_uInt32 alpha(
static_cast<sal_uInt32
>(it->a*255.0f));
1184 dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1185 dest.u=
static_cast<float>(it->u + nHalfPixelSizeX);
1186 dest.v=
static_cast<float>(it->v + nHalfPixelSizeY);
1194 nSize -= nNumVertices;
1196 commitVertexCache();
1209 return std::make_shared<DXRenderModule>(rParent);
void reset(reference_type *pBody)
virtual Size GetSizePixel() const
#define ENSURE_OR_RETURN_FALSE(c, m)
#define ENSURE_OR_THROW(c, m)
#define ENSURE_ARG_OR_THROW(c, m)
#define VERTEX_BUFFER_SIZE
sal::systools::COMReference< IDirect3DTexture9 > mpTexture
VclPtr< SystemChildWindow > mpWindow
::basegfx::B2IVector maSize
DXRenderModule & mrRenderModule
bool mbCanUseDynamicTextures
std::size_t maNumVertices
::osl::Mutex maMutex
This object represents the DirectX state machine.
sal::systools::COMReference< IDirect3DDevice9 > mpDevice
sal::systools::COMReference< IDirect3DSwapChain9 > mpSwapChain
D3DPRESENT_PARAMETERS mad3dpp
sal::systools::COMReference< IDirect3DVertexBuffer9 > mpVertexBuffer
::basegfx::B2IVector maPageSize
sal::systools::COMReference< IDirect3D9 > mpDirect3D9
vertexCache_t maVertexCache
#define SAL_WARN(area, stream)
std::unique_ptr< sal_Int32[]> pData
std::shared_ptr< osl::Mutex > const & lock()
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
std::shared_ptr< IDXRenderModule > IDXRenderModuleSharedPtr
IDXRenderModuleSharedPtr createRenderModule(const vcl::Window &rParent)
Factory method, to create an IRenderModule instance for the given VCL window instance.
Interface for a raw memory pixel container.
virtual void unlock() const =0
unlock previous locked buffer
virtual sal_uInt8 * lock() const =0
Get a pointer to the raw memory bits of the pixel.
virtual sal_uInt32 getStride() const =0
Offset, in bytes, between consecutive scan lines of the bitmap.
virtual Format getFormat() const =0
Get format of the color buffer.