From 0b974e2dd7749620bc0d9cf6374a147091a9700b Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 23 Jun 2024 19:35:03 +0200 Subject: [PATCH] Added VertexFixup setting See issues #164 and #327. --- DDrawCompat/Config/Config.cpp | 2 + DDrawCompat/Config/Settings/VertexFixup.h | 22 ++++ DDrawCompat/D3dDdi/DeviceState.cpp | 87 +++++++++++----- DDrawCompat/D3dDdi/DeviceState.h | 17 ++- DDrawCompat/D3dDdi/DrawPrimitive.cpp | 121 ++++++++++++++++++++++ DDrawCompat/D3dDdi/DrawPrimitive.h | 2 + DDrawCompat/DDrawCompat.vcxproj | 1 + DDrawCompat/DDrawCompat.vcxproj.filters | 3 + DDrawCompat/Overlay/ConfigWindow.cpp | 2 + 9 files changed, 230 insertions(+), 27 deletions(-) create mode 100644 DDrawCompat/Config/Settings/VertexFixup.h diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index 5d81adb..6021fda 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,7 @@ namespace Config Settings::TextureFilter textureFilter; Settings::ThreadPriorityBoost threadPriorityBoost; Settings::VertexBufferMemoryType vertexBufferMemoryType; + Settings::VertexFixup vertexFixup; Settings::VSync vSync; Settings::WinVersionLie winVersionLie; } diff --git a/DDrawCompat/Config/Settings/VertexFixup.h b/DDrawCompat/Config/Settings/VertexFixup.h new file mode 100644 index 0000000..7998e8f --- /dev/null +++ b/DDrawCompat/Config/Settings/VertexFixup.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace Config +{ + namespace Settings + { + class VertexFixup : public EnumSetting + { + public: + enum Values { CPU, GPU }; + + VertexFixup() + : EnumSetting("VertexFixup", "gpu", { "cpu", "gpu" }) + { + } + }; + } + + extern Settings::VertexFixup vertexFixup; +} diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 62778b5..12a7ae8 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,8 @@ namespace D3dDdi , m_vertexShaderConstB{} , m_vertexShaderConstI{} , m_vertexDecl(nullptr) + , m_vertexFixupConfig(Config::vertexFixup.get()) + , m_vertexFixupData{} , m_changedStates(0) , m_maxChangedTextureStage(0) , m_texCoordIndexes(0) @@ -100,6 +103,8 @@ namespace D3dDdi const UINT D3DBLENDOP_ADD = 1; const UINT UNINITIALIZED_STATE = 0xBAADBAAD; + m_vertexFixupData.multiplier[3] = 1.0f; + m_device.getOrigVtable().pfnSetDepthStencil(m_device, &m_current.depthStencil); m_device.getOrigVtable().pfnSetRenderTarget(m_device, &m_current.renderTarget); m_device.getOrigVtable().pfnSetViewport(m_device, &m_current.viewport); @@ -298,6 +303,10 @@ namespace D3dDdi { updateTextureStages(); } + if (m_changedStates & CS_VERTEX_FIXUP) + { + updateVertexFixupShaderConst(); + } m_changedStates = 0; m_maxChangedTextureStage = 0; @@ -1012,18 +1021,10 @@ namespace D3dDdi auto resource = (texture == m_app.textures[stage]) ? getTextureResource(stage) : m_device.getResource(texture); if (resource) { - D3DDDIARG_SETVERTEXSHADERCONST data = {}; - data.Register = 253; - data.Count = 1; - auto& si = resource->getFixedDesc().pSurfList[0]; - ShaderConstF reg = { static_cast(si.Width), static_cast(si.Height), - m_vertexShaderConst[253][2], m_vertexShaderConst[253][3] }; - - if (0 != memcmp(®, &m_vertexShaderConst[data.Register], sizeof(reg))) - { - pfnSetVertexShaderConst(&data, ®); - } + m_vertexFixupData.texCoordAdj[0] = static_cast(si.Width); + m_vertexFixupData.texCoordAdj[1] = static_cast(si.Height); + m_changedStates |= CS_VERTEX_FIXUP; } } @@ -1107,6 +1108,7 @@ namespace D3dDdi m_changedStates |= CS_RENDER_STATE | CS_RENDER_TARGET | CS_SHADER | CS_TEXTURE_STAGE; m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE); m_changedRenderStates.set(D3DDDIRS_MULTISAMPLEANTIALIAS); + m_vertexFixupConfig = Config::vertexFixup.get(); for (auto& ps : m_pixelShaders) { @@ -1211,7 +1213,7 @@ namespace D3dDdi { const float sx = static_cast(scaledVp.Width) / vp.Width; const float sy = static_cast(scaledVp.Height) / vp.Height; - updateVertexFixupConstants(vp.Width, vp.Height, sx, sy); + updateVertexFixupData(vp.Width, vp.Height, sx, sy); } const bool isScissorRectNeeded = isTransformed && 0 != memcmp(&vp, &m_app.viewport, sizeof(vp)); @@ -1230,7 +1232,16 @@ namespace D3dDdi { setPixelShader(mapPixelShader(m_app.pixelShader)); setVertexShaderDecl(m_app.vertexShaderDecl); - setVertexShaderFunc(getVertexDecl().isTransformed ? getVsVertexFixup() : m_app.vertexShaderFunc); + + if (Config::Settings::VertexFixup::GPU == m_vertexFixupConfig && + getVertexDecl().isTransformed) + { + setVertexShaderFunc(getVsVertexFixup()); + } + else + { + setVertexShaderFunc(m_app.vertexShaderFunc); + } } void DeviceState::updateStreamSource() @@ -1321,25 +1332,51 @@ namespace D3dDdi } } - void DeviceState::updateVertexFixupConstants(UINT width, UINT height, float sx, float sy) + void DeviceState::updateVertexFixupData(UINT width, UINT height, float sx, float sy) { - D3DDDIARG_SETVERTEXSHADERCONST data = {}; - data.Register = 253; - data.Count = 3; - const float stc = static_cast(Config::spriteTexCoord.getParam()) / 100; const float apc = Config::alternatePixelCenter.get(); const auto& zr = m_current.zRange; - ShaderConstF registers[3] = { - { m_vertexShaderConst[253][0], m_vertexShaderConst[253][1], stc, stc }, - { 0.5f + apc - 0.5f / sx - width / 2, 0.5f + apc - 0.5f / sy - height / 2, -zr.MinZ, 0.0f }, - { 2.0f / width, -2.0f / height, 1.0f / (zr.MaxZ - zr.MinZ), 1.0f } - }; + m_vertexFixupData.texCoordAdj[2] = stc; + m_vertexFixupData.texCoordAdj[3] = stc; - if (0 != memcmp(registers, &m_vertexShaderConst[data.Register], sizeof(registers))) + if (Config::Settings::VertexFixup::GPU == m_vertexFixupConfig) { - pfnSetVertexShaderConst(&data, registers); + m_vertexFixupData.offset[0] = 0.5f + apc - 0.5f / sx - width / 2; + m_vertexFixupData.offset[1] = 0.5f + apc - 0.5f / sy - height / 2; + m_vertexFixupData.offset[2] = -zr.MinZ; + + m_vertexFixupData.multiplier[0] = 2.0f / width; + m_vertexFixupData.multiplier[1] = -2.0f / height; + m_vertexFixupData.multiplier[2] = 1.0f / (zr.MaxZ - zr.MinZ); + } + else + { + m_vertexFixupData.offset[0] = 0.5f + apc - 0.5f / sx; + m_vertexFixupData.offset[1] = 0.5f + apc - 0.5f / sy; + + m_vertexFixupData.multiplier[0] = sx; + m_vertexFixupData.multiplier[1] = sy; + } + + m_changedStates |= CS_VERTEX_FIXUP; + } + + void DeviceState::updateVertexFixupShaderConst() + { + if (m_current.vertexShaderFunc == m_app.vertexShaderFunc) + { + return; + } + + D3DDDIARG_SETVERTEXSHADERCONST data = {}; + data.Register = 253; + data.Count = 3; + + if (0 != memcmp(&m_vertexFixupData, &m_vertexShaderConst[data.Register], sizeof(m_vertexFixupData))) + { + pfnSetVertexShaderConst(&data, &m_vertexFixupData.texCoordAdj); } } } diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index 51576ad..c91e596 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -109,6 +109,13 @@ namespace D3dDdi bool isTransformed; }; + struct VertexFixupData + { + ShaderConstF texCoordAdj; + ShaderConstF offset; + ShaderConstF multiplier; + }; + DeviceState(Device& device); HRESULT pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code); @@ -153,9 +160,11 @@ namespace D3dDdi void flush(); const State& getAppState() const { return m_app; } const State& getCurrentState() const { return m_current; } + bool getSpriteMode() const { return m_spriteMode; } Resource* getTextureResource(UINT stage); UINT getTextureStageCount() const; const VertexDecl& getVertexDecl() const; + const VertexFixupData& getVertexFixupData() const { return m_vertexFixupData; } bool isLocked() const { return m_isLocked; } void onDestroyResource(Resource* resource, HANDLE resourceHandle); void updateConfig(); @@ -168,7 +177,8 @@ namespace D3dDdi CS_RENDER_TARGET = 1 << 1, CS_SHADER = 1 << 2, CS_STREAM_SOURCE = 1 << 3, - CS_TEXTURE_STAGE = 1 << 4 + CS_TEXTURE_STAGE = 1 << 4, + CS_VERTEX_FIXUP = 1 << 5 }; struct PixelShader @@ -230,7 +240,8 @@ namespace D3dDdi void updateShaders(); void updateTextureColorKey(UINT stage); void updateTextureStages(); - void updateVertexFixupConstants(UINT width, UINT height, float sx, float sy); + void updateVertexFixupData(UINT width, UINT height, float sx, float sy); + void updateVertexFixupShaderConst(); Device& m_device; State m_app; @@ -243,6 +254,8 @@ namespace D3dDdi std::array m_vertexShaderConstI; std::map m_vertexShaderDecls; VertexDecl* m_vertexDecl; + UINT m_vertexFixupConfig; + VertexFixupData m_vertexFixupData; UINT m_changedStates; UINT m_maxChangedTextureStage; UINT m_texCoordIndexes; diff --git a/DDrawCompat/D3dDdi/DrawPrimitive.cpp b/DDrawCompat/D3dDdi/DrawPrimitive.cpp index 952013e..9b38b38 100644 --- a/DDrawCompat/D3dDdi/DrawPrimitive.cpp +++ b/DDrawCompat/D3dDdi/DrawPrimitive.cpp @@ -12,6 +12,14 @@ namespace const UINT INDEX_BUFFER_SIZE = D3DMAXNUMPRIMITIVES * 3 * sizeof(UINT16); const UINT VERTEX_BUFFER_SIZE = 1024 * 1024; + enum VertexFixupFlags + { + VF_XY = 1 << 0, + VF_Z = 1 << 1, + VF_RHW = 1 << 2, + VF_TEXCOORD = 1 << 3 + }; + UINT getVertexCount(D3DPRIMITIVETYPE primitiveType, UINT primitiveCount) { switch (primitiveType) @@ -57,6 +65,7 @@ namespace D3dDdi , m_indexBuffer(device, m_vertexBuffer ? INDEX_BUFFER_SIZE : 0) , m_streamSource{} , m_batched{} + , m_vertexFixupFlags(0) { LOG_ONCE("Dynamic vertex buffers are " << (m_vertexBuffer ? "" : "not ") << "available"); LOG_ONCE("Dynamic index buffers are " << (m_indexBuffer ? "" : "not ") << "available"); @@ -325,6 +334,74 @@ namespace D3dDdi { auto vertices = m_streamSource.vertices + base * m_streamSource.stride; m_batched.vertices.insert(m_batched.vertices.end(), vertices, vertices + count * m_streamSource.stride); + + if (0 == m_vertexFixupFlags) + { + return; + } + + auto& vertexFixupData = m_device.getState().getVertexFixupData(); + auto firstVertex = &m_batched.vertices[m_batched.vertices.size() - count * m_streamSource.stride]; + + if (m_vertexFixupFlags & VF_XY) + { + auto vPos = firstVertex; + for (unsigned i = 0; i < count; ++i) + { + auto v = reinterpret_cast(vPos); + v->sx += vertexFixupData.offset[0]; + v->sy += vertexFixupData.offset[1]; + v->sx *= vertexFixupData.multiplier[0]; + v->sy *= vertexFixupData.multiplier[1]; + vPos += m_streamSource.stride; + } + } + + if (m_vertexFixupFlags & VF_Z) + { + auto zPos = reinterpret_cast(&reinterpret_cast(firstVertex)->sz); + for (unsigned i = 0; i < count; ++i) + { + auto& z = *reinterpret_cast(zPos); + if (z > 1) + { + z = 1; + } + zPos += m_streamSource.stride; + } + } + + if (m_vertexFixupFlags & VF_RHW) + { + auto rhwPos = reinterpret_cast(&reinterpret_cast(firstVertex)->rhw); + for (unsigned i = 0; i < count; ++i) + { + auto& rhw = *reinterpret_cast(rhwPos); + if (0 == rhw || INFINITY == rhw) + { + rhw = 1; + } + rhwPos += m_streamSource.stride; + } + } + + if (m_vertexFixupFlags & VF_TEXCOORD) + { + auto tcPos = firstVertex + m_device.getState().getVertexDecl().texCoordOffset[0]; + for (unsigned i = 0; i < count; ++i) + { + float* tc = reinterpret_cast(tcPos); + tc[0] *= vertexFixupData.texCoordAdj[0]; + tc[1] *= vertexFixupData.texCoordAdj[1]; + tc[0] += vertexFixupData.texCoordAdj[2]; + tc[1] += vertexFixupData.texCoordAdj[3]; + tc[0] = roundf(tc[0]); + tc[1] = roundf(tc[1]); + tc[0] /= vertexFixupData.texCoordAdj[0]; + tc[1] /= vertexFixupData.texCoordAdj[1]; + tcPos += m_streamSource.stride; + } + } } void DrawPrimitive::clearBatchedPrimitives() @@ -456,6 +533,7 @@ namespace D3dDdi { auto& state = m_device.getState(); auto vertexCount = getVertexCount(data.PrimitiveType, data.PrimitiveCount); + m_vertexFixupFlags = 0; if (!state.isLocked()) { if (0 == m_batched.primitiveCount) @@ -477,6 +555,7 @@ namespace D3dDdi state.setSpriteMode(false); } state.flush(); + setVertexFixupFlags(data.VStart, 0); } if (0 == m_batched.primitiveCount || flagBuffer || @@ -521,6 +600,7 @@ namespace D3dDdi auto indexCount = getVertexCount(data.PrimitiveType, data.PrimitiveCount); auto vStart = data.BaseVertexOffset / static_cast(m_streamSource.stride); + m_vertexFixupFlags = 0; if (!state.isLocked()) { if (m_streamSource.vertices && data.PrimitiveType >= D3DPT_TRIANGLELIST) @@ -537,6 +617,7 @@ namespace D3dDdi state.setSpriteMode(false); } state.flush(); + setVertexFixupFlags(vStart, indices[0]); } auto [min, max] = std::minmax_element(indices, indices + indexCount); @@ -870,4 +951,44 @@ namespace D3dDdi } } } + + void DrawPrimitive::setVertexFixupFlags(INT baseVertexIndex, UINT16 index) + { + auto& state = m_device.getState(); + if (!state.getVertexDecl().isTransformed || + state.getCurrentState().vertexShaderFunc != state.getAppState().vertexShaderFunc) + { + return; + } + + auto& vertexFixupData = state.getVertexFixupData(); + if (0 != vertexFixupData.offset[0] || + 0 != vertexFixupData.offset[1] || + 1 != vertexFixupData.multiplier[0] || + 1 != vertexFixupData.multiplier[1]) + { + m_vertexFixupFlags |= VF_XY; + } + + auto vertex = reinterpret_cast( + m_streamSource.vertices + (baseVertexIndex + index) * m_streamSource.stride); + if (vertex->sz > 0) + { + m_vertexFixupFlags |= VF_Z; + } + + if (0 == vertex->rhw || INFINITY == vertex->rhw) + { + m_vertexFixupFlags |= VF_RHW; + } + + const UINT D3DDECLTYPE_FLOAT2 = 1; + if (state.getSpriteMode() && + Config::Settings::SpriteTexCoord::ROUND == Config::spriteTexCoord.get() && + 0 != Config::spriteTexCoord.getParam() && + D3DDECLTYPE_FLOAT2 == state.getVertexDecl().texCoordType[0]) + { + m_vertexFixupFlags |= VF_TEXCOORD; + } + } } diff --git a/DDrawCompat/D3dDdi/DrawPrimitive.h b/DDrawCompat/D3dDdi/DrawPrimitive.h index 3036ca8..345be17 100644 --- a/DDrawCompat/D3dDdi/DrawPrimitive.h +++ b/DDrawCompat/D3dDdi/DrawPrimitive.h @@ -71,6 +71,7 @@ namespace D3dDdi HRESULT flush(const UINT* flagBuffer); HRESULT flushIndexed(const UINT* flagBuffer); bool isSprite(INT baseVertexIndex, UINT16 index0, UINT16 index1, UINT16 index2); + void setVertexFixupFlags(INT baseVertexIndex, UINT16 index); INT loadIndices(const void* indices, UINT count); INT loadVertices(UINT count); UINT getBatchedVertexCount() const; @@ -87,5 +88,6 @@ namespace D3dDdi StreamSource m_streamSource; std::map m_sysMemVertexBuffers; BatchedPrimitives m_batched; + UINT m_vertexFixupFlags; }; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index fba9ed0..16c5531 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -214,6 +214,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 8f50274..3d49705 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -717,6 +717,9 @@ Header Files\Common + + Header Files\Config\Settings + diff --git a/DDrawCompat/Overlay/ConfigWindow.cpp b/DDrawCompat/Overlay/ConfigWindow.cpp index ed577cc..1179855 100644 --- a/DDrawCompat/Overlay/ConfigWindow.cpp +++ b/DDrawCompat/Overlay/ConfigWindow.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ namespace { &Config::statsPosY, []() { Gdi::GuiThread::getStatsWindow()->updatePos(); } }, { &Config::statsTransparency, [&]() { Gdi::GuiThread::getStatsWindow()->setAlpha(Config::statsTransparency.get()); }}, { &Config::textureFilter, &D3dDdi::Device::updateAllConfig }, + { &Config::vertexFixup, &D3dDdi::Device::updateAllConfig }, { &Config::vSync } }; }