D3D1x/WebGPU: Survive device loss in the readback paths. (#4001)

This commit is contained in:
Branimir Karadžić
2026-09-28 19:56:23 -07:00
committed by GitHub
parent 7e3060ccb9
commit ce3bee65f2
3 changed files with 259 additions and 115 deletions
+148 -52
View File
@@ -693,11 +693,13 @@ namespace bgfx { namespace d3d12
#endif // BX_PLATFORM_WINDOWS
}
static bool reportDeviceLost(HRESULT _hr);
ID3D12Resource* createCommittedResource(ID3D12Device* _device, HeapProperty::Enum _heapProperty, const D3D12_RESOURCE_DESC* _resourceDesc, const D3D12_CLEAR_VALUE* _clearValue, bool _memSet = false, D3D12_HEAP_FLAGS _heapFlags = D3D12_HEAP_FLAG_NONE)
{
const HeapProperty& heapProperty = s_heapProperties[_heapProperty];
ID3D12Resource* resource = NULL;
DX_CHECK(_device->CreateCommittedResource(
const HRESULT hr = _device->CreateCommittedResource(
&heapProperty.m_properties
, _heapFlags
, _resourceDesc
@@ -705,7 +707,14 @@ namespace bgfx { namespace d3d12
, _clearValue
, IID_ID3D12Resource
, (void**)&resource
) );
);
if (reportDeviceLost(hr) )
{
return NULL;
}
BX_ASSERT(SUCCEEDED(hr), "CreateCommittedResource FAILED 0x%08x.", uint32_t(hr) );
BX_WARN(NULL != resource, "CreateCommittedResource failed (size: %d). Out of memory?"
, _resourceDesc->Width
);
@@ -2322,7 +2331,7 @@ namespace bgfx { namespace d3d12
}
}
DX_RELEASE(dred, 0);
DX_RELEASE_I(dred);
}
bool handleDeviceLost(HRESULT _hr)
@@ -2532,6 +2541,14 @@ namespace bgfx { namespace d3d12
ID3D12Resource* readback = createCommittedResource(m_device, HeapProperty::ReadBack, total);
if (NULL == readback)
{
BX_TRACE("readTexture: failed to create readback buffer, device removed reason 0x%08x."
, uint32_t(m_device->GetDeviceRemovedReason() )
);
return;
}
const uint32_t srcWidth = bx::max(1u, texture.m_width >>_mip);
const uint32_t srcHeight = bx::max(1u, texture.m_height>>_mip);
@@ -2570,13 +2587,23 @@ namespace bgfx { namespace d3d12
uint32_t pitch = bx::min(srcPitch, dstPitch);
uint8_t* src;
readback->Map(0, NULL, (void**)&src);
uint8_t* src = NULL;
const HRESULT hr = readback->Map(0, NULL, (void**)&src);
bx::memCopy(dst, dstPitch, src, srcPitch, pitch, numBlockRows);
if (FAILED(hr) )
{
BX_TRACE("readTexture: Map failed 0x%08x, device removed reason 0x%08x."
, uint32_t(hr)
, uint32_t(m_device->GetDeviceRemovedReason() )
);
}
else
{
bx::memCopy(dst, dstPitch, src, srcPitch, pitch, numBlockRows);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
}
DX_RELEASE(readback, 0);
}
@@ -2613,6 +2640,14 @@ namespace bgfx { namespace d3d12
ID3D12Resource* readback = createCommittedResource(m_device, HeapProperty::ReadBack, stencilOffset + total[1]);
if (NULL == readback)
{
BX_TRACE("readTexturePlanar: failed to create readback buffer, device removed reason 0x%08x."
, uint32_t(m_device->GetDeviceRemovedReason() )
);
return;
}
const uint32_t srcWidth = bx::max(1u, _texture.m_width >>_mip);
const uint32_t srcHeight = bx::max(1u, _texture.m_height>>_mip);
@@ -2639,47 +2674,57 @@ namespace bgfx { namespace d3d12
finish();
m_commandList = m_cmd.alloc();
uint8_t* src;
readback->Map(0, NULL, (void**)&src);
uint8_t* src = NULL;
const HRESULT hr = readback->Map(0, NULL, (void**)&src);
const uint32_t texelSize = bimg::getBlockInfo(bimg::TextureFormat::Enum(_texture.m_textureFormat) ).blockSize;
const uint32_t dstPitch = srcWidth * texelSize;
for (uint32_t yy = 0; yy < srcHeight; ++yy)
if (FAILED(hr) )
{
const uint8_t* depthRow = src + layout[0].Offset + yy*layout[0].Footprint.RowPitch;
const uint8_t* stencilRow = src + layout[1].Offset + yy*layout[1].Footprint.RowPitch;
uint8_t* dstRow = (uint8_t*)_data + yy*dstPitch;
BX_TRACE("readTexturePlanar: Map failed 0x%08x, device removed reason 0x%08x."
, uint32_t(hr)
, uint32_t(m_device->GetDeviceRemovedReason() )
);
}
else
{
const uint32_t texelSize = bimg::getBlockInfo(bimg::TextureFormat::Enum(_texture.m_textureFormat) ).blockSize;
const uint32_t dstPitch = srcWidth * texelSize;
for (uint32_t xx = 0; xx < srcWidth; ++xx)
for (uint32_t yy = 0; yy < srcHeight; ++yy)
{
uint8_t* texel = dstRow + xx*texelSize;
const uint8_t* depthRow = src + layout[0].Offset + yy*layout[0].Footprint.RowPitch;
const uint8_t* stencilRow = src + layout[1].Offset + yy*layout[1].Footprint.RowPitch;
uint8_t* dstRow = (uint8_t*)_data + yy*dstPitch;
if (1 == texelSize)
for (uint32_t xx = 0; xx < srcWidth; ++xx)
{
texel[0] = stencilRow[xx];
}
else
{
bx::memCopy(texel, depthRow + xx*4, 4);
uint8_t* texel = dstRow + xx*texelSize;
if (4 == texelSize)
if (1 == texelSize)
{
texel[3] = stencilRow[xx];
texel[0] = stencilRow[xx];
}
else
{
texel[4] = stencilRow[xx];
texel[5] = 0;
texel[6] = 0;
texel[7] = 0;
bx::memCopy(texel, depthRow + xx*4, 4);
if (4 == texelSize)
{
texel[3] = stencilRow[xx];
}
else
{
texel[4] = stencilRow[xx];
texel[5] = 0;
texel[6] = 0;
texel[7] = 0;
}
}
}
}
}
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
}
DX_RELEASE(readback, 0);
}
@@ -2700,6 +2745,14 @@ namespace bgfx { namespace d3d12
ID3D12Resource* readback = createCommittedResource(m_device, HeapProperty::ReadBack, _size);
if (NULL == readback)
{
BX_TRACE("readBuffer: failed to create readback buffer, device removed reason 0x%08x."
, uint32_t(m_device->GetDeviceRemovedReason() )
);
return;
}
const D3D12_RESOURCE_STATES state = buffer.setState(m_commandList, D3D12_RESOURCE_STATE_COPY_SOURCE);
m_commandList->CopyBufferRegion(readback, 0, buffer.m_ptr, _offset, _size);
buffer.setState(m_commandList, state);
@@ -2708,10 +2761,22 @@ namespace bgfx { namespace d3d12
m_commandList = m_cmd.alloc();
void* src = NULL;
readback->Map(0, NULL, (void**)&src);
bx::memCopy(_data, src, _size);
D3D12_RANGE readbackWriteRange = { 0, 0 };
readback->Unmap(0, &readbackWriteRange);
const HRESULT hr = readback->Map(0, NULL, (void**)&src);
if (FAILED(hr) )
{
BX_TRACE("readBuffer: Map failed 0x%08x, device removed reason 0x%08x."
, uint32_t(hr)
, uint32_t(m_device->GetDeviceRemovedReason() )
);
}
else
{
bx::memCopy(_data, src, _size);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
}
DX_RELEASE(readback, 0);
}
@@ -2897,6 +2962,20 @@ namespace bgfx { namespace d3d12
ID3D12Resource* readback = createCommittedResource(m_device, HeapProperty::ReadBack, total);
if (NULL == readback)
{
BX_TRACE("requestScreenShot: failed to create readback buffer, device removed reason 0x%08x."
, uint32_t(m_device->GetDeviceRemovedReason() )
);
if (NULL != swapFb)
{
DX_RELEASE(backBuffer, swapFb->getSwapChainDesc().bufferCount);
}
return;
}
D3D12_BOX box;
box.left = 0;
box.top = 0;
@@ -2917,21 +2996,31 @@ namespace bgfx { namespace d3d12
finish();
m_commandList = m_cmd.alloc();
void* data;
readback->Map(0, NULL, (void**)&data);
void* data = NULL;
const HRESULT hr = readback->Map(0, NULL, (void**)&data);
g_callback->screenShot(_filePath
, width
, height
, layout.Footprint.RowPitch
, colorFormat
, data
, (uint32_t)total
, false
);
if (FAILED(hr) )
{
BX_TRACE("requestScreenShot: Map failed 0x%08x, device removed reason 0x%08x."
, uint32_t(hr)
, uint32_t(m_device->GetDeviceRemovedReason() )
);
}
else
{
g_callback->screenShot(_filePath
, width
, height
, layout.Footprint.RowPitch
, colorFormat
, data
, (uint32_t)total
, false
);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
D3D12_RANGE writeRange = { 0, 0 };
readback->Unmap(0, &writeRange);
}
DX_RELEASE(readback, 0);
@@ -4549,6 +4638,13 @@ namespace bgfx { namespace d3d12
static RendererContextD3D12* s_renderD3D12;
static bool reportDeviceLost(HRESULT _hr)
{
return NULL != s_renderD3D12
&& s_renderD3D12->handleDeviceLost(_hr)
;
}
ID3D12PipelineState* videoGetPipelineState(RendererContextD3D12* _renderer, ProgramHandle _handle)
{
return _renderer->getPipelineState(_handle);
@@ -10033,7 +10129,7 @@ namespace bgfx { namespace d3d12
;
const bool depthClamp = depthControl.m_depthClamp;
ID3D12PipelineState* pso = getPipelineState(
state