diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index 73e49b5b2..91cab70e0 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -354,6 +354,9 @@ namespace dxvk { bool NeedsAnyUpload() { return m_needsUpload.any(); } void ClearNeedsUpload() { return m_needsUpload.clearAll(); } + void SetNeedsMipGen(bool value) { m_needsMipGen = value; } + bool NeedsMipGen() const { return m_needsMipGen; } + DWORD ExposedMipLevels() { return m_exposedMipLevels; } private: @@ -395,6 +398,8 @@ namespace dxvk { DWORD m_exposedMipLevels = 0; + bool m_needsMipGen = false; + /** * \brief Mip level * \returns Size of packed mip level in bytes diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 97341f91d..e38cf7c12 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -702,7 +702,7 @@ namespace dxvk { dstTextureInfo->SetDirty(dst->GetSubresource(), true); if (dstTextureInfo->IsAutomaticMip()) - GenerateMips(dstTextureInfo); + MarkTextureMipsDirty(dstTextureInfo); return D3D_OK; } @@ -748,9 +748,14 @@ namespace dxvk { } } - dstTexInfo->MarkAllDirty(); + if (dstTexInfo->IsAutomaticMip()) { + for (uint32_t i = 0; i < dstTexInfo->Desc()->ArraySize; i++) + dstTexInfo->SetDirty(dstTexInfo->CalcSubresource(i, 0), true); - pDestinationTexture->GenerateMipSubLevels(); + MarkTextureMipsDirty(dstTexInfo); + } + else + dstTexInfo->MarkAllDirty(); FlushImplicit(false); @@ -1018,6 +1023,9 @@ namespace dxvk { dstTextureInfo->SetDirty(dst->GetSubresource(), true); + if (dstTextureInfo->IsAutomaticMip()) + MarkTextureMipsDirty(dstTextureInfo); + return D3D_OK; } @@ -1093,6 +1101,9 @@ namespace dxvk { dstTextureInfo->SetDirty(dst->GetSubresource(), true); + if (dstTextureInfo->IsAutomaticMip()) + MarkTextureMipsDirty(dstTextureInfo); + return D3D_OK; } @@ -4133,9 +4144,6 @@ namespace dxvk { pResource->SetDirty(Subresource, true); } - if (pResource->IsAutomaticMip()) - GenerateMips(pResource); - return D3D_OK; } @@ -4184,6 +4192,9 @@ namespace dxvk { copyBuffer); } + if (pResource->IsAutomaticMip()) + MarkTextureMipsDirty(pResource); + return D3D_OK; } @@ -4195,6 +4206,8 @@ namespace dxvk { ] (DxvkContext* ctx) { ctx->generateMipmaps(cImageView); }); + + pResource->SetNeedsMipGen(false); } @@ -4770,6 +4783,7 @@ namespace dxvk { m_activeDSTextures &= ~bit; m_activeTextures &= ~bit; m_activeTexturesToUpload &= ~bit; + m_activeTexturesToGen &= ~bit; auto tex = GetCommonTexture(m_state.textures[index]); if (tex != nullptr) { @@ -4783,6 +4797,9 @@ namespace dxvk { if (unlikely(tex->NeedsAnyUpload())) m_activeTexturesToUpload |= bit; + + if (unlikely(tex->NeedsMipGen())) + m_activeTexturesToGen |= bit; } if (unlikely(combinedUsage & D3DUSAGE_RENDERTARGET)) @@ -4873,6 +4890,35 @@ namespace dxvk { } + void D3D9DeviceEx::GenerateTextureMips(uint32_t mask) { + for (uint32_t tex = mask; tex; tex &= tex - 1) { + // Guaranteed to not be nullptr... + auto texInfo = GetCommonTexture(m_state.textures[bit::tzcnt(tex)]); + + this->GenerateMips(texInfo); + } + + m_activeTexturesToGen &= ~mask; + } + + + void D3D9DeviceEx::MarkTextureMipsDirty(D3D9CommonTexture* pResource) { + pResource->SetNeedsMipGen(true); + + for (uint32_t tex = m_activeTextures; tex; tex &= tex - 1) { + // Guaranteed to not be nullptr... + const uint32_t i = bit::tzcnt(tex); + auto texInfo = GetCommonTexture(m_state.textures[i]); + + if (texInfo == pResource) { + m_activeTexturesToGen |= 1 << i; + // We can early out here, no need to add another index for this. + break; + } + } + } + + template void D3D9DeviceEx::UpdatePointMode() { if constexpr (!Points) { @@ -5550,6 +5596,12 @@ namespace dxvk { if (unlikely(texturesToUpload != 0)) UploadManagedTextures(texturesToUpload); + uint32_t texturesToGen = m_activeTexturesToGen; + texturesToGen &= m_psShaderMasks.samplerMask | m_vsShaderMasks.samplerMask; + + if (unlikely(texturesToGen != 0)) + GenerateTextureMips(texturesToGen); + auto* ibo = GetCommonBuffer(m_state.indices); if (ibo != nullptr && ibo->NeedsUpload()) FlushBuffer(ibo); diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index 9fccb1a03..7a1ce49cf 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -750,6 +750,10 @@ namespace dxvk { void UploadManagedTextures(uint32_t mask); + void GenerateTextureMips(uint32_t mask); + + void MarkTextureMipsDirty(D3D9CommonTexture* pResource); + template void UpdatePointMode(); @@ -1035,6 +1039,7 @@ namespace dxvk { uint32_t m_alphaSwizzleRTs = 0; uint32_t m_activeTextures = 0; uint32_t m_activeTexturesToUpload = 0; + uint32_t m_activeTexturesToGen = 0; uint32_t m_fetch4Enabled = 0; uint32_t m_lastFetch4 = 0; diff --git a/src/d3d9/d3d9_texture.h b/src/d3d9/d3d9_texture.h index 5ea089388..3d5a5d40c 100644 --- a/src/d3d9/d3d9_texture.h +++ b/src/d3d9/d3d9_texture.h @@ -84,8 +84,10 @@ namespace dxvk { } void STDMETHODCALLTYPE GenerateMipSubLevels() final { - if (m_texture.IsAutomaticMip()) - this->m_parent->GenerateMips(&m_texture); + if (!m_texture.NeedsMipGen()) + return; + + this->m_parent->GenerateMips(&m_texture); } D3D9CommonTexture* GetCommonTexture() {