Explorar el Código

D3D9: Fixed blit and read back.

Branimir Karadžić hace 10 años
padre
commit
0c0542b2e6
Se han modificado 2 ficheros con 258 adiciones y 48 borrados
  1. 248 48
      src/renderer_d3d9.cpp
  2. 10 0
      src/renderer_d3d9.h

+ 248 - 48
src/renderer_d3d9.cpp

@@ -534,8 +534,8 @@ namespace bgfx { namespace d3d9
 				| BGFX_CAPS_FRAGMENT_DEPTH
 				| BGFX_CAPS_SWAP_CHAIN
 				| ( (UINT16_MAX < m_caps.MaxVertexIndex) ? BGFX_CAPS_INDEX32 : 0)
-//				| ( (m_caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) ? BGFX_CAPS_TEXTURE_BLIT : 0)
-//				| BGFX_CAPS_TEXTURE_READ_BACK
+				| ( (m_caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) ? BGFX_CAPS_TEXTURE_BLIT : 0)
+				| BGFX_CAPS_TEXTURE_READ_BACK
 				);
 			g_caps.maxTextureSize = uint16_t(bx::uint32_min(m_caps.MaxTextureWidth, m_caps.MaxTextureHeight) );
 //			g_caps.maxVertexIndex = m_caps.MaxVertexIndex;
@@ -581,7 +581,9 @@ namespace bgfx { namespace d3d9
 
 				for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)
 				{
-					uint8_t support = SUCCEEDED(m_d3d9->CheckDeviceFormat(m_adapter
+					uint8_t support = 0;
+					
+					support |= SUCCEEDED(m_d3d9->CheckDeviceFormat(m_adapter
 						, m_deviceType
 						, adapterFormat
 						, 0
@@ -2324,25 +2326,31 @@ namespace bgfx { namespace d3d9
 
 	void TextureD3D9::createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips)
 	{
-		m_type    = Texture2D;
+		m_type = Texture2D;
 		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
 
 		DWORD usage = 0;
-		D3DPOOL pool = s_renderD3D9->m_pool;
+		D3DPOOL pool = D3DPOOL_DEFAULT;
 
 		const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK);
 		const bool blit         = 0 != (m_flags&BGFX_TEXTURE_BLIT_DST);
+		const bool readBack     = 0 != (m_flags&BGFX_TEXTURE_READ_BACK);
 		if (isDepth(fmt) )
 		{
 			usage = D3DUSAGE_DEPTHSTENCIL;
-			pool  = D3DPOOL_DEFAULT;
+		}
+		else if (readBack)
+		{
+			usage = 0;
+			pool  = D3DPOOL_SYSTEMMEM;
 		}
 		else if (renderTarget || blit)
 		{
 			usage = D3DUSAGE_RENDERTARGET;
-			pool  = D3DPOOL_DEFAULT;
 		}
 
+		IDirect3DDevice9* device = s_renderD3D9->m_device;
+
 		if (renderTarget)
 		{
 			uint32_t msaaQuality = ( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT);
@@ -2357,7 +2365,7 @@ namespace bgfx { namespace d3d9
 
 				if (isDepth(fmt) )
 				{
-					DX_CHECK(s_renderD3D9->m_device->CreateDepthStencilSurface(
+					DX_CHECK(device->CreateDepthStencilSurface(
 						  m_width
 						, m_height
 						, s_textureFormat[m_textureFormat].m_fmt
@@ -2370,7 +2378,7 @@ namespace bgfx { namespace d3d9
 				}
 				else
 				{
-					DX_CHECK(s_renderD3D9->m_device->CreateRenderTarget(
+					DX_CHECK(device->CreateRenderTarget(
 						  m_width
 						, m_height
 						, s_textureFormat[m_textureFormat].m_fmt
@@ -2391,7 +2399,7 @@ namespace bgfx { namespace d3d9
 			}
 		}
 
-		DX_CHECK(s_renderD3D9->m_device->CreateTexture(_width
+		DX_CHECK(device->CreateTexture(_width
 			, _height
 			, _numMips
 			, usage
@@ -2401,6 +2409,57 @@ namespace bgfx { namespace d3d9
 			, NULL
 			) );
 
+		if (!renderTarget
+		&&  !readBack)
+		{
+			if (NULL == m_staging)
+			{
+				DX_CHECK(device->CreateTexture(_width
+					, _height
+					, _numMips
+					, 0
+					, s_textureFormat[fmt].m_fmt
+					, D3DPOOL_SYSTEMMEM
+					, &m_staging2d
+					, NULL
+					) );
+			}
+			else
+			{
+				const ImageBlockInfo& blockInfo = getBlockInfo(fmt);
+				const uint32_t blockWidth  = blockInfo.blockWidth;
+				const uint32_t blockHeight = blockInfo.blockHeight;
+
+				for (uint8_t lod = 0, num = _numMips; lod < num; ++lod)
+				{
+					if ( (m_width >>lod) < blockWidth
+					||   (m_height>>lod) < blockHeight)
+					{
+						break;
+					}
+
+					uint32_t mipWidth  = bx::uint32_max(blockWidth,  ( ( (m_width >>lod) + blockWidth  - 1) / blockWidth )*blockWidth);
+					uint32_t mipHeight = bx::uint32_max(blockHeight, ( ( (m_height>>lod) + blockHeight - 1) / blockHeight)*blockHeight);
+
+					IDirect3DSurface9* srcSurface;
+					DX_CHECK(m_staging2d->GetSurfaceLevel(lod, &srcSurface) );
+					IDirect3DSurface9* dstSurface = getSurface(0, lod);
+
+					RECT  srcRect  = { LONG(0), LONG(0), LONG(mipWidth), LONG(mipHeight) };
+					POINT dstPoint = { LONG(0), LONG(0) };
+
+					DX_CHECK(device->UpdateSurface(srcSurface
+						, &srcRect
+						, dstSurface
+						, &dstPoint
+						) );
+
+					srcSurface->Release();
+					dstSurface->Release();
+				}
+			}
+		}
+
 		BGFX_FATAL(NULL != m_texture2d, Fatal::UnableToCreateTexture, "Failed to create texture (size: %dx%d, mips: %d, fmt: %d)."
 			, _width
 			, _height
@@ -2414,17 +2473,37 @@ namespace bgfx { namespace d3d9
 		m_type = Texture3D;
 		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
 
-		DX_CHECK(s_renderD3D9->m_device->CreateVolumeTexture(_width
+		IDirect3DDevice9* device = s_renderD3D9->m_device;
+		DX_CHECK(device->CreateVolumeTexture(_width
 			, _height
 			, _depth
 			, _numMips
 			, 0
 			, s_textureFormat[fmt].m_fmt
-			, s_renderD3D9->m_pool
+			, D3DPOOL_DEFAULT
 			, &m_texture3d
 			, NULL
 			) );
 
+		if (NULL == m_staging)
+		{
+			DX_CHECK(device->CreateVolumeTexture(_width
+				, _height
+				, _depth
+				, _numMips
+				, 0
+				, s_textureFormat[fmt].m_fmt
+				, D3DPOOL_SYSTEMMEM
+				, &m_staging3d
+				, NULL
+				) );
+		}
+		else
+		{
+			DX_CHECK(m_texture3d->AddDirtyBox(NULL) );
+			DX_CHECK(device->UpdateTexture(m_staging3d, m_texture3d) );
+		}
+
 		BGFX_FATAL(NULL != m_texture3d, Fatal::UnableToCreateTexture, "Failed to create volume texture (size: %dx%dx%d, mips: %d, fmt: %s)."
 			, _width
 			, _height
@@ -2440,30 +2519,80 @@ namespace bgfx { namespace d3d9
 		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
 
 		DWORD usage = 0;
-		D3DPOOL pool = s_renderD3D9->m_pool;
 
 		const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK);
 		const bool blit         = 0 != (m_flags&BGFX_TEXTURE_BLIT_DST);
 		if (isDepth(fmt) )
 		{
 			usage = D3DUSAGE_DEPTHSTENCIL;
-			pool  = D3DPOOL_DEFAULT;
 		}
 		else if (renderTarget || blit)
 		{
 			usage = D3DUSAGE_RENDERTARGET;
-			pool  = D3DPOOL_DEFAULT;
 		}
 
-		DX_CHECK(s_renderD3D9->m_device->CreateCubeTexture(_edge
+		IDirect3DDevice9* device = s_renderD3D9->m_device;
+		DX_CHECK(device->CreateCubeTexture(_edge
 			, _numMips
 			, usage
 			, s_textureFormat[fmt].m_fmt
-			, pool
+			, D3DPOOL_DEFAULT
 			, &m_textureCube
 			, NULL
 			) );
 
+		if (!renderTarget)
+		{
+			if (NULL == m_staging)
+			{
+				DX_CHECK(device->CreateCubeTexture(_edge
+					, _numMips
+					, 0
+					, s_textureFormat[fmt].m_fmt
+					, D3DPOOL_SYSTEMMEM
+					, &m_stagingCube
+					, NULL
+					) );
+			}
+			else
+			{
+				const ImageBlockInfo& blockInfo = getBlockInfo(fmt);
+				const uint32_t blockWidth  = blockInfo.blockWidth;
+				const uint32_t blockHeight = blockInfo.blockHeight;
+
+				for (uint8_t side = 0, numSides = 6; side < numSides; ++side)
+				{
+					for (uint8_t lod = 0, num = _numMips; lod < num; ++lod)
+					{
+						if ( (m_width >>lod) < blockWidth
+						||   (m_height>>lod) < blockHeight)
+						{
+							break;
+						}
+
+						uint32_t mipWidth  = bx::uint32_max(blockWidth,  ( ( (m_width >>lod) + blockWidth  - 1) / blockWidth )*blockWidth);
+						uint32_t mipHeight = bx::uint32_max(blockHeight, ( ( (m_height>>lod) + blockHeight - 1) / blockHeight)*blockHeight);
+
+						IDirect3DSurface9* srcSurface;
+						DX_CHECK(m_stagingCube->GetCubeMapSurface(D3DCUBEMAP_FACES(side), lod, &srcSurface) );
+						IDirect3DSurface9* dstSurface = getSurface(side, lod);
+
+						RECT  srcRect  = { LONG(0), LONG(0), LONG(mipWidth), LONG(mipHeight) };
+						POINT dstPoint = { LONG(0), LONG(0) };
+
+						DX_CHECK(device->UpdateSurface(srcSurface
+							, &srcRect
+							, dstSurface
+							, &dstPoint
+							) );
+
+						srcSurface->Release();
+						dstSurface->Release();
+					}
+				}
+			}
+		}
+
 		BGFX_FATAL(NULL != m_textureCube, Fatal::UnableToCreateTexture, "Failed to create cube texture (edge: %d, mips: %d, fmt: %s)."
 			, _edge
 			, _numMips
@@ -2486,11 +2615,11 @@ namespace bgfx { namespace d3d9
 					rect.top    = _rect->m_y;
 					rect.right  = rect.left + _rect->m_width;
 					rect.bottom = rect.top  + _rect->m_height;
-					DX_CHECK(m_texture2d->LockRect(_lod, &lockedRect, &rect, 0) );
+					DX_CHECK(m_staging2d->LockRect(_lod, &lockedRect, &rect, 0) );
 				}
 				else
 				{
-					DX_CHECK(m_texture2d->LockRect(_lod, &lockedRect, NULL, 0) );
+					DX_CHECK(m_staging2d->LockRect(_lod, &lockedRect, NULL, 0) );
 				}
 
 				_pitch = lockedRect.Pitch;
@@ -2501,8 +2630,8 @@ namespace bgfx { namespace d3d9
 		case Texture3D:
 			{
 				D3DLOCKED_BOX box;
-				DX_CHECK(m_texture3d->LockBox(_lod, &box, NULL, 0) );
-				_pitch = box.RowPitch;
+				DX_CHECK(m_staging3d->LockBox(_lod, &box, NULL, 0) );
+				_pitch      = box.RowPitch;
 				_slicePitch = box.SlicePitch;
 				return (uint8_t*)box.pBits;
 			}
@@ -2514,15 +2643,15 @@ namespace bgfx { namespace d3d9
 				if (NULL != _rect)
 				{
 					RECT rect;
-					rect.left = _rect->m_x;
-					rect.top = _rect->m_y;
-					rect.right = rect.left + _rect->m_width;
+					rect.left   = _rect->m_x;
+					rect.top    = _rect->m_y;
+					rect.right  = rect.left + _rect->m_width;
 					rect.bottom = rect.top + _rect->m_height;
-					DX_CHECK(m_textureCube->LockRect(D3DCUBEMAP_FACES(_side), _lod, &lockedRect, &rect, 0) );
+					DX_CHECK(m_stagingCube->LockRect(D3DCUBEMAP_FACES(_side), _lod, &lockedRect, &rect, 0) );
 				}
 				else
 				{
-					DX_CHECK(m_textureCube->LockRect(D3DCUBEMAP_FACES(_side), _lod, &lockedRect, NULL, 0) );
+					DX_CHECK(m_stagingCube->LockRect(D3DCUBEMAP_FACES(_side), _lod, &lockedRect, NULL, 0) );
 				}
 
 				_pitch = lockedRect.Pitch;
@@ -2532,7 +2661,7 @@ namespace bgfx { namespace d3d9
 		}
 
 		BX_CHECK(false, "You should not be here.");
-		_pitch = 0;
+		_pitch      = 0;
 		_slicePitch = 0;
 		return NULL;
 	}
@@ -2543,19 +2672,61 @@ namespace bgfx { namespace d3d9
 		{
 		case Texture2D:
 			{
-				DX_CHECK(m_texture2d->UnlockRect(_lod) );
+				DX_CHECK(m_staging2d->UnlockRect(_lod) );
+
+				IDirect3DSurface9* srcSurface;
+				DX_CHECK(m_staging2d->GetSurfaceLevel(0, &srcSurface) );
+				IDirect3DSurface9* dstSurface = getSurface(0, _lod);
+
+				const ImageBlockInfo& blockInfo = getBlockInfo(TextureFormat::Enum(m_textureFormat) );
+				uint32_t mipWidth  = bx::uint32_max(blockInfo.blockWidth,  m_width >>_lod);
+				uint32_t mipHeight = bx::uint32_max(blockInfo.blockHeight, m_height>>_lod);
+
+				RECT  srcRect  = { LONG(0), LONG(0), LONG(mipWidth), LONG(mipHeight) };
+				POINT dstPoint = { LONG(0), LONG(0) };
+
+				s_renderD3D9->m_device->UpdateSurface(srcSurface
+					, &srcRect
+					, dstSurface
+					, &dstPoint
+					);
+
+				srcSurface->Release();
+				dstSurface->Release();
 			}
 			return;
 
 		case Texture3D:
 			{
-				DX_CHECK(m_texture3d->UnlockBox(_lod) );
+				DX_CHECK(m_staging3d->UnlockBox(_lod) );
+				DX_CHECK(m_texture3d->AddDirtyBox(NULL) );
+				DX_CHECK(s_renderD3D9->m_device->UpdateTexture(m_staging3d, m_texture3d) );
 			}
 			return;
 
 		case TextureCube:
 			{
-				DX_CHECK(m_textureCube->UnlockRect(D3DCUBEMAP_FACES(_side), _lod) );
+				DX_CHECK(m_stagingCube->UnlockRect(D3DCUBEMAP_FACES(_side), _lod) );
+
+				IDirect3DSurface9* srcSurface;
+				DX_CHECK(m_stagingCube->GetCubeMapSurface(D3DCUBEMAP_FACES(_side), _lod, &srcSurface) );
+				IDirect3DSurface9* dstSurface = getSurface(_side, _lod);
+
+				const ImageBlockInfo& blockInfo = getBlockInfo(TextureFormat::Enum(m_textureFormat) );
+				uint32_t mipWidth  = bx::uint32_max(blockInfo.blockWidth,  m_width >>_lod);
+				uint32_t mipHeight = bx::uint32_max(blockInfo.blockHeight, m_height>>_lod);
+
+				RECT  srcRect  = { LONG(0), LONG(0), LONG(mipWidth), LONG(mipHeight) };
+				POINT dstPoint = { LONG(0), LONG(0) };
+
+				DX_CHECK(s_renderD3D9->m_device->UpdateSurface(srcSurface
+					, &srcRect
+					, dstSurface
+					, &dstPoint
+					) );
+
+				srcSurface->Release();
+				dstSurface->Release();
 			}
 			return;
 		}
@@ -2570,9 +2741,9 @@ namespace bgfx { namespace d3d9
 		case Texture2D:
 			{
 				RECT rect;
-				rect.left = _rect.m_x;
-				rect.top = _rect.m_y;
-				rect.right = rect.left + _rect.m_width;
+				rect.left   = _rect.m_x;
+				rect.top    = _rect.m_y;
+				rect.right  = rect.left + _rect.m_width;
 				rect.bottom = rect.top + _rect.m_height;
 				DX_CHECK(m_texture2d->AddDirtyRect(&rect) );
 			}
@@ -2581,12 +2752,12 @@ namespace bgfx { namespace d3d9
 		case Texture3D:
 			{
 				D3DBOX box;
-				box.Left = _rect.m_x;
-				box.Top = _rect.m_y;
-				box.Right = box.Left + _rect.m_width;
+				box.Left   = _rect.m_x;
+				box.Top    = _rect.m_y;
+				box.Right  = box.Left + _rect.m_width;
 				box.Bottom = box.Top + _rect.m_height;
-				box.Front = _z;
-				box.Back = box.Front + _depth;
+				box.Front  = _z;
+				box.Back   = box.Front + _depth;
 				DX_CHECK(m_texture3d->AddDirtyBox(&box) );
 			}
 			return;
@@ -2594,9 +2765,9 @@ namespace bgfx { namespace d3d9
 		case TextureCube:
 			{
 				RECT rect;
-				rect.left = _rect.m_x;
-				rect.top = _rect.m_y;
-				rect.right = rect.left + _rect.m_width;
+				rect.left   = _rect.m_x;
+				rect.top    = _rect.m_y;
+				rect.right  = rect.left + _rect.m_width;
 				rect.bottom = rect.top + _rect.m_height;
 				DX_CHECK(m_textureCube->AddDirtyRect(D3DCUBEMAP_FACES(_side), &rect) );
 			}
@@ -2865,8 +3036,7 @@ namespace bgfx { namespace d3d9
 	void TextureD3D9::preReset()
 	{
 		TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
-		if (TextureFormat::Unknown != fmt
-		&& (isDepth(fmt) || !!(m_flags&(BGFX_TEXTURE_RT_MASK|BGFX_TEXTURE_BLIT_DST) ) ) )
+		if (TextureFormat::Unknown != fmt)
 		{
 			DX_RELEASE(m_ptr, 0);
 			DX_RELEASE(m_surface, 0);
@@ -2876,10 +3046,23 @@ namespace bgfx { namespace d3d9
 	void TextureD3D9::postReset()
 	{
 		TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
-		if (TextureFormat::Unknown != fmt
-		&& (isDepth(fmt) || !!(m_flags&(BGFX_TEXTURE_RT_MASK|BGFX_TEXTURE_BLIT_DST)) ) )
+		if (TextureFormat::Unknown != fmt)
 		{
-			createTexture(m_width, m_height, m_numMips);
+			switch (m_type)
+			{
+			default:
+			case Texture2D:
+				createTexture(m_width, m_height, m_numMips);
+				break;
+
+			case Texture3D:
+				createVolumeTexture(m_width, m_height, m_depth, m_numMips);
+				break;
+
+			case TextureCube:
+				createCubeTexture(m_width, m_numMips);
+				break;
+			}
 		}
 	}
 
@@ -3393,14 +3576,31 @@ namespace bgfx { namespace d3d9
 						IDirect3DSurface9* srcSurface = src.getSurface(uint8_t(blit.m_srcZ), blit.m_srcMip);
 						IDirect3DSurface9* dstSurface = dst.getSurface(uint8_t(blit.m_dstZ), blit.m_dstMip);
 
+						// UpdateSurface (pool src: SYSTEMMEM, dst: DEFAULT)
+						// s/d T   RTT RT
+						// T   y   y   y
+						// RTT -   -   -
+						// RT  -   -   -
+						//
+						// StretchRect (pool src and dst must be DEFAULT)
+						// s/d T   RTT RT
+						// T   -   y   y
+						// RTT -   y   y
+						// RT  -   y   y
+						//
+						// GetRenderTargetData (dst must be SYSTEMMEM)
+
 						HRESULT hr = m_device->StretchRect(srcSurface
 							, &srcRect
 							, dstSurface
 							, &dstRect
 							, D3DTEXF_NONE
 							);
-						BX_WARN(SUCCEEDED(hr), "StretchRect failed %x.", hr);
-						BX_UNUSED(hr);
+						if (FAILED(hr) )
+						{
+							hr = m_device->GetRenderTargetData(srcSurface, dstSurface);
+							BX_WARN(SUCCEEDED(hr), "StretchRect and GetRenderTargetData failed %x.", hr);
+						}
 
 						srcSurface->Release();
 						dstSurface->Release();

+ 10 - 0
src/renderer_d3d9.h

@@ -310,6 +310,7 @@ namespace bgfx { namespace d3d9
 		TextureD3D9()
 			: m_ptr(NULL)
 			, m_surface(NULL)
+			, m_staging(NULL)
 			, m_textureFormat(TextureFormat::Unknown)
 		{
 		}
@@ -329,6 +330,7 @@ namespace bgfx { namespace d3d9
 		{
 			DX_RELEASE(m_ptr, 0);
 			DX_RELEASE(m_surface, 0);
+			DX_RELEASE(m_staging, 0);
 			m_textureFormat = TextureFormat::Unknown;
 		}
 
@@ -350,6 +352,14 @@ namespace bgfx { namespace d3d9
 		};
 
 		IDirect3DSurface9* m_surface;
+
+		union
+		{
+			IDirect3DBaseTexture9*   m_staging;
+			IDirect3DTexture9*       m_staging2d;
+			IDirect3DVolumeTexture9* m_staging3d;
+			IDirect3DCubeTexture9*   m_stagingCube;
+		};
 		uint32_t m_flags;
 		uint32_t m_width;
 		uint32_t m_height;