D3D9: Fixed blit and read back.

This commit is contained in:
Branimir Karadžić 2015-10-22 21:30:55 -07:00
parent f7130318c0
commit 0c0542b2e6
2 changed files with 258 additions and 48 deletions

View file

@ -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();

View file

@ -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;