From bb6092e0bded498c8b50c35a620a77a73caea80f Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 10 Aug 2019 14:02:51 +0200 Subject: [PATCH] Partial workaround for black D3DTA_DIFFUSE color on some drivers when RHW=0 Fixes black screen issues under some circumstances (e.g. underwater) in Might and Magic 9 (issue #48). --- DDrawCompat/Common/VtableHookVisitor.h | 8 +-- DDrawCompat/D3dDdi/Device.cpp | 33 ++++++++++ DDrawCompat/D3dDdi/Device.h | 4 ++ DDrawCompat/D3dDdi/DeviceFuncs.cpp | 2 + DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp | 70 +++++++++++++++++++++ DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h | 8 +++ DDrawCompat/D3dDdi/Resource.cpp | 34 ++++++++++ DDrawCompat/D3dDdi/Resource.h | 1 + DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 ++ DDrawCompat/Direct3d/Direct3d.h | 5 +- DDrawCompat/Direct3d/Direct3dDevice.h | 5 +- DDrawCompat/Direct3d/Direct3dTexture.h | 5 +- DDrawCompat/Direct3d/Direct3dVertexBuffer.h | 5 +- DDrawCompat/Direct3d/Direct3dViewport.h | 5 +- DDrawCompat/Direct3d/Log.cpp | 26 ++++++++ DDrawCompat/Direct3d/Log.h | 9 +++ 17 files changed, 213 insertions(+), 15 deletions(-) create mode 100644 DDrawCompat/Direct3d/Log.cpp create mode 100644 DDrawCompat/Direct3d/Log.h diff --git a/DDrawCompat/Common/VtableHookVisitor.h b/DDrawCompat/Common/VtableHookVisitor.h index 14a776c1..6fac20da 100644 --- a/DDrawCompat/Common/VtableHookVisitor.h +++ b/DDrawCompat/Common/VtableHookVisitor.h @@ -7,7 +7,7 @@ struct _D3DDDI_ADAPTERCALLBACKS; struct _D3DDDI_ADAPTERFUNCS; -struct _D3DDDI_DEVICEALLBACKS; +struct _D3DDDI_DEVICECALLBACKS; struct _D3DDDI_DEVICEFUNCS; template @@ -20,7 +20,7 @@ template <> class ScopedVtableFuncLock<_D3DDDI_ADAPTERFUNCS> : public D3dDdi::ScopedCriticalSection {}; template <> -class ScopedVtableFuncLock<_D3DDDI_DEVICEALLBACKS> : public D3dDdi::ScopedCriticalSection {}; +class ScopedVtableFuncLock<_D3DDDI_DEVICECALLBACKS> : public D3dDdi::ScopedCriticalSection {}; template <> class ScopedVtableFuncLock<_D3DDDI_DEVICEFUNCS> : public D3dDdi::ScopedCriticalSection {}; @@ -42,9 +42,7 @@ class VtableHookVisitor m_origVtable.*ptr = m_srcVtable.*ptr; if (m_origVtable.*ptr && s_compatVtable.*ptr) { -#ifdef DEBUGLOGS - Compat::Log() << "Hooking function: " << FuncNameVisitor::getFuncName(); -#endif + Compat::LogDebug() << "Hooking function: " << FuncNameVisitor::getFuncName(); Compat::hookFunction(reinterpret_cast(m_origVtable.*ptr), getThreadSafeFuncPtr(s_compatVtable.*ptr)); } diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index f9ed8cd9..e08d9aac 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -38,6 +38,8 @@ namespace D3dDdi , m_adapter(Adapter::get(adapter)) , m_device(device) , m_sharedPrimary(nullptr) + , m_streamSourceData{} + , m_streamSource(nullptr) { } @@ -135,6 +137,10 @@ namespace D3dDdi g_gdiResourceHandle = nullptr; g_gdiResource = nullptr; } + if (resource == m_streamSource) + { + m_streamSource = nullptr; + } } return result; @@ -155,6 +161,11 @@ namespace D3dDdi HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer) { + if (m_streamSource && 0 != m_streamSourceData.Stride) + { + m_streamSource->fixVertexData(m_streamSourceData.Offset + data.VStart * m_streamSourceData.Stride, + data.PrimitiveCount, m_streamSourceData.Stride); + } prepareForRendering(); return m_origVtable.pfnDrawPrimitive(m_device, &data, flagBuffer); } @@ -214,6 +225,28 @@ namespace D3dDdi return m_origVtable.pfnPresent1(m_device, &data); } + HRESULT Device::setStreamSource(const D3DDDIARG_SETSTREAMSOURCE& data) + { + HRESULT result = m_origVtable.pfnSetStreamSource(m_device, &data); + if (SUCCEEDED(result) && 0 == data.Stream) + { + m_streamSourceData = data; + m_streamSource = getResource(data.hVertexBuffer); + } + return result; + } + + HRESULT Device::setStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& data, const void* umBuffer) + { + HRESULT result = m_origVtable.pfnSetStreamSourceUm(m_device, &data, umBuffer); + if (SUCCEEDED(result) && 0 == data.Stream) + { + m_streamSourceData = {}; + m_streamSource = nullptr; + } + return result; + } + HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data) { prepareForRendering(data.hDstResource, UINT_MAX, false); diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index abfb21f4..d08a7b4f 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -36,6 +36,8 @@ namespace D3dDdi HRESULT openResource(D3DDDIARG_OPENRESOURCE& data); HRESULT present(const D3DDDIARG_PRESENT& data); HRESULT present1(D3DDDIARG_PRESENT1& data); + HRESULT setStreamSource(const D3DDDIARG_SETSTREAMSOURCE& data); + HRESULT setStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& data, const void* umBuffer); HRESULT texBlt(const D3DDDIARG_TEXBLT& data); HRESULT texBlt1(const D3DDDIARG_TEXBLT1& data); HRESULT unlock(const D3DDDIARG_UNLOCK& data); @@ -76,6 +78,8 @@ namespace D3dDdi std::map, Resource&> m_dirtyRenderTargets; std::map, Resource&> m_dirtyTextures; HANDLE m_sharedPrimary; + D3DDDIARG_SETSTREAMSOURCE m_streamSourceData; + Resource* m_streamSource; static std::map s_devices; }; diff --git a/DDrawCompat/D3dDdi/DeviceFuncs.cpp b/DDrawCompat/D3dDdi/DeviceFuncs.cpp index bd533015..75b37bca 100644 --- a/DDrawCompat/D3dDdi/DeviceFuncs.cpp +++ b/DDrawCompat/D3dDdi/DeviceFuncs.cpp @@ -54,6 +54,8 @@ namespace D3dDdi vtable.pfnOpenResource = &DEVICE_FUNC(openResource); vtable.pfnPresent = &DEVICE_FUNC(present); vtable.pfnPresent1 = &DEVICE_FUNC(present1); + vtable.pfnSetStreamSource = &DEVICE_FUNC(setStreamSource); + vtable.pfnSetStreamSourceUm = &DEVICE_FUNC(setStreamSourceUm); vtable.pfnTexBlt = &DEVICE_FUNC(texBlt); vtable.pfnTexBlt1 = &DEVICE_FUNC(texBlt1); vtable.pfnUnlock = &DEVICE_FUNC(unlock); diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index e659287e..280835e5 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -88,6 +88,44 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE2& val) << Compat::hex(val.Flags2.Value); } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE& val) +{ + return Compat::LogStruct(os) + << val.PrimitiveType + << val.BaseVertexIndex + << val.MinIndex + << val.NumVertices + << val.StartIndex + << val.PrimitiveCount; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& val) +{ + return Compat::LogStruct(os) + << val.PrimitiveType + << val.BaseVertexOffset + << val.MinIndex + << val.NumVertices + << val.StartIndexOffset + << val.PrimitiveCount; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWPRIMITIVE& val) +{ + return Compat::LogStruct(os) + << val.PrimitiveType + << val.VStart + << val.PrimitiveCount; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWPRIMITIVE2& val) +{ + return Compat::LogStruct(os) + << val.PrimitiveType + << val.FirstVertexOffset + << val.PrimitiveCount; +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_LOCK& val) { return Compat::LogStruct(os) @@ -152,6 +190,38 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_RENDERSTATE& val) << val.Value; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETRENDERTARGET& val) +{ + return Compat::LogStruct(os) + << val.RenderTargetIndex + << val.hRenderTarget + << val.SubResourceIndex; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCE& val) +{ + return Compat::LogStruct(os) + << val.Stream + << val.hVertexBuffer + << val.Offset + << val.Stride; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCEUM& val) +{ + return Compat::LogStruct(os) + << val.Stream + << val.Stride; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXTURESTAGESTATE& val) +{ + return Compat::LogStruct(os) + << val.Stage + << val.State + << val.Value; +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index 10835a90..f27a37b3 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -12,12 +12,20 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CLEAR& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_COLORFILL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE2& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWPRIMITIVE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_DRAWPRIMITIVE2& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_LOCK& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_OPENRESOURCE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT1& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENTSURFACE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_RENDERSTATE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETRENDERTARGET& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCEUM& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXTURESTAGESTATE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_WINFO& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_ZRANGE& val); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 342f7414..6ce0ca0e 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -334,6 +334,15 @@ namespace D3dDdi template Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*)) { + if (D3DDDIFMT_VERTEXDATA == data.Format && + data.Flags.VertexBuffer && + data.Flags.MightDrawFromLocked && + D3DDDIPOOL_SYSTEMMEM != data.Pool) + { + const HRESULT D3DERR_NOTAVAILABLE = 0x8876086A; + throw HResultException(D3DERR_NOTAVAILABLE); + } + Resource resource(device, data); Arg origData = data; fixResourceData(device, reinterpret_cast(data)); @@ -371,6 +380,31 @@ namespace D3dDdi } } + void Resource::fixVertexData(UINT offset, UINT count, UINT stride) + { + if (!m_fixedData.Flags.MightDrawFromLocked || + !m_fixedData.pSurfList[0].pSysMem || + !(m_fixedData.Fvf & D3DFVF_XYZRHW)) + { + return; + } + + unsigned char* data = static_cast(const_cast(m_fixedData.pSurfList[0].pSysMem)) + offset; + if (0.0f != reinterpret_cast(data)->rhw) + { + return; + } + + for (UINT i = 0; i < count; ++i) + { + if (0.0f == reinterpret_cast(data)->rhw) + { + reinterpret_cast(data)->rhw = 1.0f; + } + data += stride; + } + } + void* Resource::getLockPtr(UINT subResourceIndex) { if (subResourceIndex < m_lockData.size()) diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 18e2975a..676b73d6 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -28,6 +28,7 @@ namespace D3dDdi HRESULT blt(D3DDDIARG_BLT data); HRESULT colorFill(const D3DDDIARG_COLORFILL& data); void destroy(); + void fixVertexData(UINT offset, UINT count, UINT stride); void* getLockPtr(UINT subResourceIndex); HRESULT lock(D3DDDIARG_LOCK& data); void prepareForRendering(UINT subResourceIndex, bool isReadOnly); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 8c70a305..0308ee63 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -198,6 +198,7 @@ + @@ -265,6 +266,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 3aa7edfb..063710f8 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -354,6 +354,9 @@ Header Files\D3dDdi + + Header Files\Direct3d + @@ -539,6 +542,9 @@ Source Files\D3dDdi + + Source Files\Direct3d + diff --git a/DDrawCompat/Direct3d/Direct3d.h b/DDrawCompat/Direct3d/Direct3d.h index 56a95ee3..ca00e596 100644 --- a/DDrawCompat/Direct3d/Direct3d.h +++ b/DDrawCompat/Direct3d/Direct3d.h @@ -1,7 +1,8 @@ #pragma once -#include "Common/CompatVtable.h" -#include "Direct3d/Visitors/Direct3dVtblVisitor.h" +#include +#include +#include namespace Direct3d { diff --git a/DDrawCompat/Direct3d/Direct3dDevice.h b/DDrawCompat/Direct3d/Direct3dDevice.h index f03bf4d2..6a6a65c6 100644 --- a/DDrawCompat/Direct3d/Direct3dDevice.h +++ b/DDrawCompat/Direct3d/Direct3dDevice.h @@ -1,7 +1,8 @@ #pragma once -#include "Common/CompatVtable.h" -#include "Direct3d/Visitors/Direct3dDeviceVtblVisitor.h" +#include +#include +#include namespace Direct3d { diff --git a/DDrawCompat/Direct3d/Direct3dTexture.h b/DDrawCompat/Direct3d/Direct3dTexture.h index bdae7bbc..05d309d3 100644 --- a/DDrawCompat/Direct3d/Direct3dTexture.h +++ b/DDrawCompat/Direct3d/Direct3dTexture.h @@ -1,7 +1,8 @@ #pragma once -#include "Common/CompatVtable.h" -#include "Direct3d/Visitors/Direct3dTextureVtblVisitor.h" +#include +#include +#include namespace Direct3d { diff --git a/DDrawCompat/Direct3d/Direct3dVertexBuffer.h b/DDrawCompat/Direct3d/Direct3dVertexBuffer.h index c564ca22..39853711 100644 --- a/DDrawCompat/Direct3d/Direct3dVertexBuffer.h +++ b/DDrawCompat/Direct3d/Direct3dVertexBuffer.h @@ -1,7 +1,8 @@ #pragma once -#include "Common/CompatVtable.h" -#include "Direct3d/Visitors/Direct3dVertexBufferVtblVisitor.h" +#include +#include +#include namespace Direct3d { diff --git a/DDrawCompat/Direct3d/Direct3dViewport.h b/DDrawCompat/Direct3d/Direct3dViewport.h index 558b5471..90168023 100644 --- a/DDrawCompat/Direct3d/Direct3dViewport.h +++ b/DDrawCompat/Direct3d/Direct3dViewport.h @@ -1,7 +1,8 @@ #pragma once -#include "Common/CompatVtable.h" -#include "Direct3d/Visitors/Direct3dViewportVtblVisitor.h" +#include +#include +#include namespace Direct3d { diff --git a/DDrawCompat/Direct3d/Log.cpp b/DDrawCompat/Direct3d/Log.cpp new file mode 100644 index 00000000..6029d481 --- /dev/null +++ b/DDrawCompat/Direct3d/Log.cpp @@ -0,0 +1,26 @@ +#include + +std::ostream& operator<<(std::ostream& os, const D3DDP_PTRSTRIDE& data) +{ + return Compat::LogStruct(os) + << data.lpvData + << data.dwStride; +} + +std::ostream& operator<<(std::ostream& os, const D3DDRAWPRIMITIVESTRIDEDDATA& data) +{ + return Compat::LogStruct(os) + << data.position + << data.normal + << data.diffuse + << data.specular + << Compat::array(data.textureCoords, D3DDP_MAXTEXCOORD); +} + +std::ostream& operator<<(std::ostream& os, const D3DVERTEXBUFFERDESC& data) +{ + return Compat::LogStruct(os) + << Compat::hex(data.dwCaps) + << Compat::hex(data.dwFVF) + << data.dwNumVertices; +} diff --git a/DDrawCompat/Direct3d/Log.h b/DDrawCompat/Direct3d/Log.h new file mode 100644 index 00000000..fb8eddc6 --- /dev/null +++ b/DDrawCompat/Direct3d/Log.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include + +std::ostream& operator<<(std::ostream& os, const D3DDP_PTRSTRIDE& data); +std::ostream& operator<<(std::ostream& os, const D3DDRAWPRIMITIVESTRIDEDDATA& data); +std::ostream& operator<<(std::ostream& os, const D3DVERTEXBUFFERDESC& data);