...
 
Commits (9)
......@@ -33,6 +33,10 @@ namespace dxvk {
return m_buffer.Unlock();
}
void STDMETHODCALLTYPE PreLoad() final {
m_buffer.PreLoad();
}
D3D9CommonBuffer* GetCommonBuffer() {
return &m_buffer;
}
......
......@@ -50,6 +50,16 @@ namespace dxvk {
}
void D3D9CommonBuffer::PreLoad() {
if (IsPoolManaged(m_desc.Pool)) {
auto lock = m_parent->LockDevice();
if (NeedsUpload())
m_parent->FlushBuffer(this);
}
}
Rc<DxvkBuffer> D3D9CommonBuffer::CreateBuffer() const {
DxvkBufferCreateInfo info;
info.size = m_desc.Size;
......
......@@ -163,6 +163,8 @@ namespace dxvk {
return locked;
}
void PreLoad();
private:
Rc<DxvkBuffer> CreateBuffer() const;
......
......@@ -465,6 +465,31 @@ namespace dxvk {
}
void D3D9CommonTexture::PreLoadAll() {
if (!IsManaged())
return;
auto lock = m_device->LockDevice();
m_device->UploadManagedTexture(this);
m_device->MarkTextureUploaded(this);
}
void D3D9CommonTexture::PreLoadSubresource(UINT Subresource) {
if (IsManaged()) {
auto lock = m_device->LockDevice();
if (GetNeedsUpload(Subresource)) {
m_device->FlushImage(this, Subresource);
SetNeedsUpload(Subresource, false);
if (!NeedsAnyUpload())
m_device->MarkTextureUploaded(this);
}
}
}
void D3D9CommonTexture::CreateSampleView(UINT Lod) {
// This will be a no-op for SYSTEMMEM types given we
// don't expose the cap to allow texturing with them.
......
......@@ -350,11 +350,8 @@ namespace dxvk {
bool Srgb);
D3D9SubresourceBitset& GetUploadBitmask() { return m_needsUpload; }
void SetUploading(UINT Subresource, bool uploading) { m_uploading.set(Subresource, uploading); }
void ClearUploading() { m_uploading.clearAll(); }
bool GetUploading(UINT Subresource) const { return m_uploading.get(Subresource); }
void SetNeedsUpload(UINT Subresource, bool upload) { m_needsUpload.set(Subresource, upload); }
bool GetNeedsUpload(UINT Subresource) const { return m_needsUpload.get(Subresource); }
bool NeedsAnyUpload() { return m_needsUpload.any(); }
void ClearNeedsUpload() { return m_needsUpload.clearAll(); }
......@@ -366,6 +363,9 @@ namespace dxvk {
void SetMipFilter(D3DTEXTUREFILTERTYPE filter) { m_mipFilter = filter; }
D3DTEXTUREFILTERTYPE GetMipFilter() const { return m_mipFilter; }
void PreLoadAll();
void PreLoadSubresource(UINT Subresource);
private:
D3D9DeviceEx* m_device;
......@@ -400,7 +400,6 @@ namespace dxvk {
D3D9SubresourceBitset m_dirty = { };
D3D9SubresourceBitset m_uploading = { };
D3D9SubresourceBitset m_needsUpload = { };
DWORD m_exposedMipLevels = 0;
......
......@@ -3971,7 +3971,7 @@ namespace dxvk {
physSlice = pResource->DiscardMapSlice(Subresource);
EmitCs([
cImageBuffer = mappedBuffer,
cImageBuffer = std::move(mappedBuffer),
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
......@@ -3988,16 +3988,27 @@ namespace dxvk {
// calling app promises not to overwrite data that is in use
// or is reading. Remember! This will only trigger for MANAGED resources
// that cannot get affected by GPU, therefore readonly is A-OK for NOT waiting.
const bool uploading = pResource->GetUploading(Subresource);
const bool skipWait = (managed && !uploading) || (readOnly && managed) || scratch || (readOnly && systemmem && !dirty);
const bool skipWait = (readOnly && managed) || scratch || (readOnly && systemmem && !dirty);
if (alloced)
std::memset(physSlice.mapPtr, 0, physSlice.length);
else if (!skipWait) {
else if (managed && !skipWait) {
if (!WaitForResource(mappedBuffer, D3DLOCK_DONOTWAIT)) {
// if the mapped buffer is currently being copied to image and it's small enough
// we can just avoid a stall by allocating a new slice and copying the existing contents
DxvkBufferSliceHandle oldSlice = physSlice;
physSlice = pResource->DiscardMapSlice(Subresource);
std::memcpy(physSlice.mapPtr, oldSlice.mapPtr, oldSlice.length);
EmitCs([
cImageBuffer = std::move(mappedBuffer),
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
});
}
} else if (!skipWait) {
if (!WaitForResource(mappedBuffer, Flags))
return D3DERR_WASSTILLDRAWING;
pResource->ClearUploading();
}
}
else {
......@@ -4120,6 +4131,7 @@ namespace dxvk {
(!atiHack) ? formatInfo : nullptr,
pBox);
uint8_t* data = reinterpret_cast<uint8_t*>(physSlice.mapPtr);
data += offset;
pLockedBox->pBits = data;
......@@ -4188,8 +4200,6 @@ namespace dxvk {
auto convertFormat = pResource->GetFormatMapping().ConversionFormatInfo;
pResource->SetUploading(Subresource, true);
if (likely(convertFormat.FormatType == D3D9ConversionFormat_None)) {
EmitCs([
cSrcBuffer = copyBuffer,
......@@ -4218,6 +4228,9 @@ namespace dxvk {
void D3D9DeviceEx::EmitGenerateMips(
D3D9CommonTexture* pResource) {
if (pResource->IsManaged())
UploadManagedTexture(pResource);
EmitCs([
cImageView = pResource->GetSampleView(false),
cFilter = pResource->GetMipFilter()
......@@ -4304,6 +4317,9 @@ namespace dxvk {
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cBuffer, cBufferSlice);
});
pResource->SetReadLocked(false);
pResource->DirtyRange().Clear();
}
else {
// NOOVERWRITE promises that they will not write in a currently used area.
......@@ -4315,15 +4331,28 @@ namespace dxvk {
const bool skipWait = (Flags & D3DLOCK_NOOVERWRITE) ||
quickRead ||
(boundsCheck && !pResource->DirtyRange().Overlaps(pResource->LockRange()));
if (!skipWait) {
if (!(Flags & D3DLOCK_DONOTWAIT)) {
pResource->SetReadLocked(false);
pResource->DirtyRange().Clear();
if (IsPoolManaged(desc.Pool)) {
if (!WaitForResource(mappingBuffer, D3DLOCK_DONOTWAIT)) {
// if the mapped buffer is currently being copied to the primary buffer and it's small enough
// we can just avoid a stall by allocating a new slice and copying the existing contents
DxvkBufferSliceHandle oldSlice = physSlice;
physSlice = pResource->DiscardMapSlice();
std::memcpy(physSlice.mapPtr, oldSlice.mapPtr, oldSlice.length);
EmitCs([
cBuffer = std::move(mappingBuffer),
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cBuffer, cBufferSlice);
});
}
} else {
if (!WaitForResource(mappingBuffer, Flags))
return D3DERR_WASSTILLDRAWING;
}
if (!WaitForResource(mappingBuffer, Flags))
return D3DERR_WASSTILLDRAWING;
pResource->SetReadLocked(false);
pResource->DirtyRange().Clear();
}
// Use map pointer from previous map operation. This
......@@ -4886,21 +4915,22 @@ namespace dxvk {
}
void D3D9DeviceEx::UploadManagedTextures(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)]);
void D3D9DeviceEx::UploadManagedTexture(D3D9CommonTexture* pResource) {
for (uint32_t subresource = 0; subresource < pResource->CountSubresources(); subresource++) {
if (!pResource->GetNeedsUpload(subresource))
continue;
for (uint32_t i = 0; i < texInfo->GetUploadBitmask().dwordCount(); i++) {
for (uint32_t subresources = texInfo->GetUploadBitmask().dword(i); subresources; subresources &= subresources - 1) {
uint32_t subresource = i * 32 + bit::tzcnt(subresources);
this->FlushImage(pResource, subresource);
}
this->FlushImage(texInfo, subresource);
}
}
pResource->ClearNeedsUpload();
}
texInfo->ClearNeedsUpload();
}
void D3D9DeviceEx::UploadManagedTextures(uint32_t mask) {
// Guaranteed to not be nullptr...
for (uint32_t tex = mask; tex; tex &= tex - 1)
UploadManagedTexture(GetCommonTexture(m_state.textures[bit::tzcnt(tex)]));
m_activeTexturesToUpload &= ~mask;
}
......@@ -4952,6 +4982,18 @@ namespace dxvk {
}
void D3D9DeviceEx::MarkTextureUploaded(D3D9CommonTexture* pResource) {
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_activeTexturesToUpload &= ~(1 << i);
}
}
template <bool Points>
void D3D9DeviceEx::UpdatePointMode() {
if constexpr (!Points) {
......
......@@ -748,6 +748,8 @@ namespace dxvk {
void MarkRenderHazards();
void UploadManagedTexture(D3D9CommonTexture* pResource);
void UploadManagedTextures(uint32_t mask);
void GenerateTextureMips(uint32_t mask);
......@@ -756,6 +758,8 @@ namespace dxvk {
void MarkTextureMipsUnDirty(D3D9CommonTexture* pResource);
void MarkTextureUploaded(D3D9CommonTexture* pResource);
template <bool Points>
void UpdatePointMode();
......
......@@ -70,9 +70,6 @@ namespace dxvk {
return m_priority;
}
void STDMETHODCALLTYPE PreLoad() {
}
protected:
......
......@@ -52,6 +52,10 @@ namespace dxvk {
return this->GetDevice()->QueryInterface(riid, ppContainer);
}
void STDMETHODCALLTYPE PreLoad() {
m_texture->PreLoadSubresource(GetSubresource());
}
D3D9CommonTexture* GetCommonTexture() {
return m_texture;
}
......
......@@ -77,7 +77,10 @@ namespace dxvk {
if (unlikely(FilterType == D3DTEXF_NONE))
return D3DERR_INVALIDCALL;
auto lock = this->m_parent->LockDevice();
m_texture.SetMipFilter(FilterType);
this->m_parent->MarkTextureMipsDirty(&m_texture);
return D3D_OK;
}
......@@ -89,10 +92,16 @@ namespace dxvk {
if (!m_texture.NeedsMipGen())
return;
auto lock = this->m_parent->LockDevice();
this->m_parent->MarkTextureMipsUnDirty(&m_texture);
this->m_parent->EmitGenerateMips(&m_texture);
}
void STDMETHODCALLTYPE PreLoad() final {
m_texture.PreLoadAll();
}
D3D9CommonTexture* GetCommonTexture() {
return &m_texture;
}
......
......@@ -201,6 +201,10 @@ namespace dxvk {
{ R"(\\SecretWorldLegendsDX11\.exe$)", {{
{ "d3d11.constantBufferRangeCheck", "True" },
}} },
/* Stars End */
{ R"(\\Stars End\.exe$)", {{
{ "d3d11.enableRtOutputNanFixup", "True" },
}} },
/**********************************************/
/* D3D9 GAMES */
......