diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index 16c956f..b5e3f8d 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -9,6 +9,7 @@ namespace Config Settings::DisplayFilter displayFilter; Settings::DisplayResolution displayResolution; Settings::RenderColorDepth renderColorDepth; + Settings::ResolutionScale resolutionScale; Settings::SupportedResolutions supportedResolutions; Settings::TextureFilter textureFilter; Settings::ThreadPriorityBoost threadPriorityBoost; diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index 1b39fe0..473833b 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ namespace Config extern Settings::DisplayFilter displayFilter; extern Settings::DisplayResolution displayResolution; extern Settings::RenderColorDepth renderColorDepth; + extern Settings::ResolutionScale resolutionScale; extern Settings::SupportedResolutions supportedResolutions; extern Settings::TextureFilter textureFilter; extern Settings::ThreadPriorityBoost threadPriorityBoost; diff --git a/DDrawCompat/Config/Settings/ResolutionScale.cpp b/DDrawCompat/Config/Settings/ResolutionScale.cpp new file mode 100644 index 0000000..37e4633 --- /dev/null +++ b/DDrawCompat/Config/Settings/ResolutionScale.cpp @@ -0,0 +1,44 @@ +#include + +namespace Config +{ + namespace Settings + { + ResolutionScale::ResolutionScale() + : MappedSetting("ResolutionScale", "app", { {"app", APP}, {"display", DISPLAY} }) + { + } + + std::string ResolutionScale::getValueStr() const + { + try + { + return MappedSetting::getValueStr(); + } + catch (const ParsingError&) + { + return std::to_string(m_value.cx) + 'x' + std::to_string(m_value.cy); + } + } + + Setting::ParamInfo ResolutionScale::getParamInfo() const + { + return { "Multiplier", APP == m_value ? 1 : -16, 16, 1, m_param }; + } + + void ResolutionScale::setValue(const std::string& value) + { + try + { + MappedSetting::setValue(value); + } + catch (const ParsingError&) + { + m_value = Parser::parseResolution(value); + } + } + + const SIZE ResolutionScale::APP = { 0, 0 }; + const SIZE ResolutionScale::DISPLAY = { 1, 0 }; + } +} diff --git a/DDrawCompat/Config/Settings/ResolutionScale.h b/DDrawCompat/Config/Settings/ResolutionScale.h new file mode 100644 index 0000000..398f288 --- /dev/null +++ b/DDrawCompat/Config/Settings/ResolutionScale.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include +#include + +namespace Config +{ + namespace Settings + { + class ResolutionScale : public MappedSetting + { + public: + static const SIZE APP; + static const SIZE DISPLAY; + + ResolutionScale(); + + virtual ParamInfo getParamInfo() const override; + + protected: + std::string getValueStr() const override; + void setValue(const std::string& value) override; + }; + } +} diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index cbc798c..e0b89d1 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -37,6 +37,7 @@ namespace D3dDdi , m_runtimeVersion(data.Version) , m_driverVersion(data.DriverVersion) , m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid) + , m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().monitorInfo.szDevice) , m_repository{} { } @@ -56,6 +57,11 @@ namespace D3dDdi Compat::Log() << "Supported z-buffer bit depths: " << bitDepthsToString(info.supportedZBufferBitDepths); Compat::Log() << "Supported MSAA modes: " << getSupportedMsaaModes(info.formatOps); + LOG_DEBUG << "Supported resource formats:"; + for (const auto& formatOp : info.formatOps) + { + LOG_DEBUG << " " << formatOp.second; + } return info; } @@ -86,6 +92,14 @@ namespace D3dDdi return result; } + float Adapter::getMaxScaleFactor(SIZE size) const + { + const auto& caps = getInfo().d3dExtendedCaps; + const float scaleX = static_cast(caps.dwMaxTextureWidth) / size.cx; + const float scaleY = static_cast(caps.dwMaxTextureHeight) / size.cy; + return min(scaleX, scaleY); + } + std::pair Adapter::getMultisampleConfig(D3DDDIFORMAT format) const { UINT samples = Config::antialiasing.get(); @@ -113,6 +127,53 @@ namespace D3dDdi return { levels.MsType, min(static_cast(Config::antialiasing.getParam()), levels.QualityLevels - 1) }; } + SIZE Adapter::getScaledSize(SIZE size) const + { + DEVMODEW dm = {}; + dm.dmSize = sizeof(dm); + EnumDisplaySettingsExW(m_deviceName.c_str(), ENUM_CURRENT_SETTINGS, &dm, 0); + + const SIZE emulatedDisplaySize = { static_cast(dm.dmPelsHeight), static_cast(dm.dmPelsHeight) }; + const float displayMaxScaleFactor = getMaxScaleFactor(emulatedDisplaySize); + const float resourceMaxScaleFactor = getMaxScaleFactor(size); + float maxScaleFactor = min(displayMaxScaleFactor, resourceMaxScaleFactor); + if (Config::resolutionScale.getParam() > 0) + { + maxScaleFactor = floor(maxScaleFactor); + } + + SIZE baseSize = Config::resolutionScale.get(); + const int multiplier = Config::resolutionScale.getParam(); + + if (Config::Settings::ResolutionScale::APP == baseSize) + { + baseSize = emulatedDisplaySize; + } + else if (Config::Settings::ResolutionScale::DISPLAY == baseSize) + { + CALL_ORIG_FUNC(EnumDisplaySettingsExW)(m_deviceName.c_str(), ENUM_CURRENT_SETTINGS, &dm, 0); + baseSize = { static_cast(dm.dmPelsHeight), static_cast(dm.dmPelsHeight) }; + } + + float scaleX = static_cast(baseSize.cx) / emulatedDisplaySize.cx; + float scaleY = static_cast(baseSize.cy) / emulatedDisplaySize.cy; + float scale = min(scaleX, scaleY) * abs(multiplier); + if (multiplier > 0) + { + scale = ceil(scale); + } + scale = max(scale, 1.0f); + scale = min(scale, maxScaleFactor); + + size.cx = static_cast(size.cx * scale); + size.cy = static_cast(size.cy * scale); + + const auto& caps = getInfo().d3dExtendedCaps; + size.cx = min(size.cx, static_cast(caps.dwMaxTextureWidth)); + size.cy = min(size.cy, static_cast(caps.dwMaxTextureHeight)); + return size; + } + std::string Adapter::getSupportedMsaaModes(const std::map& formatOps) const { auto it = formatOps.find(D3DDDIFMT_X8R8G8B8); diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index 2bdc709..1d4d11f 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -35,6 +35,7 @@ namespace D3dDdi std::pair getMultisampleConfig(D3DDDIFORMAT format) const; const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; } CompatWeakPtr getRepository() const { return m_repository; } + SIZE getScaledSize(SIZE size) const; HRESULT pfnCloseAdapter(); HRESULT pfnCreateDevice(D3DDDIARG_CREATEDEVICE* pCreateData); @@ -49,6 +50,7 @@ namespace D3dDdi HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const; std::map getFormatOps() const; + float getMaxScaleFactor(SIZE size) const; std::string getSupportedMsaaModes(const std::map& formatOps) const; DWORD getSupportedZBufferBitDepths(const std::map& formatOps) const; @@ -57,6 +59,7 @@ namespace D3dDdi UINT m_runtimeVersion; UINT m_driverVersion; LUID m_luid; + std::wstring m_deviceName; CompatWeakPtr m_repository; static std::map s_adapters; diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index e8177f1..f97b06f 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -18,6 +18,7 @@ namespace { HANDLE g_gdiResourceHandle = nullptr; D3dDdi::Resource* g_gdiResource = nullptr; + bool g_isConfigUpdatePending = false; } namespace D3dDdi @@ -163,12 +164,22 @@ namespace D3dDdi { prepareForGpuWrite(); } + + if (m_renderTarget && rect) + { + std::vector scaledRect(rect, rect + numRect); + for (UINT i = 0; i < numRect; ++i) + { + m_renderTarget->scaleRect(scaledRect[i]); + } + return m_origVtable.pfnClear(m_device, data, numRect, scaledRect.data()); + } + return m_origVtable.pfnClear(m_device, data, numRect, rect); } HRESULT Device::pfnColorFill(const D3DDDIARG_COLORFILL* data) { - flushPrimitives(); auto it = m_resources.find(data->hResource); if (it != m_resources.end()) { @@ -309,7 +320,10 @@ namespace D3dDdi { d.hSrcResource = resource->prepareForGpuRead(data->SrcSubResourceIndex); } - return m_origVtable.pfnPresent(m_device, &d); + + HRESULT result = m_origVtable.pfnPresent(m_device, &d); + updateAllConfigNow(); + return result; } HRESULT Device::pfnPresent1(D3DDDIARG_PRESENT1* data) @@ -325,7 +339,10 @@ namespace D3dDdi srcResources[i].hResource = resource->prepareForGpuRead(srcResources[i].SubResourceIndex); } } - return m_origVtable.pfnPresent1(m_device, data); + + HRESULT result = m_origVtable.pfnPresent1(m_device, data); + updateAllConfigNow(); + return result; } HRESULT Device::pfnUnlock(const D3DDDIARG_UNLOCK* data) @@ -341,11 +358,18 @@ namespace D3dDdi void Device::updateAllConfig() { - DDraw::ScopedThreadLock ddLock; - D3dDdi::ScopedCriticalSection lock; - for (auto& device : s_devices) + g_isConfigUpdatePending = true; + } + + void Device::updateAllConfigNow() + { + if (g_isConfigUpdatePending) { - device.second.updateConfig(); + g_isConfigUpdatePending = false; + for (auto& device : s_devices) + { + device.second.updateConfig(); + } } } diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index d494722..f843f1f 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -70,6 +70,8 @@ namespace D3dDdi static void updateAllConfig(); private: + static void updateAllConfigNow(); + D3DDDI_DEVICEFUNCS m_origVtable; Adapter& m_adapter; HANDLE m_device; diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 8cc7410..01ae673 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -239,17 +239,13 @@ namespace D3dDdi return; } - if (m_changedStates & CS_MISC) - { - updateMisc(); - } if (m_changedStates & CS_RENDER_STATE) { updateRenderStates(); } if (m_changedStates & CS_RENDER_TARGET) { - updateRenderTargets(); + updateRenderTarget(); } if (m_changedStates & CS_SHADER) { @@ -449,21 +445,21 @@ namespace D3dDdi HRESULT DeviceState::pfnSetViewport(const D3DDDIARG_VIEWPORTINFO* data) { m_app.viewport = *data; - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; return S_OK; } HRESULT DeviceState::pfnSetZRange(const D3DDDIARG_ZRANGE* data) { m_app.zRange = *data; - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; return S_OK; } HRESULT DeviceState::pfnUpdateWInfo(const D3DDDIARG_WINFO* data) { m_app.wInfo = *data; - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; return S_OK; } @@ -528,11 +524,10 @@ namespace D3dDdi void DeviceState::setRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget) { - if (setData(renderTarget, m_current.renderTarget, m_device.getOrigVtable().pfnSetRenderTarget)) - { - m_device.setRenderTarget(m_app.renderTarget); - LOG_DS << renderTarget; - } + m_device.flushPrimitives(); + m_device.getOrigVtable().pfnSetRenderTarget(m_device, &renderTarget); + m_current.renderTarget = renderTarget; + LOG_DS << renderTarget; } bool DeviceState::setShader(HANDLE shader, HANDLE& currentShader, @@ -600,6 +595,7 @@ namespace D3dDdi void DeviceState::setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget) { setRenderTarget(renderTarget); + m_device.setRenderTarget({}); m_changedStates |= CS_RENDER_TARGET; } @@ -644,6 +640,7 @@ namespace D3dDdi void DeviceState::setTempVertexShaderDecl(HANDLE decl) { + m_current.vertexShaderDecl = DELETED_RESOURCE; setVertexShaderDecl(decl); m_changedStates |= CS_SHADER; } @@ -651,19 +648,19 @@ namespace D3dDdi void DeviceState::setTempViewport(const D3DDDIARG_VIEWPORTINFO& viewport) { setViewport(viewport); - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; } void DeviceState::setTempWInfo(const D3DDDIARG_WINFO& wInfo) { setWInfo(wInfo); - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; } void DeviceState::setTempZRange(const D3DDDIARG_ZRANGE& zRange) { setZRange(zRange); - m_changedStates |= CS_MISC; + m_changedStates |= CS_RENDER_TARGET; } bool DeviceState::setTexture(UINT stage, HANDLE texture) @@ -762,26 +759,6 @@ namespace D3dDdi m_changedTextureStageStates[i].set(D3DDDITSS_MAXANISOTROPY); } m_maxChangedTextureStage = m_changedTextureStageStates.size() - 1; - updateVertexFixupConstants(); - } - - void DeviceState::updateMisc() - { - bool updateConstants = setViewport(m_app.viewport); - - auto wInfo = m_app.wInfo; - if (1.0f == wInfo.WNear && 1.0f == wInfo.WFar) - { - wInfo.WNear = 0.0f; - } - setWInfo(wInfo); - - updateConstants |= setZRange(m_app.zRange); - - if (updateConstants) - { - updateVertexFixupConstants(); - } } void DeviceState::updateRenderStates() @@ -794,23 +771,42 @@ namespace D3dDdi m_changedRenderStates.reset(); } - void DeviceState::updateRenderTargets() + void DeviceState::updateRenderTarget() { + auto vp = m_app.viewport; auto renderTarget = m_app.renderTarget; + auto depthStencil = m_app.depthStencil; + Resource* resource = m_device.getResource(renderTarget.hRenderTarget); if (resource && resource->getCustomResource()) { + resource->scaleRect(reinterpret_cast(vp)); renderTarget.hRenderTarget = *resource->getCustomResource(); + + resource = m_device.getResource(depthStencil.hZBuffer); + if (resource && resource->getCustomResource()) + { + depthStencil.hZBuffer = *resource->getCustomResource(); + } } - setRenderTarget(renderTarget); - auto depthStencil = m_app.depthStencil; - resource = m_device.getResource(depthStencil.hZBuffer); - if (resource && resource->getCustomResource()) - { - depthStencil.hZBuffer = *resource->getCustomResource(); - } + setRenderTarget(renderTarget); + m_current.vertexShaderFunc = DELETED_RESOURCE; + m_changedStates |= CS_SHADER; + m_device.setRenderTarget(m_app.renderTarget); setDepthStencil(depthStencil); + setViewport(vp); + + auto wInfo = m_app.wInfo; + if (1.0f == wInfo.WNear && 1.0f == wInfo.WFar) + { + wInfo.WNear = 0.0f; + } + setWInfo(wInfo); + + setZRange(m_app.zRange); + + updateVertexFixupConstants(); } void DeviceState::updateShaders() @@ -902,14 +898,19 @@ namespace D3dDdi data.Count = 2; const float apc = Config::alternatePixelCenter.get(); - const auto& vp = m_current.viewport; + const auto& vp = m_app.viewport; const auto& zr = m_current.zRange; + const float sx = static_cast(m_current.viewport.Width) / m_app.viewport.Width; + const float sy = static_cast(m_current.viewport.Height) / m_app.viewport.Height; ShaderConstF registers[2] = { - { apc - vp.X - vp.Width / 2, apc - vp.Y - vp.Height / 2, -zr.MinZ, 0.0f }, + { 0.5f + apc - 0.5f / sx - vp.X - vp.Width / 2, 0.5f + apc - 0.5f / sy - vp.Y - vp.Height / 2, -zr.MinZ, 0.0f }, { 2.0f / vp.Width, -2.0f / vp.Height, 1.0f / (zr.MaxZ - zr.MinZ), 1.0f } }; - m_device.getOrigVtable().pfnSetVertexShaderConst(m_device, &data, registers); + if (0 != memcmp(registers, &m_vertexShaderConst[data.Register], sizeof(registers))) + { + pfnSetVertexShaderConst(&data, registers); + } } } diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index aeb1ea8..c3fc2ca 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -98,6 +98,7 @@ namespace D3dDdi void setTempZRange(const D3DDDIARG_ZRANGE& zRange); void flush(); + HANDLE getVertexFixupDecl() const { return m_vsVertexFixup.get(); } void onDestroyResource(HANDLE resource); void updateConfig(); @@ -106,12 +107,11 @@ namespace D3dDdi enum ChangedState { - CS_MISC = 1 << 0, - CS_RENDER_STATE = 1 << 1, - CS_RENDER_TARGET = 1 << 2, - CS_SHADER = 1 << 3, - CS_STREAM_SOURCE = 1 << 4, - CS_TEXTURE_STAGE = 1 << 5 + CS_RENDER_STATE = 1 << 0, + CS_RENDER_TARGET = 1 << 1, + CS_SHADER = 1 << 2, + CS_STREAM_SOURCE = 1 << 3, + CS_TEXTURE_STAGE = 1 << 4 }; struct State @@ -170,9 +170,8 @@ namespace D3dDdi void setWInfo(const D3DDDIARG_WINFO& wInfo); bool setZRange(const D3DDDIARG_ZRANGE& zRange); - void updateMisc(); void updateRenderStates(); - void updateRenderTargets(); + void updateRenderTarget(); void updateShaders(); void updateStreamSource(); void updateTextureColorKey(UINT stage); diff --git a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp index 07431a8..680ad25 100644 --- a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp @@ -87,3 +87,13 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_GETCAPS& data) << data.pData << data.DataSize; } + +std::ostream& operator<<(std::ostream& os, const FORMATOP& data) +{ + return Compat::LogStruct(os) + << data.Format + << Compat::hex(data.Operations) + << Compat::hex(data.FlipMsTypes) + << Compat::hex(data.BltMsTypes) + << data.PrivateFormatBitCount; +} diff --git a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h index 3f39003..b1a9d0c 100644 --- a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h @@ -10,3 +10,4 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATEDEVICE& data); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_GETCAPS& data); std::ostream& operator<<(std::ostream& os, D3DDDICAPS_TYPE data); +std::ostream& operator<<(std::ostream& os, const FORMATOP& data); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 3e3df3a..9db57b1 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include namespace { @@ -25,16 +27,12 @@ namespace const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; RECT g_presentationRect = {}; - RECT g_primaryRect = {}; D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN; std::pair g_msaaOverride = {}; - RECT calculatePresentationRect() + RECT calculateScaledRect(const RECT& srcRect, const RECT& dstRect) { - const RECT srcRect = DDraw::PrimarySurface::getMonitorRect(); - const RECT dstRect = DDraw::RealPrimarySurface::getMonitorRect(); - const int srcWidth = srcRect.right - srcRect.left; const int srcHeight = srcRect.bottom - srcRect.top; const int dstWidth = dstRect.right - dstRect.left; @@ -54,6 +52,11 @@ namespace return rect; } + RECT calculatePresentationRect() + { + return calculateScaledRect(DDraw::PrimarySurface::getMonitorRect(), DDraw::RealPrimarySurface::getMonitorRect()); + } + LONG divCeil(LONG n, LONG d) { return (n + d - 1) / d; @@ -113,6 +116,7 @@ namespace D3dDdi , m_msaaResolvedSurface{} , m_formatConfig(D3DDDIFMT_UNKNOWN) , m_multiSampleConfig{ D3DDDIMULTISAMPLE_NONE, 0 } + , m_scaledSize{} , m_isSurfaceRepoResource(SurfaceRepository::inCreateSurface()) { if (m_origData.Flags.VertexBuffer && @@ -126,10 +130,10 @@ namespace D3dDdi { g_presentationRect = calculatePresentationRect(); auto& si = m_origData.pSurfList[0]; - g_primaryRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; + RECT primaryRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect()); - if (!EqualRect(&g_presentationRect, &g_primaryRect)) + if (!EqualRect(&g_presentationRect, &primaryRect)) { Gdi::Cursor::setEmulated(true); } @@ -139,6 +143,7 @@ namespace D3dDdi fixResourceData(); m_formatInfo = getFormatInfo(m_fixedData.Format); m_formatConfig = m_fixedData.Format; + m_scaledSize = { static_cast(m_fixedData.pSurfList[0].Width), static_cast(m_fixedData.pSurfList[0].Height) }; HRESULT result = m_device.createPrivateResource(m_fixedData); if (FAILED(result)) @@ -243,15 +248,17 @@ namespace D3dDdi { LOG_FUNC("Resource::bltLock", data); - loadSysMemResource(data.SubResourceIndex); + if (data.Flags.ReadOnly) + { + prepareForCpuRead(data.SubResourceIndex); + } + else + { + prepareForCpuWrite(data.SubResourceIndex); + } auto& lockData = m_lockData[data.SubResourceIndex]; lockData.qpcLastForcedLock = Time::queryPerformanceCounter(); - if (!data.Flags.ReadOnly) - { - clearUpToDateFlags(data.SubResourceIndex); - lockData.isSysMemUpToDate = true; - } unsigned char* ptr = static_cast(lockData.data); if (data.Flags.AreaValid) @@ -292,25 +299,7 @@ namespace D3dDdi if (m_lockResource) { auto& lockData = m_lockData[data.SubResourceIndex]; - - if (lockData.isVidMemUpToDate) - { - m_device.getOrigVtable().pfnColorFill(m_device, &data); - } - - if (lockData.isMsaaUpToDate) - { - data.hResource = *m_msaaSurface.resource; - m_device.getOrigVtable().pfnColorFill(m_device, &data); - } - - if (lockData.isMsaaResolvedUpToDate) - { - data.hResource = *m_msaaResolvedSurface.resource; - m_device.getOrigVtable().pfnColorFill(m_device, &data); - } - - if (lockData.isSysMemUpToDate) + if (lockData.isSysMemUpToDate && !lockData.isVidMemUpToDate) { auto dstBuf = static_cast(lockData.data) + data.DstRect.top * lockData.pitch + data.DstRect.left * m_formatInfo.bytesPerPixel; @@ -318,21 +307,25 @@ namespace D3dDdi DDraw::Blitter::colorFill(dstBuf, lockData.pitch, data.DstRect.right - data.DstRect.left, data.DstRect.bottom - data.DstRect.top, m_formatInfo.bytesPerPixel, colorConvert(m_formatInfo, data.Color)); - } - return LOG_RESULT(S_OK); + return LOG_RESULT(S_OK); + } } + prepareForBltDst(data.hResource, data.SubResourceIndex, data.DstRect); return LOG_RESULT(m_device.getOrigVtable().pfnColorFill(m_device, &data)); } + HRESULT Resource::copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex) + { + return copySubResourceRegion(dstResource, subResourceIndex, dstResource.getRect(subResourceIndex), + srcResource, subResourceIndex, srcResource.getRect(subResourceIndex)); + } + HRESULT Resource::copySubResource(HANDLE dstResource, HANDLE srcResource, UINT subResourceIndex) { - RECT rect = {}; - rect.right = m_fixedData.pSurfList[subResourceIndex].Width; - rect.bottom = m_fixedData.pSurfList[subResourceIndex].Height; - - return copySubResourceRegion(dstResource, subResourceIndex, rect, srcResource, subResourceIndex, rect); + return copySubResourceRegion(dstResource, subResourceIndex, getRect(subResourceIndex), + srcResource, subResourceIndex, getRect(subResourceIndex)); } HRESULT Resource::copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect, @@ -540,6 +533,24 @@ namespace D3dDdi return { D3DDDIMULTISAMPLE_NONE, 0 }; } + RECT Resource::getRect(UINT subResourceIndex) + { + const auto& si = m_fixedData.pSurfList[subResourceIndex]; + return { 0, 0, static_cast(si.Width), static_cast(si.Height) }; + } + + SIZE Resource::getScaledSize() + { + SIZE size = { static_cast(m_fixedData.pSurfList[0].Width), static_cast(m_fixedData.pSurfList[0].Height) }; + if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.Primary || + m_fixedData.Flags.ZBuffer) && + D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool) + { + return m_device.getAdapter().getScaledSize(size); + } + return size; + } + bool Resource::isOversized() const { return m_fixedData.SurfCount != m_origData.SurfCount; @@ -564,7 +575,7 @@ namespace D3dDdi else { loadVidMemResource(subResourceIndex); - copySubResource(*m_msaaSurface.resource, m_handle, subResourceIndex); + copySubResource(*m_msaaSurface.resource, *this, subResourceIndex); } m_lockData[subResourceIndex].isMsaaUpToDate = true; } @@ -581,7 +592,7 @@ namespace D3dDdi else { loadVidMemResource(subResourceIndex); - copySubResource(*m_msaaResolvedSurface.resource, m_handle, subResourceIndex); + copySubResource(*m_msaaResolvedSurface.resource, *this, subResourceIndex); } m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; } @@ -592,7 +603,7 @@ namespace D3dDdi if (!m_lockData[subResourceIndex].isSysMemUpToDate) { loadVidMemResource(subResourceIndex); - copySubResource(m_lockResource.get(), m_handle, subResourceIndex); + copySubResource(m_lockResource.get(), *this, subResourceIndex); notifyLock(subResourceIndex); m_lockData[subResourceIndex].isSysMemUpToDate = true; } @@ -607,16 +618,16 @@ namespace D3dDdi if (m_msaaResolvedSurface.resource) { loadMsaaResolvedResource(subResourceIndex); - copySubResource(m_handle, *m_msaaResolvedSurface.resource, subResourceIndex); + copySubResource(*this, *m_msaaResolvedSurface.resource, subResourceIndex); } else { - copySubResource(m_handle, *m_msaaSurface.resource, subResourceIndex); + copySubResource(*this, *m_msaaSurface.resource, subResourceIndex); } } else { - copySubResource(m_handle, m_lockResource.get(), subResourceIndex); + copySubResource(*this, m_lockResource.get(), subResourceIndex); notifyLock(subResourceIndex); } m_lockData[subResourceIndex].isVidMemUpToDate = true; @@ -686,28 +697,35 @@ namespace D3dDdi } Resource& Resource::prepareForBltDst(D3DDDIARG_BLT& data) + { + return prepareForBltDst(data.hDstResource, data.DstSubResourceIndex, data.DstRect); + } + + Resource& Resource::prepareForBltDst(HANDLE& resource, UINT& subResourceIndex, RECT& rect) { if (m_lockResource) { - if (m_lockData[data.DstSubResourceIndex].isMsaaUpToDate) + if (m_lockData[subResourceIndex].isMsaaUpToDate) { - data.hDstResource = *m_msaaSurface.resource; - clearUpToDateFlags(data.DstSubResourceIndex); - m_lockData[data.DstSubResourceIndex].isMsaaUpToDate = true; + resource = *m_msaaSurface.resource; + clearUpToDateFlags(subResourceIndex); + m_lockData[subResourceIndex].isMsaaUpToDate = true; + scaleRect(rect); return *m_msaaSurface.resource; } - else if (m_lockData[data.DstSubResourceIndex].isMsaaResolvedUpToDate) + else if (m_lockData[subResourceIndex].isMsaaResolvedUpToDate) { - data.hDstResource = *m_msaaResolvedSurface.resource; - clearUpToDateFlags(data.DstSubResourceIndex); - m_lockData[data.DstSubResourceIndex].isMsaaResolvedUpToDate = true; + resource = *m_msaaResolvedSurface.resource; + clearUpToDateFlags(subResourceIndex); + m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; + scaleRect(rect); return *m_msaaResolvedSurface.resource; } else { - loadVidMemResource(data.DstSubResourceIndex); - clearUpToDateFlags(data.DstSubResourceIndex); - m_lockData[data.DstSubResourceIndex].isVidMemUpToDate = true; + loadVidMemResource(subResourceIndex); + clearUpToDateFlags(subResourceIndex); + m_lockData[subResourceIndex].isVidMemUpToDate = true; } } return *this; @@ -782,7 +800,9 @@ namespace D3dDdi { srcResource->m_lockData[0].isVidMemUpToDate = false; } - data.hSrcResource = srcResource->prepareForGpuRead(0); + + srcResource = &srcResource->prepareForGpuRead(0); + data.hSrcResource = *srcResource; } const bool isPalettized = D3DDDIFMT_P8 == srcResource->m_origData.Format; @@ -793,14 +813,18 @@ namespace D3dDdi const RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); const bool isLayeredPresentNeeded = Gdi::Window::presentLayered(nullptr, monitorRect); + const LONG srcWidth = srcResource->m_fixedData.pSurfList[0].Width; + const LONG srcHeight = srcResource->m_fixedData.pSurfList[0].Height; + data.SrcRect = { 0, 0, srcWidth, srcHeight }; + UINT presentationFilter = Config::displayFilter.get(); UINT presentationFilterParam = Config::displayFilter.getParam(); if (Config::Settings::DisplayFilter::BILINEAR == presentationFilter && - (g_presentationRect.right - g_presentationRect.left == g_primaryRect.right && - g_presentationRect.bottom - g_presentationRect.top == g_primaryRect.bottom) || + (g_presentationRect.right - g_presentationRect.left == srcWidth && + g_presentationRect.bottom - g_presentationRect.top == srcHeight) || (0 == presentationFilterParam && - 0 == (g_presentationRect.right - g_presentationRect.left) % g_primaryRect.right && - 0 == (g_presentationRect.bottom - g_presentationRect.top) % g_primaryRect.bottom)) + 0 == (g_presentationRect.right - g_presentationRect.left) % srcWidth && + 0 == (g_presentationRect.bottom - g_presentationRect.top) % srcHeight)) { presentationFilter = Config::Settings::DisplayFilter::POINT; } @@ -808,8 +832,7 @@ namespace D3dDdi if (isPalettized || isCursorEmulated || isLayeredPresentNeeded || Config::Settings::DisplayFilter::POINT != presentationFilter) { - const auto& si = srcResource->m_fixedData.pSurfList[0]; - const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getTempRenderTarget(si.Width, si.Height)); + const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getTempRenderTarget(srcWidth, srcHeight)); if (!dst.resource) { return E_OUTOFMEMORY; @@ -859,6 +882,17 @@ namespace D3dDdi return m_device.getOrigVtable().pfnBlt(m_device, &data); } + void Resource::scaleRect(RECT& rect) + { + const LONG origWidth = m_fixedData.pSurfList[0].Width; + const LONG origHeight = m_fixedData.pSurfList[0].Height; + + rect.left = rect.left * m_scaledSize.cx / origWidth; + rect.top = rect.top * m_scaledSize.cy / origHeight; + rect.right = rect.right * m_scaledSize.cx / origWidth; + rect.bottom = rect.bottom * m_scaledSize.cy / origHeight; + } + void Resource::setAsGdiResource(bool isGdiResource) { m_lockResource.reset(); @@ -1097,7 +1131,8 @@ namespace D3dDdi } } - if (m_fixedData.Flags.RenderTarget || data.Flags.SrcColorKey || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown) + if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && + (m_fixedData.Flags.RenderTarget || data.Flags.SrcColorKey || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown)) { if (SUCCEEDED(shaderBlt(data, srcResource))) { @@ -1163,12 +1198,14 @@ namespace D3dDdi const auto msaa = getMultisampleConfig(); const auto formatConfig = getFormatConfig(); - if (m_multiSampleConfig == msaa && m_formatConfig == formatConfig) + const auto scaledSize = getScaledSize(); + if (m_multiSampleConfig == msaa && m_formatConfig == formatConfig && m_scaledSize == scaledSize) { return; } m_multiSampleConfig = msaa; m_formatConfig = formatConfig; + m_scaledSize = scaledSize; if (m_fixedData.Flags.RenderTarget && (m_msaaSurface.resource || m_msaaResolvedSurface.resource)) @@ -1187,9 +1224,10 @@ namespace D3dDdi m_msaaSurface = {}; m_msaaResolvedSurface = {}; - if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig) + if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig || + static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || + static_cast(m_fixedData.pSurfList[0].Height) != m_scaledSize.cy) { - g_formatOverride = formatConfig; if (m_fixedData.Flags.ZBuffer) { DDPIXELFORMAT pf = {}; @@ -1198,10 +1236,12 @@ namespace D3dDdi pf.dwZBufferBitDepth = 16; pf.dwZBitMask = 0xFFFF; + g_formatOverride = formatConfig; g_msaaOverride = msaa; SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaSurface, - m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height, pf, + scaledSize.cx, scaledSize.cy, pf, DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); + g_formatOverride = D3DDDIFMT_UNKNOWN; g_msaaOverride = {}; } else @@ -1210,18 +1250,15 @@ namespace D3dDdi { g_msaaOverride = msaa; SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaSurface, - m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height, - DDraw::DirectDraw::getRgbPixelFormat(32), - DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY); + scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), + DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); g_msaaOverride = {}; } SurfaceRepository::get(m_device.getAdapter()).getSurface(m_msaaResolvedSurface, - m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height, - DDraw::DirectDraw::getRgbPixelFormat(32), - DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY); + scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), + DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); } - g_formatOverride = D3DDDIFMT_UNKNOWN; } } } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index cc5d18a..249fbcd 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -37,10 +37,12 @@ namespace D3dDdi void onDestroyResource(HANDLE resource); Resource& prepareForBltSrc(const D3DDDIARG_BLT& data); Resource& prepareForBltDst(D3DDDIARG_BLT& data); + Resource& prepareForBltDst(HANDLE& resource, UINT& subResourceIndex, RECT& rect); void prepareForCpuRead(UINT subResourceIndex); void prepareForCpuWrite(UINT subResourceIndex); Resource& prepareForGpuRead(UINT subResourceIndex); void prepareForGpuWrite(UINT subResourceIndex); + void scaleRect(RECT& rect); void setAsGdiResource(bool isGdiResource); HRESULT unlock(const D3DDDIARG_UNLOCK& data); void updateConfig(); @@ -74,6 +76,7 @@ namespace D3dDdi HRESULT bltLock(D3DDDIARG_LOCK& data); void clearUpToDateFlags(UINT subResourceIndex); void clipRect(UINT subResourceIndex, RECT& rect); + HRESULT copySubResource(Resource& dstResource, Resource& srcResource, UINT subResourceIndex); HRESULT copySubResource(HANDLE dstResource, HANDLE srcResource, UINT subResourceIndex); HRESULT copySubResourceRegion(HANDLE dst, UINT dstIndex, const RECT& dstRect, HANDLE src, UINT srcIndex, const RECT& srcRect); @@ -83,6 +86,8 @@ namespace D3dDdi void fixResourceData(); D3DDDIFORMAT getFormatConfig(); std::pair getMultisampleConfig(); + RECT getRect(UINT subResourceIndex); + SIZE getScaledSize(); bool isOversized() const; bool isValidRect(UINT subResourceIndex, const RECT& rect); void loadMsaaResource(UINT subResourceIndex); @@ -112,6 +117,7 @@ namespace D3dDdi SurfaceRepository::Surface m_msaaResolvedSurface; D3DDDIFORMAT m_formatConfig; std::pair m_multiSampleConfig; + SIZE m_scaledSize; bool m_isSurfaceRepoResource; }; } diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 16058f5..56a0b6a 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -38,6 +38,7 @@ namespace D3dDdi } const auto& srcSurface = srcResource.getFixedDesc().pSurfList[srcSubResourceIndex]; + const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex]; auto& state = m_device.getState(); state.setTempRenderState({ D3DDDIRS_SCENECAPTURE, TRUE }); @@ -45,8 +46,7 @@ namespace D3dDdi state.setTempPixelShader(pixelShader); state.setTempRenderTarget({ 0, dstResource, dstSubResourceIndex }); state.setTempDepthStencil({ nullptr }); - state.setTempViewport({ static_cast(dstRect.left), static_cast(dstRect.top), - static_cast(dstRect.right - dstRect.left), static_cast(dstRect.bottom - dstRect.top) }); + state.setTempViewport({ 0, 0, dstSurface.Width, dstSurface.Height }); state.setTempZRange({ 0, 1 }); state.setTempRenderState({ D3DDDIRS_ZENABLE, D3DZB_FALSE }); diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 9fa6a40..49562ea 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -241,7 +241,7 @@ namespace D3dDdi const SurfaceRepository::Surface& SurfaceRepository::getTempRenderTarget(DWORD width, DWORD height) { - return getTempSurface(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32), + return getTempSurface(m_renderTarget, width, height, getPixelFormat(D3DDDIFMT_A8R8G8B8), DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY); } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 3cf666a..f3f8205 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -92,6 +92,7 @@ namespace DDraw } data->restore(); + D3dDdi::Device::updateAllConfig(); return DD_OK; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index b0ebd19..ebd394b 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -221,6 +221,7 @@ + @@ -340,6 +341,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 6f5a6b4..64e6d06 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -507,6 +507,9 @@ Header Files\DDraw + + Header Files\Config\Settings + @@ -797,6 +800,9 @@ Source Files\D3dDdi\Log + + Source Files\Config\Settings + diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 9ea36fe..7a0041d 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -54,17 +54,6 @@ namespace switch (uMsg) { - case WM_ACTIVATEAPP: - if (!wParam) - { - auto configWindow = Gdi::PresentationWindow::getConfigWindow(); - if (configWindow) - { - configWindow->setVisible(false); - } - } - break; - case WM_DISPLAYCHANGE: { if (0 != wParam) @@ -100,6 +89,18 @@ namespace switch (uMsg) { + case WM_ACTIVATEAPP: + if (!wParam) + { + auto configWindow = Gdi::PresentationWindow::getConfigWindow(); + if (configWindow) + { + configWindow->setVisible(false); + } + CALL_ORIG_FUNC(ClipCursor)(nullptr); + } + break; + case WM_CTLCOLORSCROLLBAR: if (reinterpret_cast(lParam) != hwnd && isUser32ScrollBar(reinterpret_cast(lParam))) diff --git a/DDrawCompat/Overlay/ConfigWindow.cpp b/DDrawCompat/Overlay/ConfigWindow.cpp index 9ce3346..5496b37 100644 --- a/DDrawCompat/Overlay/ConfigWindow.cpp +++ b/DDrawCompat/Overlay/ConfigWindow.cpp @@ -12,6 +12,7 @@ namespace Overlay addControl(Config::antialiasing); addControl(Config::displayFilter); addControl(Config::renderColorDepth); + addControl(Config::resolutionScale); addControl(Config::textureFilter); } diff --git a/DDrawCompat/Overlay/SettingControl.cpp b/DDrawCompat/Overlay/SettingControl.cpp index e956974..d60eb7a 100644 --- a/DDrawCompat/Overlay/SettingControl.cpp +++ b/DDrawCompat/Overlay/SettingControl.cpp @@ -6,6 +6,24 @@ #include #include +namespace +{ + std::vector getValueStrings(Config::Setting& setting) + { + auto values(setting.getDefaultValueStrings()); + const auto currentValue = setting.getValueStr(); + for (const auto& value : values) + { + if (Config::Parser::removeParam(value) == Config::Parser::removeParam(currentValue)) + { + return values; + } + } + values.push_back(currentValue); + return values; + } +} + namespace Overlay { SettingControl::SettingControl(Control& parent, const RECT& rect, Config::Setting& setting) @@ -17,7 +35,7 @@ namespace Overlay rect.left + SETTING_LABEL_WIDTH + SETTING_CONTROL_WIDTH, rect.bottom - BORDER / 2 }; m_valueControl.reset(new ComboBoxControl(*this, r)); getValueComboBox().setValue(setting.getValueStr()); - getValueComboBox().setValues(setting.getDefaultValueStrings()); + getValueComboBox().setValues(getValueStrings(setting)); onValueChanged(); updateValuesParam(); } @@ -40,6 +58,7 @@ namespace Overlay if (&Config::antialiasing == &m_setting || &Config::renderColorDepth == &m_setting || + &Config::resolutionScale == &m_setting || &Config::textureFilter == &m_setting) { D3dDdi::Device::updateAllConfig(); diff --git a/DDrawCompat/Overlay/SettingControl.h b/DDrawCompat/Overlay/SettingControl.h index 224d1de..2765fba 100644 --- a/DDrawCompat/Overlay/SettingControl.h +++ b/DDrawCompat/Overlay/SettingControl.h @@ -18,7 +18,7 @@ namespace Overlay class SettingControl : public Control { public: - static const int PARAM_LABEL_WIDTH = 50; + static const int PARAM_LABEL_WIDTH = 70; static const int PARAM_CONTROL_WIDTH = 151; static const int SETTING_LABEL_WIDTH = 120; static const int SETTING_CONTROL_WIDTH = 151; diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index cfca5d9..4ee377c 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -205,10 +205,10 @@ namespace g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName); g_emulatedDisplayMode.rect = getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor; - g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + lpDevMode->dmPelsWidth; - g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + lpDevMode->dmPelsHeight; - g_emulatedDisplayMode.diff.cx = lpDevMode->dmPelsWidth - currDevMode.dmPelsWidth; - g_emulatedDisplayMode.diff.cy = lpDevMode->dmPelsHeight - currDevMode.dmPelsHeight; + g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + emulatedResolution.cx; + g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + emulatedResolution.cy; + g_emulatedDisplayMode.diff.cx = emulatedResolution.cx - currDevMode.dmPelsWidth; + g_emulatedDisplayMode.diff.cy = emulatedResolution.cy - currDevMode.dmPelsHeight; } else {