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::B2ISize 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::B2ISize& 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 ) :
232#ifdef FAKE_MAX_NUMBER_TEXTURES
234 if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
238#ifdef FAKE_MAX_TEXTURE_SIZE
239 if(rSize.getWidth() > FAKE_MAX_TEXTURE_SIZE)
241 if(rSize.getHeight() > FAKE_MAX_TEXTURE_SIZE)
246 "DXSurface::DXSurface(): request for zero-sized surface");
248 sal::systools::COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
250 IDirect3DTexture9 *pTexture(
nullptr);
251 if(FAILED(pDevice->CreateTexture(
259 mpTexture = sal::systools::COMReference<IDirect3DTexture9>(pTexture,
false);
267 DXSurface::~DXSurface()
271#ifdef FAKE_MAX_NUMBER_TEXTURES
280 bool DXSurface::selectTexture()
284 sal::systools::COMReference<IDirect3DDevice9> pDevice(
mrRenderModule.getDevice());
286 if( FAILED(pDevice->SetTexture(0,
mpTexture.get())) )
296 bool DXSurface::isValid()
309 bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
310 const ::basegfx::B2IRange& rSourceRect,
320 D3DLOCKED_RECT aLockedRect;
322 rect.left =
std::max(sal_Int32(0),rDestPos.getX());
323 rect.top =
std::max(sal_Int32(0),rDestPos.getY());
328 rect.left + sal_Int32(rSourceRect.getWidth()+1));
330 rect.top + sal_Int32(rSourceRect.getHeight()+1));
334 if(SUCCEEDED(
mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
340 case ::canvas::IColorBuffer::Format::A8R8G8B8:
342 const std::size_t nSourceBytesPerPixel(4);
343 const std::size_t nSourcePitchInBytes(rSource.
getStride());
344 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
345 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
350 const sal_uInt32 nNumBytesToCopy(
351 static_cast<sal_uInt32
>(
352 rSourceRect.getWidth())*
353 nSourceBytesPerPixel);
354 const sal_uInt64 nNumLines(rSourceRect.getHeight());
356 for(sal_uInt64 i=0;
i<nNumLines; ++
i)
358 memcpy(pDst,pImage,nNumBytesToCopy);
360 if( bClearRightColumn )
367 pDst[nNumBytesToCopy] =
368 pDst[nNumBytesToCopy+1] =
369 pDst[nNumBytesToCopy+2] =
370 pDst[nNumBytesToCopy+3] = 0x00;
372 pDst += aLockedRect.Pitch;
373 pImage += nSourcePitchInBytes;
376 if( bClearBottomRow )
377 memset(pDst, 0, nNumBytesToCopy+4);
381 case ::canvas::IColorBuffer::Format::X8R8G8B8:
383 const std::size_t nSourceBytesPerPixel(4);
384 const std::size_t nSourcePitchInBytes(rSource.
getStride());
385 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
386 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
391 const sal_Int32 nNumLines(
392 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
393 const sal_Int32 nNumColumns(
394 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
395 for(sal_Int32 i=0;
i<nNumLines; ++
i)
397 sal_uInt32 *pSrc32 =
reinterpret_cast<sal_uInt32 *
>(pImage);
398 sal_uInt32 *pDst32 =
reinterpret_cast<sal_uInt32 *
>(pDst);
399 for(sal_Int32 j=0; j<nNumColumns; ++j)
400 pDst32[j] = 0xFF000000 | pSrc32[j];
402 if( bClearRightColumn )
403 pDst32[nNumColumns] = 0xFF000000;
405 pDst += aLockedRect.Pitch;
406 pImage += nSourcePitchInBytes;
409 if( bClearBottomRow )
410 memset(pDst, 0, 4*(nNumColumns+1));
416 "DXSurface::update(): Unknown/unimplemented buffer format" );
423 return SUCCEEDED(
mpTexture->UnlockRect(0));
434 DXRenderModule::DXRenderModule(
const vcl::Window& rWindow ) :
453 ::osl::MutexGuard aGuard(
maMutex );
457 throw lang::NoSupportException(
"Could not create DirectX device!" );
469 aPageSize.setX(aPageSize.getX()>>1);
470 aPageSize.setY(aPageSize.getY()>>1);
474 throw lang::NoSupportException(
475 "Could not create DirectX device - insufficient texture space!" );
480 IDirect3DVertexBuffer9 *pVB(
nullptr);
482 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
483 D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
488 throw lang::NoSupportException(
489 "Could not create DirectX device - out of memory!" );
492 mpVertexBuffer = sal::systools::COMReference<IDirect3DVertexBuffer9>(pVB,
false);
499 DXRenderModule::~DXRenderModule()
508 void DXRenderModule::disposing()
527 bool DXRenderModule::create(
const vcl::Window& rWindow )
530 ::osl::MutexGuard aGuard(
maMutex );
535 mpDirect3D9 = sal::systools::COMReference<IDirect3D9>(
536 Direct3DCreate9(D3D_SDK_VERSION),
false);
547 mpWindow->SetMouseTransparent(
true );
550 mpWindow->SetParentClipMode(ParentClipMode::NoClip);
553 mpWindow->EnableEraseBackground(
false );
559 const HWND hwnd(
reinterpret_cast<HWND
>(
pData->hWnd));
563 "DXRenderModule::create() No valid HWND given." );
577 if(!(createDevice()))
592 bool DXRenderModule::verifyDevice(
const UINT nAdapter )
595 "DXRenderModule::verifyDevice() No valid device." );
602 if(FAILED(
mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
604 if(!(aCaps.MaxTextureWidth))
606 if(!(aCaps.MaxTextureHeight))
611 D3DADAPTER_IDENTIFIER9 aIdent;
612 if(FAILED(
mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
615 DXCanvasItem aConfigItem;
616 DXCanvasItem::DeviceInfo aInfo;
617 aInfo.nVendorId = aIdent.VendorId;
618 aInfo.nDeviceId = aIdent.DeviceId;
619 aInfo.nDeviceSubSysId = aIdent.SubSysId;
620 aInfo.nDeviceRevision = aIdent.Revision;
622 aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
623 aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
624 aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
625 aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
627 if( !aConfigItem.isDeviceUsable(aInfo) )
630 if( aConfigItem.isDenylistCurrentDevice() )
632 aConfigItem.denylistDevice(aInfo);
647 bool DXRenderModule::createDevice()
651 "DXRenderModule::createDevice() No valid HWND given." );
655 "DXRenderModule::createDevice() no direct3d?." );
658 const UINT aAdapter(getAdapterFromWindow());
659 if(aAdapter ==
static_cast<UINT
>(-1))
663 if( !verifyDevice(aAdapter) )
669 D3DDISPLAYMODE d3ddm;
670 mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
694 mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
695 mad3dpp.BackBufferFormat = d3ddm.Format;
698 mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
703 IDirect3DDevice9 *pDevice(
nullptr);
707 D3DCREATE_HARDWARE_VERTEXPROCESSING|
708 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
714 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
715 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
721 mpDevice = sal::systools::COMReference<IDirect3DDevice9>(pDevice,
false);
724 IDirect3DSwapChain9 *pSwapChain(
nullptr);
725 pDevice->GetSwapChain(0,&pSwapChain);
726 mpSwapChain = sal::systools::COMReference<IDirect3DSwapChain9>(pSwapChain,
false);
735 LPDIRECT3DSURFACE9 pBackBuffer =
nullptr;
736 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
737 mpDevice->SetRenderTarget( 0, pBackBuffer );
738 mpDevice->Clear(0,
nullptr,D3DCLEAR_TARGET,0,1.0f,0);
739 pBackBuffer->Release();
748 sal::systools::COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface(const ::basegfx::B2ISize& rSize)
751 return sal::systools::COMReference<IDirect3DSurface9>(
nullptr);
756 IDirect3DSurface9 *pSurface(
nullptr);
757 if( FAILED(
mpDevice->CreateOffscreenPlainSurface(
765 throw lang::NoSupportException(
766 "Could not create offscreen surface - out of mem!" );
769 return sal::systools::COMReference<IDirect3DSurface9>(pSurface,
false);
776 bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
777 const ::basegfx::B2IRectangle& )
780 ::osl::MutexGuard aGuard(
maMutex );
790 rUpdateArea.getMinX(),
791 rUpdateArea.getMinY(),
792 rUpdateArea.getMaxX(),
793 rUpdateArea.getMaxY()
795 HRESULT
hr(
mpSwapChain->Present(&aRect,&aRect,
nullptr,
nullptr,0));
798 if(hr != D3DERR_DEVICELOST)
810 IDirect3DVertexBuffer9 *pVB(
nullptr);
812 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
813 D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
818 throw lang::NoSupportException(
819 "Could not create DirectX device - out of memory!" );
821 mpVertexBuffer = sal::systools::COMReference<IDirect3DVertexBuffer9>(pVB,
false);
824 if(SUCCEEDED(
mpSwapChain->Present(&aRect,&aRect,
nullptr,
nullptr,0)))
828 osl::Thread::wait(std::chrono::seconds(1));
830 while(hr == D3DERR_DEVICELOST);
842 void DXRenderModule::screenShot()
850 void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
853 ::osl::MutexGuard aGuard(
maMutex );
859 if(
maSize.
getWidth() ==
static_cast<sal_Int32
>(rect.getWidth()) &&
890 IDirect3DSwapChain9 *pSwapChain(
nullptr);
893 mpSwapChain = sal::systools::COMReference<IDirect3DSwapChain9>(pSwapChain,
false);
900 LPDIRECT3DSURFACE9 pBackBuffer =
nullptr;
901 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
902 mpDevice->SetRenderTarget( 0, pBackBuffer );
903 mpDevice->Clear(0,
nullptr,D3DCLEAR_TARGET,0,1.0f,0);
904 pBackBuffer->Release();
915 ::osl::MutexGuard aGuard(
maMutex );
923 std::shared_ptr<canvas::ISurface> DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
926 ::osl::MutexGuard aGuard(
maMutex );
929 return std::shared_ptr<canvas::ISurface>();
931 const ::basegfx::B2IVector& rPageSize( getPageSize() );
933 if(!(aSize.getWidth()))
934 aSize.setWidth(rPageSize.getX());
935 if(!(aSize.getHeight()))
936 aSize.setHeight(rPageSize.getY());
941 return std::make_shared<DXSurface>(*
this,aSize);
948 void DXRenderModule::beginPrimitive( PrimitiveType eType )
951 ::osl::MutexGuard aGuard(
maMutex );
957 "DXRenderModule::beginPrimitive(): nested call" );
968 void DXRenderModule::endPrimitive()
971 ::osl::MutexGuard aGuard(
maMutex );
977 meType = PrimitiveType::Unknown;
985 void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
988 ::osl::MutexGuard aGuard(
maMutex );
995 case PrimitiveType::Triangle:
1003 case PrimitiveType::Quad:
1024 SAL_WARN(
"canvas.directx",
"DXRenderModule::pushVertex(): unexpected primitive type");
1033 bool DXRenderModule::isError()
1036 ::osl::MutexGuard aGuard(
maMutex );
1045 UINT DXRenderModule::getAdapterFromWindow()
1047 HMONITOR hMonitor(MonitorFromWindow(
mhWnd, MONITOR_DEFAULTTONEAREST));
1048 UINT aAdapterCount(
mpDirect3D9->GetAdapterCount());
1049 for(UINT i=0;
i<aAdapterCount; ++
i)
1052 return static_cast<UINT
>(-1);
1059 void DXRenderModule::commitVertexCache()
1063 const std::size_t nVertexStride =
sizeof(dxvertex);
1065 const unsigned int nNumPrimitives = nNumVertices / 3;
1070 if(FAILED(
mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1087 void DXRenderModule::flushVertexCache()
1094 if( FAILED(
mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1098 if( FAILED(
mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1101 mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1102 mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1103 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1104 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1111 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1112 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1113 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1116 if( FAILED(
mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1120 if( FAILED(
mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1126 if( FAILED(
mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1132 const std::size_t nVertexStride =
sizeof(dxvertex);
1134 const ::basegfx::B2IVector aPageSize(getPageSize());
1135 const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1136 const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1141 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1147 commitVertexCache();
1148 dwLockFlags = D3DLOCK_DISCARD;
1153 dxvertex *vertices(
nullptr);
1154 const std::size_t nNumVertices(
1158 nNumVertices*nVertexStride,
1159 reinterpret_cast<void **
>(&vertices),
1164 while( nIndex < nNumVertices )
1166 dxvertex &dest = vertices[
nIndex++];
1171 const sal_uInt32
alpha(
static_cast<sal_uInt32
>(it->a*255.0f));
1172 dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1173 dest.u=
static_cast<float>(it->u + nHalfPixelSizeX);
1174 dest.v=
static_cast<float>(it->v + nHalfPixelSizeY);
1182 nSize -= nNumVertices;
1184 commitVertexCache();
1197 return std::make_shared<DXRenderModule>(rParent);
void reset(reference_type *pBody)
void setHeight(TYPE const &rHeight)
void setWidth(TYPE const &rWidth)
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
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
::basegfx::B2ISize maSize
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.
constexpr double alpha[nDetails]
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.