1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stddirect3d.h"
22 #include "nel/3d/vertex_buffer.h"
23 #include "nel/3d/light.h"
24 #include "nel/3d/index_buffer.h"
25 #include "nel/misc/rect.h"
26 #include "nel/3d/viewport.h"
27 #include "nel/3d/scissor.h"
28 #include "nel/3d/u_driver.h"
30 #include "driver_direct3d.h"
37 using namespace NLMISC
;
43 std::vector
<uint8
> CDriverD3D::_TempBuffer
;
45 // ***************************************************************************
47 CTextureDrvInfosD3D::CTextureDrvInfosD3D(IDriver
*drv
, ItTexDrvInfoPtrMap it
, CDriverD3D
*drvD3D
, bool renderTarget
)
48 : ITextureDrvInfos(drv
, it
)
50 H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3D
)
55 RenderTarget
= renderTarget
;
58 // Nb: at Driver dtor, all tex infos are deleted, so _Driver is always valid.
61 WrapS
= D3DTADDRESS_WRAP
;
62 WrapT
= D3DTADDRESS_WRAP
;
63 MagFilter
= D3DTEXF_POINT
;
64 MinFilter
= D3DTEXF_POINT
;
65 MipFilter
= D3DTEXF_NONE
;
68 // ***************************************************************************
70 CTextureDrvInfosD3D::~CTextureDrvInfosD3D()
72 H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3DDtor
)
75 // If a texture is in the cache state -> set to null (texture no more used)
76 for (uint32 i
= 0; i
< CDriverD3D::MaxTexture
; ++i
)
77 if (_Driver
->_TexturePtrStateCache
[i
].Texture
== Texture
)
78 _Driver
->setTexture(i
, (LPDIRECT3DBASETEXTURE9
)NULL
);
86 // release profiling texture mem.
87 _Driver
->_AllocatedTextureMemory
-= TextureMemory
;
89 // release in TextureUsed.
90 _Driver
->_TextureUsed
.erase (this);
93 // ***************************************************************************
95 bool CDriverD3D::setupTexture (ITexture
& tex
)
97 H_AUTO_D3D(CDriverD3D_setupTexture
)
99 return setupTextureEx (tex
, true, nTmp
, false);
102 // ***************************************************************************
104 const D3DTEXTUREADDRESS RemapTextureAdressTypeNeL2D3D
[ITexture::WrapModeCount
]=
106 D3DTADDRESS_WRAP
, // Repeat
107 D3DTADDRESS_CLAMP
, // Clamp
110 // ***************************************************************************
112 const D3DTEXTUREFILTERTYPE RemapMagTextureFilterTypeNeL2D3D
[ITexture::MagFilterCount
]=
114 D3DTEXF_POINT
, // Nearest
115 D3DTEXF_LINEAR
, // Linear
118 // ***************************************************************************
120 const D3DTEXTUREFILTERTYPE RemapMinTextureFilterTypeNeL2D3D
[ITexture::MinFilterCount
]=
122 D3DTEXF_POINT
, // NearestMipMapOff
123 D3DTEXF_POINT
, // NearestMipMapNearest
124 D3DTEXF_POINT
, // NearestMipMapLinear
125 D3DTEXF_LINEAR
, // LinearMipMapOff
126 D3DTEXF_LINEAR
, // LinearMipMapNearest
127 D3DTEXF_LINEAR
, // LinearMipMapLinear
130 // ***************************************************************************
132 const D3DTEXTUREFILTERTYPE RemapMipTextureFilterTypeNeL2D3D
[ITexture::MinFilterCount
]=
134 D3DTEXF_NONE
, // NearestMipMapOff
135 D3DTEXF_POINT
, // NearestMipMapNearest
136 D3DTEXF_LINEAR
, // NearestMipMapLinear
137 D3DTEXF_NONE
, // LinearMipMapOff
138 D3DTEXF_POINT
, // LinearMipMapNearest
139 D3DTEXF_LINEAR
, // LinearMipMapLinear
142 // ***************************************************************************
144 const D3DFORMAT RemapTextureFormatTypeNeL2D3D
[CBitmap::ModeCount
]=
146 D3DFMT_A8R8G8B8
, // RGBA
147 D3DFMT_L8
, // Luminance
149 D3DFMT_A8L8
, // AlphaLuminance
150 D3DFMT_DXT1
, // DXTC1
151 D3DFMT_DXT1
, // DXTC1Alpha
152 D3DFMT_DXT3
, // DXTC3
153 D3DFMT_DXT5
, // DXTC5
157 // ***************************************************************************
159 const bool RemapTextureFormatCompressedTypeNeL2D3D
[CBitmap::ModeCount
]=
164 false, // AlphaLuminance
172 // ***************************************************************************
174 const D3DCUBEMAP_FACES RemapCubeFaceTypeNeL2D3D
[6]=
176 D3DCUBEMAP_FACE_POSITIVE_X
, // positive_x
177 D3DCUBEMAP_FACE_NEGATIVE_X
, // negative_x
178 D3DCUBEMAP_FACE_POSITIVE_Z
, // positive_y
179 D3DCUBEMAP_FACE_NEGATIVE_Z
, // negative_y
180 D3DCUBEMAP_FACE_POSITIVE_Y
, // positive_z
181 D3DCUBEMAP_FACE_NEGATIVE_Y
, // negative_z
184 // ***************************************************************************
186 D3DFORMAT
CDriverD3D::getD3DDestTextureFormat (ITexture
& tex
)
188 H_AUTO_D3D(CDriverD3D_getD3DDestTextureFormat
)
189 ITexture::TUploadFormat texfmt
= tex
.getUploadFormat();
191 // If auto, retrieve the pixel format of the bitmap.
192 if(texfmt
== ITexture::Auto
)
194 switch(tex
.getPixelFormat())
197 if(_ForceDXTCCompression
&& tex
.allowDegradation() )
198 texfmt
= ITexture::DXTC5
;
200 texfmt
= ITexture::RGBA8888
;
203 texfmt
= ITexture::DXTC1
;
205 case CBitmap::DXTC1Alpha
:
206 texfmt
= ITexture::DXTC1Alpha
;
209 texfmt
= ITexture::DXTC3
;
212 texfmt
= ITexture::DXTC5
;
214 case CBitmap::Luminance
:
215 texfmt
= ITexture::Luminance
;
218 texfmt
= ITexture::Alpha
;
220 case CBitmap::AlphaLuminance
:
221 texfmt
= ITexture::AlphaLuminance
;
224 texfmt
= ITexture::DsDt
;
226 default: texfmt
= ITexture::RGBA8888
; break;
230 // Get standard prefered tex format.
231 nlassert (texfmt
<ITexture::UploadFormatCount
);
232 return _PreferedTextureFormat
[texfmt
];
235 // ***************************************************************************
237 uint
getPixelFormatSize (D3DFORMAT destFormat
)
242 case D3DFMT_R8G8B8
: bits
=32; break;
243 case D3DFMT_A8R8G8B8
: bits
=32; break;
244 case D3DFMT_X8R8G8B8
: bits
=32; break;
245 case D3DFMT_R5G6B5
: bits
=16; break;
246 case D3DFMT_X1R5G5B5
: bits
=16; break;
247 case D3DFMT_A1R5G5B5
: bits
=16; break;
248 case D3DFMT_A4R4G4B4
: bits
=16; break;
249 case D3DFMT_R3G3B2
: bits
=8; break;
250 case D3DFMT_A8
: bits
=8; break;
251 case D3DFMT_A8R3G3B2
: bits
=16; break;
252 case D3DFMT_X4R4G4B4
: bits
=16; break;
253 case D3DFMT_A2B10G10R10
: bits
=32; break;
254 case D3DFMT_A8B8G8R8
: bits
=32; break;
255 case D3DFMT_X8B8G8R8
: bits
=32; break;
256 case D3DFMT_G16R16
: bits
=32; break;
257 case D3DFMT_A2R10G10B10
: bits
=32; break;
258 case D3DFMT_A16B16G16R16
: bits
=64; break;
259 case D3DFMT_A8P8
: bits
=16; break;
260 case D3DFMT_P8
: bits
=8; break;
261 case D3DFMT_L8
: bits
=8; break;
262 case D3DFMT_L16
: bits
=16; break;
263 case D3DFMT_A8L8
: bits
=16; break;
264 case D3DFMT_A4L4
: bits
=8; break;
265 case D3DFMT_V8U8
: bits
=16; break;
266 case D3DFMT_Q8W8V8U8
: bits
=32; break;
267 case D3DFMT_V16U16
: bits
=32; break;
268 case D3DFMT_Q16W16V16U16
: bits
=64; break;
269 case D3DFMT_CxV8U8
: bits
=16; break;
270 case D3DFMT_L6V5U5
: bits
=16; break;
271 case D3DFMT_X8L8V8U8
: bits
=32; break;
272 case D3DFMT_A2W10V10U10
: bits
=32; break;
273 case D3DFMT_G8R8_G8B8
: bits
=24; break;
274 case D3DFMT_R8G8_B8G8
: bits
=24; break;
275 case D3DFMT_DXT1
: bits
=4; break;
276 case D3DFMT_DXT2
: bits
=8; break;
277 case D3DFMT_DXT3
: bits
=8; break;
278 case D3DFMT_DXT4
: bits
=8; break;
279 case D3DFMT_DXT5
: bits
=8; break;
280 default: nlstop
; break; // unknown pixel format
285 // ***************************************************************************
287 uint32
CDriverD3D::computeTextureMemoryUsage (uint width
, uint height
, uint levels
, D3DFORMAT destFormat
, bool cube
)
289 H_AUTO_D3D(CDriverD3D_computeTextureMemoryUsage
)
291 uint bits
= getPixelFormatSize (destFormat
);
295 size
+= (width
* height
* bits
) >> 3;
296 width
= max((uint
)(width
>>1), 1U);
297 height
= max((uint
)(height
>>1), 1U);
305 // ***************************************************************************
307 bool CDriverD3D::generateD3DTexture (ITexture
& tex
, bool textureDegradation
, D3DFORMAT
&destFormat
, D3DFORMAT
&srcFormat
, bool &cube
)
309 H_AUTO_D3D(CDriverD3D_generateD3DTexture
)
310 // Regenerate all the texture.
313 // Is a cube texture ?
314 cube
= tex
.isTextureCube();
317 CTextureDrvInfosD3D
* d3dtext
;
318 d3dtext
= getTextureD3D(tex
);
324 bool srcFormatCompressed
= true;
325 bool renderTarget
= false;
326 const uint faceCount
= cube
?6:1;
328 uint firstMipMap
= 0;
329 for (face
=0; face
<faceCount
; face
++)
331 // Get the texture pointer
332 ITexture
*texture
= cube
?(static_cast<CTextureCube
*>(&tex
)->getTexture((CTextureCube::TFace
)face
)):&tex
;
334 // getD3DTextureFormat choose a d3d dest and a src format. src format should be the tex one.
337 srcFormatCompressed
= RemapTextureFormatCompressedTypeNeL2D3D
[texture
->getPixelFormat()];
338 srcFormat
= RemapTextureFormatTypeNeL2D3D
[texture
->getPixelFormat()];
339 destFormat
= getD3DDestTextureFormat (*texture
);
343 // All cube texture must have the same format
344 nlassert (srcFormatCompressed
== RemapTextureFormatCompressedTypeNeL2D3D
[texture
->getPixelFormat()]);
345 nlassert (srcFormat
== RemapTextureFormatTypeNeL2D3D
[texture
->getPixelFormat()]);
346 nlassert (destFormat
== getD3DDestTextureFormat (*texture
));
350 nlassert (!((srcFormatCompressed
) && (destFormat
== D3DFMT_A8R8G8B8
)));
352 // Get new texture format
353 width
= texture
->getWidth();
354 height
= texture
->getHeight();
355 levels
= texture
->getMipMapCount();
356 if (levels
== 1 && !srcFormatCompressed
)
358 // if not built-in mipmap levels, compute how many of them are needed
359 levels
= texture
->computeNeededMipMapCount();
361 if (cube
&& !_CubbedMipMapSupported
)
365 renderTarget
= texture
->getRenderTarget();
367 // Texture degradation
368 if (_ForceTextureResizePower
>0 && texture
->allowDegradation() && (!srcFormatCompressed
|| levels
>1) && textureDegradation
)
371 width
= max(1U, (UINT
)(texture
->getWidth(0) >> _ForceTextureResizePower
));
372 height
= max(1U, (UINT
)(texture
->getHeight(0) >> _ForceTextureResizePower
));
373 levels
= (levels
>_ForceTextureResizePower
)?levels
-_ForceTextureResizePower
:1;
375 // Modify source texture
376 if (srcFormatCompressed
)
378 if (cube
&& !_CubbedMipMapSupported
)
380 // just uses one the level of interest and not the others
381 firstMipMap
= (texture
->getMipMapCount()>_ForceTextureResizePower
)?_ForceTextureResizePower
: texture
->getMipMapCount() - 1;
386 // Skip a compressed mipmap
387 firstMipMap
= texture
->getMipMapCount()-levels
;
392 // Resample the non-compressed texture
393 texture
->resample(width
, height
);
398 if (!srcFormatCompressed
)
400 if (texture
->mipMapOn() && levels
> 1)
402 texture
->buildMipMaps();
403 levels
= texture
->getMipMapCount();
410 // If compressed, width and height must be 4x4 aligned
411 if (srcFormatCompressed
)
414 width
= (width
& ~3)+4;
416 height
= (height
& ~3)+4;
419 // Got an old texture ?
420 if (d3dtext
->Texture
&&
422 (d3dtext
->Width
!= width
) ||
423 (d3dtext
->Height
!= height
) ||
424 (d3dtext
->Levels
!= levels
) ||
425 (d3dtext
->FirstMipMap
!= firstMipMap
) ||
426 (d3dtext
->DestFormat
!= destFormat
) ||
427 (d3dtext
->IsCube
!= cube
) ||
428 (d3dtext
->RenderTarget
!= renderTarget
)
432 // Delete this texture
433 if (d3dtext
->Texture
)
435 d3dtext
->Texture
->Release();
436 d3dtext
->Texture
= NULL
;
437 d3dtext
->Texture2d
= NULL
;
438 d3dtext
->TextureCube
= NULL
;
441 // profiling: count TextureMemory usage.
442 _AllocatedTextureMemory
-= d3dtext
->TextureMemory
;
443 d3dtext
->TextureMemory
= 0;
446 // Texture must be created ?
447 if (d3dtext
->Texture
== NULL
)
449 // profiling: count TextureMemory usage.
450 uint32 textureMemory
= computeTextureMemoryUsage (width
, height
, levels
, destFormat
, cube
);
452 // Create the texture
457 createSuccess
= _DeviceInterface
->CreateCubeTexture(width
, levels
, renderTarget
?D3DUSAGE_RENDERTARGET
:0, destFormat
, renderTarget
?D3DPOOL_DEFAULT
:D3DPOOL_MANAGED
, &(d3dtext
->TextureCube
), NULL
) == D3D_OK
;
458 d3dtext
->Texture
= d3dtext
->TextureCube
;
463 // textures with mipmaps doesn't support not power of two sizes
464 // only DXTC formats are beginning with a 'D'
465 if (supportNonPowerOfTwoTextures() && (!isPowerOf2(width) || !isPowerOf2(height)) && levels == 1)
467 // support for non-power of two sizes for textures need these lines
468 _DeviceInterface->SetRenderState(D3DRS_WRAP0, 0);
469 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
470 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
471 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);
475 HRESULT hr
= _DeviceInterface
->CreateTexture (width
, height
, levels
, renderTarget
?D3DUSAGE_RENDERTARGET
:0, destFormat
, renderTarget
?D3DPOOL_DEFAULT
:D3DPOOL_MANAGED
, &(d3dtext
->Texture2d
), NULL
);
479 nlwarning("CreateTexture failed with code 0x%x for texture %s in %ux%u", hr
, tex
.getShareName().c_str(), width
, height
);
482 createSuccess
= hr
== D3D_OK
;
483 d3dtext
->Texture
= d3dtext
->Texture2d
;
490 d3dtext
->TextureMemory
= textureMemory
;
491 _AllocatedTextureMemory
+= d3dtext
->TextureMemory
;
494 d3dtext
->Width
= width
;
495 d3dtext
->Height
= height
;
496 d3dtext
->Levels
= uint8(levels
);
497 d3dtext
->FirstMipMap
= uint8(firstMipMap
);
498 d3dtext
->DestFormat
= destFormat
;
499 d3dtext
->SrcCompressed
= srcFormatCompressed
;
500 d3dtext
->IsCube
= cube
;
506 // ***************************************************************************
507 inline void CDriverD3D::setupTextureWrapMode(ITexture
& tex
)
509 CTextureDrvInfosD3D
*d3dtext
= CDriverD3D::getTextureD3D(tex
);
511 d3dtext
->WrapS
= RemapTextureAdressTypeNeL2D3D
[tex
.getWrapS()];
512 d3dtext
->WrapT
= RemapTextureAdressTypeNeL2D3D
[tex
.getWrapT()];
513 d3dtext
->MagFilter
= RemapMagTextureFilterTypeNeL2D3D
[tex
.getMagFilter()];
514 d3dtext
->MinFilter
= RemapMinTextureFilterTypeNeL2D3D
[tex
.getMinFilter()];
515 d3dtext
->MipFilter
= RemapMipTextureFilterTypeNeL2D3D
[tex
.getMinFilter()];
517 // only enable for min filter, because it's never supported for mag filter
518 if (_AnisotropicFilter
> 1 && tex
.getMinFilter() > ITexture::NearestMipMapLinear
)
520 if (tex
.isTextureCube())
522 if (_AnisotropicMinCubeSupported
) d3dtext
->MinFilter
= D3DTEXF_ANISOTROPIC
;
526 if (_AnisotropicMinSupported
) d3dtext
->MinFilter
= D3DTEXF_ANISOTROPIC
;
532 bool CDriverD3D::setupTextureEx (ITexture
& tex
, bool bUpload
, bool &bAllUploaded
, bool bMustRecreateSharedTexture
)
534 H_AUTO_D3D(CDriverD3D_setupTextureEx
)
535 bAllUploaded
= false;
538 // 0. Create/Retrieve the driver texture.
539 //=======================================
540 bool mustCreate
= false;
541 if ( !tex
.TextureDrvShare
)
543 // insert into driver list. (so it is deleted when driver is deleted).
544 ItTexDrvSharePtrList it
= _TexDrvShares
.insert(_TexDrvShares
.end(), (NL3D::CTextureDrvShare
*)NULL
);
545 // create and set iterator, for future deletion.
546 *it
= tex
.TextureDrvShare
= new CTextureDrvShare(this, it
, &tex
);
548 // Must (re)-create the texture.
552 // Does the texture has been touched ?
553 if ( (!tex
.touched()) && (!mustCreate
) )
555 setupTextureWrapMode(tex
); // update basics parameters if needed
556 return true; // Do not do anything
560 // 1. If modified, may (re)load texture part or all of the texture.
561 //=================================================================
564 bool mustLoadAll
= false;
565 bool mustLoadPart
= false;
569 if(tex
.supportSharing())
571 // Try to get the shared texture.
573 // Create the shared Name.
575 getTextureShareName (tex
, name
);
577 // insert or get the texture.
579 CSynchronized
<TTexDrvInfoPtrMap
>::CAccessor
access(&_SyncTexDrvInfos
);
580 TTexDrvInfoPtrMap
&rTexDrvInfos
= access
.value();
582 ItTexDrvInfoPtrMap itTex
;
583 itTex
= rTexDrvInfos
.find(name
);
585 // texture not found?
586 if( itTex
==rTexDrvInfos
.end() )
588 // insert into driver map. (so it is deleted when driver is deleted).
589 itTex
= (rTexDrvInfos
.insert(make_pair(name
, (ITextureDrvInfos
*)NULL
))).first
;
590 // create and set iterator, for future deletion.
591 itTex
->second
= tex
.TextureDrvShare
->DrvTexture
= new CTextureDrvInfosD3D(this, itTex
, this, tex
.getRenderTarget());
593 // need to load ALL this texture.
598 tex
.TextureDrvShare
->DrvTexture
= itTex
->second
;
600 if(bMustRecreateSharedTexture
)
601 // reload this shared texture (user request)
604 // Do not need to reload this texture, even if the format/mipmap has changed, since we found this
605 // couple in the map.
609 // Do not test if part of texture may need to be computed, because Rect invalidation is incompatible
610 // with texture sharing.
614 // If texture not already created.
615 if(!tex
.TextureDrvShare
->DrvTexture
)
617 // Must create it. Create auto a D3D id (in constructor).
618 // Do not insert into the map. This un-shared texture will be deleted at deletion of the texture.
619 // Inform ITextureDrvInfos by passing NULL _Driver.
620 tex
.TextureDrvShare
->DrvTexture
= new CTextureDrvInfosD3D(NULL
, ItTexDrvInfoPtrMap(), this, tex
.getRenderTarget());
622 // need to load ALL this texture.
625 else if(tex
.isAllInvalidated())
627 else if(tex
.touched())
631 if(tex
.isTextureCube() && (!_TextureCubeSupported
))
638 if(mustLoadAll
|| mustLoadPart
)
640 CTextureDrvInfosD3D
* d3dtext
;
641 d3dtext
= getTextureD3D(tex
);
643 // a. Load All the texture case.
644 //==============================
648 D3DFORMAT destFormat
;
650 if (generateD3DTexture (tex
, true, destFormat
, srcFormat
, cube
))
652 if((tex
.getSize()>0) || cube
)
654 // Can support multi part upload ?
655 if ((destFormat
!= srcFormat
) && d3dtext
->SrcCompressed
)
658 bUpload
= true; // Force all upload
661 // Must upload the texture ?
662 if (bUpload
&& !tex
.getRenderTarget())
667 uint blockCount
= d3dtext
->Height
>>(d3dtext
->SrcCompressed
?2:0);
668 uint lineWidth
= d3dtext
->Width
;
669 const uint srcPixelSize
= getPixelFormatSize (srcFormat
);
670 for(i
=d3dtext
->FirstMipMap
;i
<uint(d3dtext
->FirstMipMap
)+uint(d3dtext
->Levels
);i
++, destLevel
++)
673 const uint blockSize
= ((lineWidth
*srcPixelSize
)>>3)<<(d3dtext
->SrcCompressed
?2:0);
675 // Several faces for cube texture
676 const uint numFaces
= d3dtext
->IsCube
?6:1;
678 for (face
=0; face
<numFaces
; face
++)
680 // Get the cube texture
681 ITexture
*texture
= d3dtext
->IsCube
?(static_cast<CTextureCube
*>(&tex
)->getTexture((CTextureCube::TFace
)face
)):&tex
;
685 if (destFormat
== srcFormat
)
687 // Lock the surface level
690 if (!d3dtext
->IsCube
)
691 locked
= d3dtext
->Texture2d
->LockRect (destLevel
, &rect
, NULL
, 0) == D3D_OK
;
693 locked
= d3dtext
->TextureCube
->LockRect (RemapCubeFaceTypeNeL2D3D
[face
], destLevel
, &rect
, NULL
, 0) == D3D_OK
;
699 for (block
=0; block
<blockCount
; block
++)
702 const uint8
*src
= &(texture
->getPixels(i
)[block
*blockSize
]);
703 uint8
*dest
= ((uint8
*)rect
.pBits
)+block
*rect
.Pitch
;
704 if (destFormat
== D3DFMT_A8R8G8B8
)
705 copyRGBA2BGRA ((uint32
*)dest
, (const uint32
*)src
, blockSize
>>2);
707 memcpy (dest
, src
, blockSize
);
711 if (!d3dtext
->IsCube
)
712 d3dtext
->Texture2d
->UnlockRect (destLevel
);
714 d3dtext
->TextureCube
->UnlockRect (RemapCubeFaceTypeNeL2D3D
[face
], destLevel
);
719 // Convert the surface using a D3DX method
720 IDirect3DSurface9
*pDestSurface
;
721 bool surfaceOk
= false;
722 if (!d3dtext
->IsCube
)
723 surfaceOk
= d3dtext
->Texture2d
->GetSurfaceLevel(destLevel
, &pDestSurface
) == D3D_OK
;
725 surfaceOk
= d3dtext
->TextureCube
->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D
[face
], destLevel
, &pDestSurface
) == D3D_OK
;
727 // Surface has been retrieved ?
730 if (srcFormat
== D3DFMT_A8R8G8B8
)
732 const uint8
*src
= &(texture
->getPixels(i
)[0]);
734 // Fill the temp buffer with BGRA info
735 _TempBuffer
.resize (blockCount
*blockSize
);
736 uint8
*dest
= &(_TempBuffer
[0]);
738 for (line
=0; line
<blockCount
; line
++)
740 copyRGBA2BGRA ((uint32
*)dest
, (uint32
*)(src
+line
*blockSize
), lineWidth
);
744 // Upload the texture part
747 srcRect
.bottom
= blockCount
;
749 srcRect
.right
= lineWidth
;
750 D3DXLoadSurfaceFromMemory (pDestSurface
, NULL
, NULL
, &(_TempBuffer
[0]), srcFormat
,
751 blockSize
, NULL
, &srcRect
, D3DX_FILTER_NONE
, 0);
757 rect
.bottom
= blockCount
;
759 rect
.right
= lineWidth
;
760 D3DXLoadSurfaceFromMemory (pDestSurface
, NULL
, NULL
, &(texture
->getPixels(i
)[0]), srcFormat
,
761 blockSize
, NULL
, &rect
, D3DX_FILTER_NONE
, 0);
763 pDestSurface
->Release();
770 lineWidth
= max((UINT
)(lineWidth
>>1), (UINT
)(d3dtext
->SrcCompressed
?4:1));
771 blockCount
= max((UINT
)(blockCount
>>1), 1U);
775 if (!d3dtext
->IsCube
)
776 d3dtext
->Texture
->PreLoad();
778 d3dtext
->Texture
->PreLoad();
784 // b. Load part of the texture case.
785 //==================================
786 // Replace parts of a compressed image. Maybe don't work with the actual system of invalidateRect()...
787 else if (mustLoadPart
&& !d3dtext
->SrcCompressed
)
789 D3DFORMAT destFormat
;
792 if (CDriverD3D::generateD3DTexture (tex
, false, destFormat
, srcFormat
, cube
))
794 // No degradation in load part
795 nlassert (d3dtext
->FirstMipMap
== 0);
797 if(tex
.getSize()>0 && bUpload
&& !tex
.getRenderTarget())
799 // For all rect, update the texture/mipmap.
800 //===============================================
801 list
<NLMISC::CRect
>::iterator itRect
;
802 for(itRect
=tex
._ListInvalidRect
.begin(); itRect
!=tex
._ListInvalidRect
.end(); itRect
++)
804 CRect
&rect
= *itRect
;
807 sint x1
= rect
.X
+rect
.Width
;
808 sint y1
= rect
.Y
+rect
.Height
;
813 for(i
=d3dtext
->FirstMipMap
;i
<uint(d3dtext
->FirstMipMap
)+uint(d3dtext
->Levels
);i
++, destLevel
++)
818 rectDest
.Width
= x1
-x0
;
819 rectDest
.Height
= y1
-y0
;
820 uploadTextureInternal (tex
, rectDest
, uint8(destLevel
), uint8(i
), destFormat
, srcFormat
);
834 // Release, if wanted.
835 if(tex
.getReleasable())
839 setupTextureWrapMode(tex
);
840 // The texture is correctly setuped.
845 // ***************************************************************************
847 bool CDriverD3D::uploadTexture (ITexture
& tex
, CRect
& rect
, uint8 nNumMipMap
)
849 H_AUTO_D3D(CDriverD3D_uploadTexture
)
850 if (tex
.TextureDrvShare
== NULL
)
851 return false; // Texture not created
852 if (tex
.TextureDrvShare
->DrvTexture
== NULL
)
853 return false; // Texture not created
854 if (tex
.isTextureCube())
857 CTextureDrvInfosD3D
* d3dtext
= getTextureD3D(tex
);
858 // if the texture src is in DXTC MipMaped, and mipmapskip is enabled, skip first levels the user want to upload
859 if(d3dtext
->FirstMipMap
> nNumMipMap
)
862 nlassert (rect
.X
< (sint
)d3dtext
->Width
);
863 nlassert (rect
.Y
< (sint
)d3dtext
->Height
);
864 nlassert (rect
.X
+ rect
.Width
<= (sint
)d3dtext
->Width
);
865 nlassert (rect
.Y
+ rect
.Height
<= (sint
)d3dtext
->Height
);
866 nlassert(nNumMipMap
<(uint8
)tex
.getMipMapCount());
871 sint x1
= rect
.X
+rect
.Width
;
872 sint y1
= rect
.Y
+rect
.Height
;
873 sint w
= tex
.getWidth (nNumMipMap
);
874 sint h
= tex
.getHeight (nNumMipMap
);
881 rect
.Width
= x1
- x0
;
882 rect
.Height
= y1
- y0
;
885 nlassert (!tex
.isTextureCube());
886 D3DFORMAT srcFormat
= RemapTextureFormatTypeNeL2D3D
[tex
.getPixelFormat()];
887 D3DFORMAT destFormat
= getD3DDestTextureFormat (tex
);
889 return uploadTextureInternal (tex
, rect
, nNumMipMap
-d3dtext
->FirstMipMap
, nNumMipMap
, destFormat
, srcFormat
);
892 // ***************************************************************************
894 bool CDriverD3D::uploadTextureInternal (ITexture
& tex
, CRect
& rect
, uint8 destMipmap
, uint8 srcMipmap
,
895 D3DFORMAT destFormat
, D3DFORMAT srcFormat
)
897 H_AUTO_D3D(CDriverD3D_uploadTextureInternal
)
899 if (rect
.Width
== 0 || rect
.Height
== 0)
901 nlwarning("Rectangle width or height cannot be 0");
906 CTextureDrvInfosD3D
* d3dtext
= getTextureD3D(tex
);
909 const uint pixelSize
= CBitmap::bitPerPixels
[tex
.getPixelFormat()];
911 // The line width of that mipmap level
912 uint lineWidth
= max(d3dtext
->Width
>>destMipmap
, uint(d3dtext
->SrcCompressed
?4:1));
916 sint x1
= rect
.X
+rect
.Width
;
917 sint y1
= rect
.Y
+rect
.Height
;
921 if (d3dtext
->SrcCompressed
)
923 nlassert ((x0
& 0x3) == 0);
924 nlassert ((y0
& 0x3) == 0);
925 nlassert (((x1
& 0x3) == 0) || (x1
<4));
926 nlassert (((y1
& 0x3) == 0) || (y1
<4));
927 x1Copy
= std::max(4, x1
);
928 y1Copy
= std::max(4, y1
);
932 const uint lineSize
= ((lineWidth
*pixelSize
)>>3)<<(d3dtext
->SrcCompressed
?2:0);
933 const uint offsetX
= (x0
*pixelSize
)>>3;
935 // Block of line (for compressed textures)
937 uint lineEnd
= y1Copy
;
939 // Pitch for compressed texture
940 if (d3dtext
->SrcCompressed
)
947 if (destFormat
== srcFormat
)
949 // Lock the surface level
959 const sint dataToCopy
= (((x1Copy
-x0
)*pixelSize
)>>3)<<(d3dtext
->SrcCompressed
?2:0);
960 if (d3dtext
->Texture2d
->LockRect (destMipmap
, &rect
, ®ion
, 0) == D3D_OK
)
963 for (line
=lineStart
; line
<lineEnd
; line
++)
966 const uint8
*src
= &(tex
.getPixels(srcMipmap
)[line
*lineSize
+offsetX
]);
967 uint8
*dest
= ((uint8
*)rect
.pBits
)+(line
-lineStart
)*rect
.Pitch
;
968 if (destFormat
== D3DFMT_A8R8G8B8
)
969 copyRGBA2BGRA ((uint32
*)dest
, (const uint32
*)src
, dataToCopy
>>2);
971 memcpy (dest
, src
, dataToCopy
);
973 d3dtext
->Texture2d
->UnlockRect (destMipmap
);
982 // Convert the surface using a D3DX method
983 IDirect3DSurface9
*pDestSurface
;
985 // Surface has been retrieved ?
986 if (d3dtext
->Texture2d
->GetSurfaceLevel(destMipmap
, &pDestSurface
) == D3D_OK
)
990 destRect
.bottom
= y1
;
994 if (srcFormat
== D3DFMT_A8R8G8B8
)
996 const uint8
*src
= &(tex
.getPixels(srcMipmap
)[0]);
998 // Fill the temp buffer with BGRA info
999 const sint lineWidth
= x1
-x0
;
1000 _TempBuffer
.resize (((y1
-y0
)*lineWidth
)<<2);
1001 uint8
*dest
= &(_TempBuffer
[0]);
1003 for (line
=y0
; line
<(uint
)y1
; line
++)
1005 copyRGBA2BGRA ((uint32
*)dest
, (uint32
*)(src
+line
*lineSize
+(x0
<<2)), lineWidth
);
1006 dest
+= lineWidth
<<2;
1009 // Upload the texture part
1012 srcRect
.bottom
= y1
-y0
;
1014 srcRect
.right
= lineWidth
;
1015 if (D3DXLoadSurfaceFromMemory (pDestSurface
, NULL
, &destRect
, &(_TempBuffer
[0]), srcFormat
,
1016 lineWidth
<<2, NULL
, &srcRect
, D3DX_FILTER_NONE
, 0) != D3D_OK
)
1023 srcRect
.bottom
= y1
;
1026 const uint8
*src
= &(tex
.getPixels(srcMipmap
)[0]);
1027 if (D3DXLoadSurfaceFromMemory (pDestSurface
, NULL
, &destRect
, src
, srcFormat
,
1028 lineSize
, NULL
, &srcRect
, D3DX_FILTER_NONE
, 0) != D3D_OK
)
1031 pDestSurface
->Release();
1038 // ***************************************************************************
1040 bool CDriverD3D::isTextureExist(const ITexture
&tex
)
1042 H_AUTO_D3D(CDriverD3D_isTextureExist
)
1045 // Create the shared Name.
1047 getTextureShareName (tex
, name
);
1050 CSynchronized
<TTexDrvInfoPtrMap
>::CAccessor
access(&_SyncTexDrvInfos
);
1051 TTexDrvInfoPtrMap
&rTexDrvInfos
= access
.value();
1052 result
= (rTexDrvInfos
.find(name
) != rTexDrvInfos
.end());
1057 // ***************************************************************************
1059 void CDriverD3D::swapTextureHandle(ITexture
&tex0
, ITexture
&tex1
)
1061 H_AUTO_D3D(CDriverD3D_swapTextureHandle
)
1062 // ensure creation of both texture
1066 // avoid any problem, disable all textures
1067 for(uint stage
=0; stage
<inlGetNumTextStages() ; stage
++)
1069 setTexture (stage
, (LPDIRECT3DBASETEXTURE9
)NULL
);
1073 CTextureDrvInfosD3D
*t0
= getTextureD3D(tex0
);
1074 CTextureDrvInfosD3D
*t1
= getTextureD3D(tex1
);
1076 /* Swap contents. Can't swap directly the pointers cause would have to change all CTextureDrvShare which point on
1077 Can't do swap(*t0, *t1), because must keep the correct _DriverIterator
1079 swap(t0
->Texture
, t1
->Texture
);
1080 swap(t0
->Texture2d
, t1
->Texture2d
);
1081 swap(t0
->TextureCube
, t1
->TextureCube
);
1082 swap(t0
->DestFormat
, t1
->DestFormat
);
1083 swap(t0
->Width
, t1
->Width
);
1084 swap(t0
->Height
, t1
->Height
);
1085 swap(t0
->SrcCompressed
, t1
->SrcCompressed
);
1086 swap(t0
->IsCube
, t1
->IsCube
);
1087 swap(t0
->RenderTarget
, t1
->RenderTarget
);
1088 swap(t0
->Levels
, t1
->Levels
);
1089 swap(t0
->FirstMipMap
, t1
->FirstMipMap
);
1090 swap(t0
->TextureMemory
, t1
->TextureMemory
);
1091 swap(t0
->WrapS
, t1
->WrapS
);
1092 swap(t0
->WrapT
, t1
->WrapT
);
1093 swap(t0
->MagFilter
, t1
->MagFilter
);
1094 swap(t0
->MinFilter
, t1
->MinFilter
);
1095 swap(t0
->MipFilter
, t1
->MipFilter
);
1098 // ***************************************************************************
1100 uintptr_t CDriverD3D::getTextureHandle(const ITexture
&tex
)
1102 H_AUTO_D3D(CDriverD3D_getTextureHandle
)
1103 // If DrvShare not setuped
1104 if(!tex
.TextureDrvShare
)
1107 CTextureDrvInfosD3D
*d3dtext
= getTextureD3D(const_cast<ITexture
&>(tex
));
1109 // If DrvInfo not setuped
1113 return (uintptr_t)(d3dtext
->Texture
);
1116 // ***************************************************************************
1118 bool CDriverD3D::setRenderTarget (ITexture
*tex
, uint32
/* x */, uint32
/* y */, uint32
/* width */, uint32
/* height */, uint32 mipmapLevel
, uint32 cubeFace
)
1120 H_AUTO_D3D(CDriverD3D_setRenderTarget
)
1121 // Check the texture is a render target
1123 nlassertex (tex
->getRenderTarget(), ("The texture must be a render target. Call ITexture::setRenderTarget(true)."));
1127 _InvertCullMode
= false;
1130 setRenderTarget (_BackBuffer
, NULL
, 0, 0);
1131 _BackBuffer
->Release();
1137 _InvertCullMode
= true;
1140 updateRenderVariables ();
1141 _DeviceInterface
->GetRenderTarget (0, &_BackBuffer
);
1145 if (tex
->TextureDrvShare
)
1148 CTextureDrvInfosD3D
*d3dtext
= getTextureD3D(*tex
);
1150 // Renderable ? Erase and rebuild
1151 if (!d3dtext
->RenderTarget
)
1152 // Touch the texture
1156 // Setup the new texture
1158 if (!setupTextureEx (*tex
, false, nTmp
, false))
1162 CTextureDrvInfosD3D
*d3dtext
= getTextureD3D(*tex
);
1164 // Setup texture for texture rendering
1165 IDirect3DSurface9
*pDestSurface
;
1166 bool surfaceOk
= false;
1167 if (!d3dtext
->IsCube
)
1168 surfaceOk
= d3dtext
->Texture2d
->GetSurfaceLevel(mipmapLevel
, &pDestSurface
) == D3D_OK
;
1170 surfaceOk
= d3dtext
->TextureCube
->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D
[cubeFace
], mipmapLevel
, &pDestSurface
) == D3D_OK
;
1173 setRenderTarget (pDestSurface
, tex
, (uint8
)mipmapLevel
, (uint8
)cubeFace
);
1174 pDestSurface
->Release();
1183 if (_CullMode
== CCW
)
1185 setRenderState (D3DRS_CULLMODE
, _InvertCullMode
?D3DCULL_CCW
:D3DCULL_CW
);
1189 setRenderState (D3DRS_CULLMODE
, _InvertCullMode
?D3DCULL_CW
:D3DCULL_CCW
);
1196 ITexture
*CDriverD3D::getRenderTarget() const
1198 return _RenderTarget
.Texture
;
1201 // ***************************************************************************
1203 bool CDriverD3D::copyTargetToTexture (ITexture
* /* tex */, uint32
/* offsetx */, uint32
/* offsety */, uint32
/* x */, uint32
/* y */, uint32
/* width */,
1204 uint32
/* height */, uint32
/* mipmapLevel */)
1206 H_AUTO_D3D(CDriverD3D_copyTargetToTexture
)
1210 // ***************************************************************************
1212 bool CDriverD3D::getRenderTargetSize (uint32
&width
, uint32
&height
)
1214 H_AUTO_D3D(CDriverD3D_getRenderTargetSize
)
1215 // Target is the frame buffer ?
1216 if (_RenderTarget
.Texture
)
1218 CTextureDrvInfosD3D
* d3dtext
= getTextureD3D(*_RenderTarget
.Texture
);
1219 width
= max ((uint32
)1, (uint32
)(d3dtext
->Width
>> (_RenderTarget
.Level
)));
1220 height
= max ((uint32
)1, (uint32
)(d3dtext
->Height
>> (_RenderTarget
.Level
)));
1225 getWindowSize (width
, height
);
1230 // ***************************************************************************