From ba37f327b05d94fc5a23ec57d227b16f45915319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 29 Sep 2026 13:16:59 -0600 Subject: [PATCH] D3D11: Check Map() results Map fails after device removal, leaving pData garbage. Skip the upload or draw instead of writing through it. Co-Authored-By: Claude Opus 5.5 (1M context) --- GPU/D3D11/D3D11Util.h | 15 +++++++++++++-- GPU/D3D11/DrawEngineD3D11.cpp | 12 ++++++++++++ GPU/D3D11/ShaderManagerD3D11.cpp | 15 +++++++++------ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index cae9399142..4a749e2b66 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -46,7 +46,11 @@ public: nextMapDiscard_ = true; } + // Returns null if the buffer can't be mapped (after device removal, for example). Skip the draw then. uint8_t *BeginPush(ID3D11DeviceContext *context, UINT *offset, size_t size, int align = 16) { + if (!buffer_) { + return nullptr; + } D3D11_MAPPED_SUBRESOURCE map; pos_ = (pos_ + align - 1) & ~(align - 1); if (pos_ + size > size_) { @@ -55,7 +59,10 @@ public: pos_ = 0; nextMapDiscard_ = true; } - context->Map(buffer_.Get(), 0, nextMapDiscard_ ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); + if (FAILED(context->Map(buffer_.Get(), 0, nextMapDiscard_ ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map))) { + return nullptr; + } + mapped_ = true; nextMapDiscard_ = false; *offset = (UINT)pos_; uint8_t *retval = (uint8_t *)map.pData + pos_; @@ -63,7 +70,10 @@ public: return retval; } void EndPush(ID3D11DeviceContext *context) { - context->Unmap(buffer_.Get(), 0); + if (mapped_) { + context->Unmap(buffer_.Get(), 0); + mapped_ = false; + } } private: @@ -71,6 +81,7 @@ private: size_t pos_ = 0; size_t size_; bool nextMapDiscard_ = false; + bool mapped_ = false; }; std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags, std::string *errorMessage = nullptr); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 576a803513..a75fd7ab9e 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -358,6 +358,9 @@ void DrawEngineD3D11::Flush() { UINT vOffset; int vSize = numDecodedVerts_ * dec_->GetDecVtxFmt().stride; uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize); + if (!vptr) { + goto bail; + } memcpy(vptr, decoded_, vSize); pushVerts_->EndPush(context_); ID3D11Buffer *buf = pushVerts_->Buf(); @@ -366,6 +369,9 @@ void DrawEngineD3D11::Flush() { UINT iOffset; int iSize = 2 * vertexCount; uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); + if (!iptr) { + goto bail; + } memcpy(iptr, decIndex_, iSize); pushInds_->EndPush(context_); context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); @@ -477,6 +483,9 @@ void DrawEngineD3D11::Flush() { UINT vOffset = 0; int vSize = result.drawVertexCount * stride; uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize); + if (!vptr) { + goto bail; + } memcpy(vptr, result.drawBuffer, vSize); pushVerts_->EndPush(context_); ID3D11Buffer *buf = pushVerts_->Buf(); @@ -484,6 +493,9 @@ void DrawEngineD3D11::Flush() { UINT iOffset; int iSize = sizeof(uint16_t) * result.drawIndexCount; uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); + if (!iptr) { + goto bail; + } memcpy(iptr, inds, iSize); pushInds_->EndPush(context_); context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 46584a3ca4..d7e3b94300 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -147,15 +147,18 @@ uint64_t ShaderManagerD3D11::UpdateUniforms(bool useBufferedRendering, bool pixe D3D11_MAPPED_SUBRESOURCE map; if (dirty & DIRTY_BASE_UNIFORMS) { BaseUpdateUniforms(&ub_base, dirty, useBufferedRendering, pixelMapped); - context_->Map(push_base.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &ub_base, sizeof(ub_base)); - context_->Unmap(push_base.Get(), 0); + // Map fails after device removal, and map.pData is garbage then. + if (SUCCEEDED(context_->Map(push_base.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map))) { + memcpy(map.pData, &ub_base, sizeof(ub_base)); + context_->Unmap(push_base.Get(), 0); + } } if (dirty & DIRTY_LIGHT_UNIFORMS) { LightUpdateUniforms(&ub_lights, dirty); - context_->Map(push_lights.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &ub_lights, sizeof(ub_lights)); - context_->Unmap(push_lights.Get(), 0); + if (SUCCEEDED(context_->Map(push_lights.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map))) { + memcpy(map.pData, &ub_lights, sizeof(ub_lights)); + context_->Unmap(push_lights.Get(), 0); + } } } gstate_c.CleanUniforms();