Fix more D3D11 lifecycle problems. Removed some ComPtr that got in the way

This commit is contained in:
Henrik Rydgård
2025-08-01 18:20:44 +02:00
parent a5aac9c386
commit 77e894c64d
12 changed files with 116 additions and 82 deletions
-1
View File
@@ -2533,7 +2533,6 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) {
void TextureCacheCommon::Clear(bool delete_them) {
textureShaderCache_->Clear();
ForgetLastTexture();
for (TexCache::iterator iter = cache_.begin(); iter != cache_.end(); ++iter) {
ReleaseTexture(iter->second.get(), delete_them);
}
-25
View File
@@ -107,28 +107,3 @@ HRESULT CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t
return device->CreateGeometryShader(byteCode.data(), byteCode.size(), nullptr, ppGeometryShader);
}
void StockObjectsD3D11::Create(ID3D11Device *device) {
D3D11_SAMPLER_DESC sampler_desc{};
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
for (int i = 0; i < 4; i++)
sampler_desc.BorderColor[i] = 1.0f;
sampler_desc.MinLOD = -FLT_MAX;
sampler_desc.MaxLOD = FLT_MAX;
sampler_desc.MipLODBias = 0.0f;
sampler_desc.MaxAnisotropy = 1;
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
ASSERT_SUCCESS(device->CreateSamplerState(&sampler_desc, &samplerPoint2DClamp));
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
ASSERT_SUCCESS(device->CreateSamplerState(&sampler_desc, &samplerLinear2DClamp));
}
void StockObjectsD3D11::Destroy() {
samplerPoint2DClamp.Reset();
samplerLinear2DClamp.Reset();
}
StockObjectsD3D11 stockD3D11;
-11
View File
@@ -80,17 +80,6 @@ HRESULT CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t co
HRESULT CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11ComputeShader **);
HRESULT CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11GeometryShader **);
class StockObjectsD3D11 {
public:
void Create(ID3D11Device *device);
void Destroy();
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerPoint2DClamp;
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerLinear2DClamp;
};
#define ASSERT_SUCCESS(x) \
if (!SUCCEEDED((x))) \
Crash();
extern StockObjectsD3D11 stockD3D11;
+32 -5
View File
@@ -103,6 +103,33 @@ void DrawEngineD3D11::DestroyDeviceObjects() {
delete pushInds_;
pushVerts_ = nullptr;
pushInds_ = nullptr;
// Clear state caches.
blendCache_.Iterate([&](const uint64_t &key, ID3D11BlendState *state) {
state->Release();
});
blendCache_.Clear();
blendCache1_.Iterate([&](const uint64_t &key, ID3D11BlendState1 *state) {
state->Release();
});
blendCache1_.Clear();
depthStencilCache_.Iterate([&](const uint64_t &key, ID3D11DepthStencilState *state) {
state->Release();
});
depthStencilCache_.Clear();
rasterCache_.Iterate([&](const uint32_t &key, ID3D11RasterizerState *state) {
state->Release();
});
rasterCache_.Clear();
inputLayoutMap_.Iterate([&](const InputLayoutKey &key, ID3D11InputLayout *state) {
state->Release();
});
inputLayoutMap_.Clear();
blendState_ = nullptr;
blendState1_ = nullptr;
rasterState_ = nullptr;
depthStencilState_ = nullptr;
}
void DrawEngineD3D11::DeviceLost() {
@@ -166,9 +193,9 @@ HRESULT DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const De
// TODO: Instead of one for each vshader, we can reduce it to one for each type of shader
// that reads TEXCOORD or not, etc. Not sure if worth it.
const InputLayoutKey key{ vshader, decFmt.id };
ComPtr<ID3D11InputLayout> inputLayout;
ID3D11InputLayout *inputLayout;
if (inputLayoutMap_.Get(key, &inputLayout)) {
*ppInputLayout = inputLayout.Detach();
*ppInputLayout = inputLayout;
return S_OK;
} else {
D3D11_INPUT_ELEMENT_DESC VertexElements[8];
@@ -224,7 +251,7 @@ HRESULT DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const De
// Add it to map
inputLayoutMap_.Insert(key, inputLayout);
*ppInputLayout = inputLayout.Detach();
*ppInputLayout = inputLayout;
return hr;
}
}
@@ -441,12 +468,12 @@ void DrawEngineD3D11::Flush() {
// We really do need a vertex layout for each vertex shader (or at least check its ID bits for what inputs it uses)!
// Some vertex shaders ignore one of the inputs, and then the layout created from it will lack it, which will be a problem for others.
InputLayoutKey key{ vshader, 0xFFFFFFFF }; // Let's use 0xFFFFFFFF to signify TransformedVertex
ComPtr<ID3D11InputLayout> layout;
ID3D11InputLayout *layout;
if (!inputLayoutMap_.Get(key, &layout)) {
ASSERT_SUCCESS(device_->CreateInputLayout(TransformedVertexElements, ARRAY_SIZE(TransformedVertexElements), vshader->bytecode().data(), vshader->bytecode().size(), &layout));
inputLayoutMap_.Insert(key, layout);
}
context_->IASetInputLayout(layout.Get());
context_->IASetInputLayout(layout);
context_->IASetPrimitiveTopology(d3d11prim[prim]);
UINT stride = sizeof(TransformedVertex);
+14 -13
View File
@@ -110,7 +110,7 @@ private:
}
};
DenseHashMap<InputLayoutKey, Microsoft::WRL::ComPtr<ID3D11InputLayout>> inputLayoutMap_;
DenseHashMap<InputLayoutKey, ID3D11InputLayout *> inputLayoutMap_;
// Other
ShaderManagerD3D11 *shaderManager_ = nullptr;
@@ -118,27 +118,28 @@ private:
FramebufferManagerD3D11 *framebufferManager_ = nullptr;
// Pushbuffers
PushBufferD3D11 *pushVerts_;
PushBufferD3D11 *pushInds_;
PushBufferD3D11 *pushVerts_ = nullptr;
PushBufferD3D11 *pushInds_ = nullptr;
// D3D11 state object caches.
DenseHashMap<uint64_t, Microsoft::WRL::ComPtr<ID3D11BlendState>> blendCache_;
DenseHashMap<uint64_t, Microsoft::WRL::ComPtr<ID3D11BlendState1>> blendCache1_;
DenseHashMap<uint64_t, Microsoft::WRL::ComPtr<ID3D11DepthStencilState>> depthStencilCache_;
DenseHashMap<uint32_t, Microsoft::WRL::ComPtr<ID3D11RasterizerState>> rasterCache_;
// D3D11 state object caches. Previously had smart pointers but they were harder to deal with.
DenseHashMap<uint64_t, ID3D11BlendState *> blendCache_;
DenseHashMap<uint64_t, ID3D11BlendState1 *> blendCache1_;
DenseHashMap<uint64_t, ID3D11DepthStencilState *> depthStencilCache_;
DenseHashMap<uint32_t, ID3D11RasterizerState *> rasterCache_;
// Keep the depth state between ApplyDrawState and ApplyDrawStateLate
Microsoft::WRL::ComPtr<ID3D11RasterizerState> rasterState_;
Microsoft::WRL::ComPtr<ID3D11BlendState> blendState_;
Microsoft::WRL::ComPtr<ID3D11BlendState1> blendState1_;
Microsoft::WRL::ComPtr<ID3D11DepthStencilState> depthStencilState_;
// These do not hold ownership.
ID3D11BlendState *blendState_ = nullptr;
ID3D11BlendState1 *blendState1_ = nullptr;
ID3D11DepthStencilState *depthStencilState_ = nullptr;
ID3D11RasterizerState *rasterState_ = nullptr;
// State keys
D3D11StateKeys keys_{};
D3D11DynamicState dynState_{};
// Hardware tessellation
TessellationDataTransferD3D11 *tessDataTransferD3D11;
TessellationDataTransferD3D11 *tessDataTransferD3D11 = nullptr;
int lastRenderStepId_ = -1;
};
-5
View File
@@ -75,12 +75,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
textureCache_->NotifyConfigChanged();
}
void GPU_D3D11::FinishInitOnMainThread() {
stockD3D11.Create(device_);
}
GPU_D3D11::~GPU_D3D11() {
stockD3D11.Destroy();
}
u32 GPU_D3D11::CheckGPUFeatures() const {
+1 -3
View File
@@ -34,12 +34,10 @@ public:
GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
~GPU_D3D11();
void FinishInitOnMainThread() override;
u32 CheckGPUFeatures() const override;
void GetStats(char *buffer, size_t bufsize) override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceLost() override; // Destroy all device objects.
void DeviceRestore(Draw::DrawContext *draw) override;
protected:
+27 -4
View File
@@ -88,7 +88,18 @@ ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *de
static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big");
static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big");
D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE };
InitDeviceObjects();
}
ShaderManagerD3D11::~ShaderManagerD3D11() {
ClearShaders();
delete[] codeBuffer_;
DestroyDeviceObjects();
}
void ShaderManagerD3D11::InitDeviceObjects() {
D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE};
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_base));
desc.ByteWidth = sizeof(ub_lights);
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_lights));
@@ -96,9 +107,21 @@ ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *de
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_bones));
}
ShaderManagerD3D11::~ShaderManagerD3D11() {
ClearShaders();
delete[] codeBuffer_;
void ShaderManagerD3D11::DestroyDeviceObjects() {
push_base.Reset();
push_lights.Reset();
push_bones.Reset();
Clear();
}
void ShaderManagerD3D11::DeviceLost() {
DestroyDeviceObjects();
draw_ = nullptr;
}
void ShaderManagerD3D11::DeviceRestore(Draw::DrawContext *draw) {
draw_ = draw;
InitDeviceObjects();
}
void ShaderManagerD3D11::Clear() {
+5 -2
View File
@@ -90,8 +90,11 @@ public:
void ClearShaders() override;
void DirtyLastShader() override;
void DeviceLost() override { draw_ = nullptr; }
void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
void InitDeviceObjects();
void DestroyDeviceObjects();
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
+8 -8
View File
@@ -356,7 +356,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
// There might have been interactions between depth and blend above.
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
if (!device1_) {
ComPtr<ID3D11BlendState> bs;
ID3D11BlendState *bs;
if (!blendCache_.Get(keys_.blend.value, &bs) || !bs) {
D3D11_BLEND_DESC desc{};
D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0];
@@ -373,7 +373,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
}
blendState_ = bs;
} else {
ComPtr<ID3D11BlendState1> bs1;
ID3D11BlendState1 *bs1;
if (!blendCache1_.Get(keys_.blend.value, &bs1) || !bs1) {
D3D11_BLEND_DESC1 desc1{};
D3D11_RENDER_TARGET_BLEND_DESC1 &rt = desc1.RenderTarget[0];
@@ -395,7 +395,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
}
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
ComPtr<ID3D11RasterizerState> rs;
ID3D11RasterizerState *rs;
if (!rasterCache_.Get(keys_.raster.value, &rs) || !rs) {
D3D11_RASTERIZER_DESC desc{};
desc.CullMode = (D3D11_CULL_MODE)(keys_.raster.cullMode);
@@ -410,7 +410,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
}
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
ComPtr<ID3D11DepthStencilState> ds;
ID3D11DepthStencilState *ds;
if (!depthStencilCache_.Get(keys_.depthStencil.value, &ds) || !ds) {
D3D11_DEPTH_STENCIL_DESC desc{};
desc.DepthEnable = keys_.depthStencil.depthTestEnable;
@@ -446,20 +446,20 @@ void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRe
draw_->SetScissorRect(dynState_.scissor.left, dynState_.scissor.top, dynState_.scissor.right - dynState_.scissor.left, dynState_.scissor.bottom - dynState_.scissor.top);
}
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
context_->RSSetState(rasterState_.Get());
context_->RSSetState(rasterState_);
}
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
// Need to do this AFTER ApplyTexture because the process of depalettization can ruin the blend state.
float blendColor[4];
Uint8x4ToFloat4(blendColor, dynState_.blendColor);
if (device1_) {
context1_->OMSetBlendState(blendState1_.Get(), blendColor, 0xFFFFFFFF);
context1_->OMSetBlendState(blendState1_, blendColor, 0xFFFFFFFF);
} else {
context_->OMSetBlendState(blendState_.Get(), blendColor, 0xFFFFFFFF);
context_->OMSetBlendState(blendState_, blendColor, 0xFFFFFFFF);
}
}
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE) || applyStencilRef) {
context_->OMSetDepthStencilState(depthStencilState_.Get(), applyStencilRef ? stencilRef : dynState_.stencilRef);
context_->OMSetDepthStencilState(depthStencilState_, applyStencilRef ? stencilRef : dynState_.stencilRef);
}
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_BLEND_STATE);
gstate_c.Dirty(dirtyRequiresRecheck_);
+22 -3
View File
@@ -147,10 +147,29 @@ void TextureCacheD3D11::InitDeviceObjects() {
D3D11_BUFFER_DESC desc{ sizeof(DepthPushConstants), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE };
HRESULT hr = device_->CreateBuffer(&desc, nullptr, &depalConstants_);
_dbg_assert_(SUCCEEDED(hr));
D3D11_SAMPLER_DESC sampler_desc{};
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
for (int i = 0; i < 4; i++)
sampler_desc.BorderColor[i] = 1.0f;
sampler_desc.MinLOD = -FLT_MAX;
sampler_desc.MaxLOD = FLT_MAX;
sampler_desc.MipLODBias = 0.0f;
sampler_desc.MaxAnisotropy = 1;
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
ASSERT_SUCCESS(device_->CreateSamplerState(&sampler_desc, &samplerPoint2DClamp_));
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
ASSERT_SUCCESS(device_->CreateSamplerState(&sampler_desc, &samplerLinear2DClamp_));
}
void TextureCacheD3D11::DestroyDeviceObjects() {
depalConstants_.Reset();
samplerPoint2DClamp_.Reset();
samplerLinear2DClamp_.Reset();
lastBoundTexture_ = D3D11_INVALID_TEX;
samplerCache_.Destroy();
}
void TextureCacheD3D11::DeviceLost() {
@@ -238,14 +257,14 @@ void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) {
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
ComPtr<ID3D11SamplerState> state;
samplerCache_.GetOrCreateSampler(device_.Get(), samplerKey, &state);
samplerCache_.GetOrCreateSampler(device_, samplerKey, &state);
context_->PSSetSamplers(0, 1, state.GetAddressOf());
gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF);
}
void TextureCacheD3D11::ApplySamplingParams(const SamplerCacheKey &key) {
ComPtr<ID3D11SamplerState> state;
samplerCache_.GetOrCreateSampler(device_.Get(), key, &state);
samplerCache_.GetOrCreateSampler(device_, key, &state);
context_->PSSetSamplers(0, 1, state.GetAddressOf());
}
@@ -256,7 +275,7 @@ void TextureCacheD3D11::Unbind() {
void TextureCacheD3D11::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
ID3D11ShaderResourceView *clutTexture = (ID3D11ShaderResourceView *)draw_->GetNativeObject(Draw::NativeObject::TEXTURE_VIEW, tex);
context_->PSSetShaderResources(TEX_SLOT_CLUT, 1, &clutTexture);
context_->PSSetSamplers(3, 1, smooth ? stockD3D11.samplerLinear2DClamp.GetAddressOf() : stockD3D11.samplerPoint2DClamp.GetAddressOf());
context_->PSSetSamplers(3, 1, smooth ? samplerLinear2DClamp_.GetAddressOf() : samplerPoint2DClamp_.GetAddressOf());
}
void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
+7 -2
View File
@@ -37,6 +37,9 @@ public:
SamplerCacheD3D11() {}
~SamplerCacheD3D11();
HRESULT GetOrCreateSampler(ID3D11Device *device, const SamplerCacheKey &key, ID3D11SamplerState **);
void Destroy() {
cache_.clear();
}
private:
std::map<SamplerCacheKey, Microsoft::WRL::ComPtr<ID3D11SamplerState>> cache_;
@@ -75,8 +78,8 @@ private:
void BuildTexture(TexCacheEntry *const entry) override;
Microsoft::WRL::ComPtr<ID3D11Device> device_;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context_;
ID3D11Device *device_;
ID3D11DeviceContext *context_;
ID3D11Resource *&DxTex(const TexCacheEntry *entry) const {
return (ID3D11Resource *&)entry->texturePtr;
@@ -89,6 +92,8 @@ private:
ID3D11ShaderResourceView *lastBoundTexture_ = D3D11_INVALID_TEX;
Microsoft::WRL::ComPtr<ID3D11Buffer> depalConstants_;
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerPoint2DClamp_;
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerLinear2DClamp_;
};
DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format);