diff --git a/DDrawCompat/Common/Hook.cpp b/DDrawCompat/Common/Hook.cpp index a8eef0f..2c3492a 100644 --- a/DDrawCompat/Common/Hook.cpp +++ b/DDrawCompat/Common/Hook.cpp @@ -105,28 +105,6 @@ namespace return ntHeaders; } - unsigned getInstructionSize(void* instruction) - { - const unsigned MAX_INSTRUCTION_SIZE = 15; - HRESULT result = g_debugDataSpaces->WriteVirtual(g_debugBase, instruction, MAX_INSTRUCTION_SIZE, nullptr); - if (FAILED(result)) - { - LOG_ONCE("ERROR: DbgEng: WriteVirtual failed: " << Compat::hex(result)); - return 0; - } - - ULONG64 endOffset = 0; - result = g_debugControl->Disassemble(g_debugBase, 0, nullptr, 0, nullptr, &endOffset); - if (FAILED(result)) - { - LOG_ONCE("ERROR: DbgEng: Disassemble failed: " << Compat::hex(result) << " " - << Compat::hexDump(instruction, MAX_INSTRUCTION_SIZE)); - return 0; - } - - return static_cast(endOffset - g_debugBase); - } - void hookFunction(void*& origFuncPtr, void* newFuncPtr, const char* funcName) { BYTE* targetFunc = static_cast(origFuncPtr); @@ -193,7 +171,7 @@ namespace BYTE* dst = trampoline; while (src - targetFunc < 5) { - unsigned instructionSize = getInstructionSize(src); + unsigned instructionSize = Compat::getInstructionSize(src); if (0 == instructionSize) { return; @@ -223,13 +201,12 @@ namespace memset(targetFunc + 5, 0xCC, src - targetFunc - 5); VirtualProtect(targetFunc, src - targetFunc, PAGE_EXECUTE_READ, &oldProtect); - FlushInstructionCache(GetCurrentProcess(), nullptr, 0); + origFuncPtr = trampoline; + CALL_ORIG_FUNC(FlushInstructionCache)(GetCurrentProcess(), nullptr, 0); HMODULE module = nullptr; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, reinterpret_cast(targetFunc), &module); - - origFuncPtr = trampoline; } bool initDbgEng() @@ -339,7 +316,7 @@ namespace Compat g_isDbgEngInitialized = false; } - std::string funcPtrToStr(void* funcPtr) + std::string funcPtrToStr(const void* funcPtr) { std::ostringstream oss; HMODULE module = Compat::getModuleHandleFromAddress(funcPtr); @@ -355,11 +332,63 @@ namespace Compat return oss.str(); } - HMODULE getModuleHandleFromAddress(void* address) + unsigned getInstructionSize(void* instruction) + { + const unsigned MAX_INSTRUCTION_SIZE = 15; + HRESULT result = g_debugDataSpaces->WriteVirtual(g_debugBase, instruction, MAX_INSTRUCTION_SIZE, nullptr); + if (FAILED(result)) + { + LOG_ONCE("ERROR: DbgEng: WriteVirtual failed: " << Compat::hex(result)); + return 0; + } + + ULONG64 endOffset = 0; + result = g_debugControl->Disassemble(g_debugBase, 0, nullptr, 0, nullptr, &endOffset); + if (FAILED(result)) + { + LOG_ONCE("ERROR: DbgEng: Disassemble failed: " << Compat::hex(result) << " " + << Compat::hexDump(instruction, MAX_INSTRUCTION_SIZE)); + return 0; + } + + return static_cast(endOffset - g_debugBase); + } + + DWORD getModuleFileOffset(const void* address) + { + LOG_FUNC("getModuleFileOffset", address); + HMODULE mod = getModuleHandleFromAddress(address); + if (!mod) + { + return LOG_RESULT(0); + } + + PIMAGE_NT_HEADERS ntHeaders = getImageNtHeaders(mod); + if (!ntHeaders) + { + return LOG_RESULT(0); + } + + DWORD offset = static_cast(address) - reinterpret_cast(mod); + auto sectionHeader = reinterpret_cast( + &ntHeaders->OptionalHeader.DataDirectory[ntHeaders->OptionalHeader.NumberOfRvaAndSizes]); + for (unsigned i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) + { + if (offset >= sectionHeader->VirtualAddress && + offset < sectionHeader->VirtualAddress + sectionHeader->SizeOfRawData) + { + return LOG_RESULT(sectionHeader->PointerToRawData + offset - sectionHeader->VirtualAddress); + } + sectionHeader++; + } + return LOG_RESULT(0); + } + + HMODULE getModuleHandleFromAddress(const void* address) { HMODULE module = nullptr; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - static_cast(address), &module); + static_cast(address), &module); return module; } diff --git a/DDrawCompat/Common/Hook.h b/DDrawCompat/Common/Hook.h index fd324d6..897afd3 100644 --- a/DDrawCompat/Common/Hook.h +++ b/DDrawCompat/Common/Hook.h @@ -14,8 +14,10 @@ namespace Compat { void closeDbgEng(); - std::string funcPtrToStr(void* funcPtr); - HMODULE getModuleHandleFromAddress(void* address); + std::string funcPtrToStr(const void* funcPtr); + unsigned getInstructionSize(void* instruction); + DWORD getModuleFileOffset(const void* address); + HMODULE getModuleHandleFromAddress(const void* address); template decltype(origFunc) g_origFuncPtr = origFunc; diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index b5d8f27..cdd820b 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -58,6 +58,8 @@ namespace D3dDdi , m_origVtable(CompatVtable::s_origVtable) , m_runtimeVersion(data.Version) , m_driverVersion(data.DriverVersion) + , m_guid(nullptr) + , m_guidBuf{} , m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid) , m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().deviceName) , m_repository{} @@ -496,19 +498,20 @@ namespace D3dDdi return result; } - void Adapter::setRepository(LUID luid, CompatWeakPtr repository, bool isPrimary) + void Adapter::setRepository(LUID luid, GUID* guid, CompatWeakPtr repository) { for (auto& adapter : s_adapters) { if (adapter.second.m_luid == luid) { + if (guid) + { + adapter.second.m_guidBuf = *guid; + adapter.second.m_guid = &adapter.second.m_guidBuf; + } adapter.second.m_repository = repository; auto& surfaceRepo = SurfaceRepository::get(adapter.second); surfaceRepo.setRepository(repository); - if (isPrimary) - { - surfaceRepo.setAsPrimaryRepo(); - } } } } diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index a5d2cb6..df88c15 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -36,6 +36,7 @@ namespace D3dDdi operator HANDLE() const { return m_adapter; } SIZE getAspectRatio() const; + GUID* getGuid() const { return m_guid; } const AdapterInfo& getInfo() const { return m_info; } LUID getLuid() const { return m_luid; } const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } @@ -53,7 +54,7 @@ namespace D3dDdi static void add(const D3DDDIARG_OPENADAPTER& data) { s_adapters.emplace(data.hAdapter, data); } static Adapter& get(HANDLE adapter) { return s_adapters.find(adapter)->second; } - static void setRepository(LUID luid, CompatWeakPtr repository, bool isPrimary); + static void setRepository(LUID luid, GUID* guid, CompatWeakPtr repository); private: const AdapterInfo& findInfo() const; @@ -74,6 +75,8 @@ namespace D3dDdi D3DDDI_ADAPTERFUNCS m_origVtable; UINT m_runtimeVersion; UINT m_driverVersion; + GUID* m_guid; + GUID m_guidBuf; LUID m_luid; std::wstring m_deviceName; CompatWeakPtr m_repository; diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 9f16e0c..3ffffbe 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": " @@ -1117,7 +1118,19 @@ namespace D3dDdi auto depthStencil = m_app.depthStencil; bool isTransformed = getVertexDecl().isTransformed; - Resource* resource = m_device.getResource(renderTarget.hRenderTarget); + Resource* resource = nullptr; + auto steamResources = Overlay::Steam::getResources(); + if (steamResources.bbResource && *steamResources.rtResource == renderTarget.hRenderTarget) + { + resource = steamResources.bbResource; + renderTarget.hRenderTarget = *steamResources.bbResource; + renderTarget.SubResourceIndex = steamResources.bbSubResourceIndex; + } + else + { + resource = m_device.getResource(renderTarget.hRenderTarget); + } + if (resource) { auto customResource = resource->getCustomResource(); @@ -1129,11 +1142,11 @@ namespace D3dDdi if (isTransformed) { scissorRect = makeRect(scaledVp); - auto& si = resource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; + auto& si = resource->getFixedDesc().pSurfList[renderTarget.SubResourceIndex]; vp = { 0, 0, si.Width, si.Height }; if (customResource) { - auto& scaledSi = customResource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; + auto& scaledSi = customResource->getFixedDesc().pSurfList[renderTarget.SubResourceIndex]; scaledVp = { 0, 0, scaledSi.Width, scaledSi.Height }; } else diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index 31568ae..2c2b21f 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -273,6 +273,27 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETVERTEXSHADERCONST& << val.Count; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXBLT& val) +{ + return Compat::LogStruct(os) + << val.hDstResource + << val.hSrcResource + << val.CubeMapFace + << val.DstPoint + << val.SrcRect; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXBLT1& val) +{ + return Compat::LogStruct(os) + << val.hDstResource + << val.hSrcResource + << val.CubeMapFace + << val.DstPoint + << val.SrcRect + << Compat::hex(val.CopyFlags); +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXTURESTAGESTATE& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index bb94a7f..fad5a07 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -34,6 +34,8 @@ 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_SETVERTEXSHADERCONST& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXBLT& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXBLT1& 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_UPDATEPALETTE& val); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index a43224b..8f975af 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace { @@ -244,7 +245,14 @@ namespace D3dDdi return S_OK; } - if (shouldBltViaCpu(data, *srcResource)) + auto steamResources = Overlay::Steam::getResources(); + if (steamResources.rtResource == srcResource && steamResources.bbResource) + { + srcResource = steamResources.bbResource; + data.hSrcResource = *steamResources.bbResource; + data.SrcSubResourceIndex = steamResources.bbSubResourceIndex; + } + else if (shouldBltViaCpu(data, *srcResource)) { return bltViaCpu(data, *srcResource); } @@ -1014,7 +1022,7 @@ namespace D3dDdi HRESULT Resource::lock(D3DDDIARG_LOCK& data) { - if (D3DDDIMULTISAMPLE_NONE != m_fixedData.MultisampleType) + if (D3DDDIMULTISAMPLE_NONE != m_fixedData.MultisampleType || FOURCC_NULL == m_fixedData.Format) { return E_FAIL; } @@ -1325,6 +1333,8 @@ namespace D3dDdi presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor); + Overlay::Steam::render(*this, data.DstSubResourceIndex); + return LOG_RESULT(S_OK); } diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 3212025..1f06eea 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -431,9 +431,13 @@ namespace D3dDdi } } - void SurfaceRepository::setAsPrimaryRepo() + void SurfaceRepository::setRepository(CompatWeakPtr dd) { - g_primaryRepository = this; + m_dd = dd; + if (!g_primaryRepository) + { + g_primaryRepository = this; + } } bool SurfaceRepository::s_inCreateSurface = false; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index 7779143..4946cda 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -57,8 +57,7 @@ namespace D3dDdi CompatWeakPtr getWindowedPrimary(); CompatPtr getWindowedSrc(RECT rect); void release(Surface& surface); - void setAsPrimaryRepo(); - void setRepository(CompatWeakPtr dd) { m_dd = dd; } + void setRepository(CompatWeakPtr dd); static SurfaceRepository& get(const Adapter& adapter); static SurfaceRepository& getPrimaryRepo(); diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 0b3dd88..9464a3d 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -343,7 +343,7 @@ namespace DDraw } repo.get()->lpVtbl->SetCooperativeLevel(repo, nullptr, DDSCL_NORMAL); it = repositories.insert({ adapterInfo.luid, repo }).first; - D3dDdi::Adapter::setRepository(adapterInfo.luid, it->second, !guid); + D3dDdi::Adapter::setRepository(adapterInfo.luid, guid, it->second); repo.detach(); } } diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 9556ce1..0acac1e 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -12,18 +13,26 @@ namespace DDraw { namespace DirectDraw { + template + struct IsDirectDraw : std::false_type {}; + + template <> struct IsDirectDraw : std::true_type {}; + template <> struct IsDirectDraw : std::true_type {}; + template <> struct IsDirectDraw : std::true_type {}; + template <> struct IsDirectDraw : std::true_type {}; + DDPIXELFORMAT getRgbPixelFormat(DWORD bpp); void hookDDrawWindowProc(WNDPROC ddrawWndProc); void onCreate(GUID* guid, CompatRef dd); void suppressEmulatedDirectDraw(GUID*& guid); - template + template ::value>> DDRAWI_DIRECTDRAW_INT& getInt(TDirectDraw& dd) { return reinterpret_cast(dd); } - template + template ::value>> HWND* getDeviceWindowPtr(TDirectDraw& dd) { return &reinterpret_cast(getInt(dd).lpLcl->hWnd); diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index 360ba0d..58301ad 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #define SET_COMPAT_METHOD(method) \ vtable.method = &callImpl::method), &DDraw::SurfaceImpl::method, \ @@ -92,6 +94,12 @@ namespace DDraw return context.surfaces; } + D3dDdi::SurfaceRepository* getSurfaceRepository(HANDLE resource) + { + auto device = D3dDdi::Device::findDeviceByResource(resource); + return device ? &device->getRepo() : nullptr; + } + template void hookVtable(const Vtable& vtable) { diff --git a/DDrawCompat/DDraw/DirectDrawSurface.h b/DDrawCompat/DDraw/DirectDrawSurface.h index 4792994..b6bc4d4 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.h +++ b/DDrawCompat/DDraw/DirectDrawSurface.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -8,36 +9,58 @@ #include #include +namespace D3dDdi +{ + class SurfaceRepository; +} + namespace DDraw { namespace DirectDrawSurface { + template + struct IsSurface : std::false_type {}; + + template <> struct IsSurface : std::true_type {}; + template <> struct IsSurface : std::true_type {}; + template <> struct IsSurface : std::true_type {}; + template <> struct IsSurface : std::true_type {}; + template <> struct IsSurface : std::true_type {}; + std::vector> getAllAttachedSurfaces(CompatRef surface); - template + template ::value>> DDRAWI_DDRAWSURFACE_INT& getInt(TSurface& surface) { return reinterpret_cast(surface); } - template + template ::value>> HANDLE getRuntimeResourceHandle(TSurface& surface) { return reinterpret_cast(getInt(surface).lpLcl->hDDSurface); } - template - HANDLE getDriverResourceHandle(TSurface& surface) + template ::value>> + HANDLE& getDriverResourceHandle(TSurface& surface) { return reinterpret_cast(getRuntimeResourceHandle(surface))[0]; } - template - UINT getSubResourceIndex(TSurface& surface) + template ::value>> + UINT& getSubResourceIndex(TSurface& surface) { return reinterpret_cast(getRuntimeResourceHandle(surface))[1]; } + D3dDdi::SurfaceRepository* getSurfaceRepository(HANDLE resource); + + template ::value>> + D3dDdi::SurfaceRepository* getSurfaceRepository(TSurface& surface) + { + return getSurfaceRepository(getDriverResourceHandle(surface)); + } + template void hookVtable(const Vtable& vtable); } diff --git a/DDrawCompat/DDraw/Hooks.cpp b/DDrawCompat/DDraw/Hooks.cpp index d526517..c2a3d9b 100644 --- a/DDrawCompat/DDraw/Hooks.cpp +++ b/DDrawCompat/DDraw/Hooks.cpp @@ -97,9 +97,6 @@ namespace DDraw { void installHooks(CompatPtr dd7) { - DDraw::DirectDraw::onCreate(nullptr, *dd7); - RealPrimarySurface::init(); - g_origInitialize = dd7.get()->lpVtbl->Initialize; Compat::hookFunction(reinterpret_cast(g_origInitialize), initialize, "IDirectDrawVtbl::Initialize"); @@ -107,5 +104,8 @@ namespace DDraw hookDirectDrawClipper(*dd7); hookDirectDrawPalette(*dd7); hookDirectDrawSurface(*dd7); + + DDraw::DirectDraw::onCreate(nullptr, *dd7); + DDraw::RealPrimarySurface::init(); } } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index dda2535..32cfe35 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -276,18 +277,7 @@ namespace D3dDdi::SurfaceRepository* repo = nullptr; if (src) { - auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*frontBuffer); - if (!resource) - { - return; - } - - auto device = D3dDdi::Device::findDeviceByResource(resource); - if (!device) - { - return; - } - repo = &device->getRepo(); + repo = DDraw::DirectDrawSurface::getSurfaceRepository(*frontBuffer); } else { @@ -364,7 +354,7 @@ namespace } Gdi::Cursor::setMonitorClipRect(clipRect); - Gdi::Cursor::setEmulated(true); + Gdi::Cursor::setEmulated(!Overlay::Steam::isOverlayOpen()); } } @@ -568,6 +558,7 @@ namespace DDraw static UINT lastOverlayCheckVsyncCount = 0; if (vsyncCount != lastOverlayCheckVsyncCount) { + updatePresentationParams(); setPresentationWindowTopmost(); Gdi::Cursor::update(); Gdi::Caret::blink(); @@ -577,11 +568,10 @@ namespace DDraw statsWindow->updateStats(); g_qpcLastUpdate = Time::queryPerformanceCounter(); } + Overlay::Steam::flush(); lastOverlayCheckVsyncCount = vsyncCount; } - updatePresentationParams(); - bool isOverlayOnly = false; { diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index ac1e00b..5ccf80c 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -325,6 +325,7 @@ + @@ -459,6 +460,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 6da85da..2d572ca 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -708,6 +708,9 @@ Header Files\Win32 + + Header Files\Overlay + @@ -1106,6 +1109,9 @@ Source Files\Win32 + + Source Files\Overlay + diff --git a/DDrawCompat/Dll/Dll.cpp b/DDrawCompat/Dll/Dll.cpp index 6d1c3c9..ae79270 100644 --- a/DDrawCompat/Dll/Dll.cpp +++ b/DDrawCompat/Dll/Dll.cpp @@ -10,6 +10,7 @@ namespace Dll HMODULE g_origDciman32Module = nullptr; Procs g_origProcs = {}; Procs g_jmpTargetProcs = {}; + Procs g_newProcs = {}; bool g_isHooked = false; HANDLE createThread(unsigned(__stdcall* threadProc)(void*), unsigned int* threadId, int priority, unsigned initFlags) diff --git a/DDrawCompat/Dll/Dll.h b/DDrawCompat/Dll/Dll.h index 721bacf..21649ab 100644 --- a/DDrawCompat/Dll/Dll.h +++ b/DDrawCompat/Dll/Dll.h @@ -80,6 +80,7 @@ namespace Dll extern HMODULE g_origDciman32Module; extern Procs g_origProcs; extern Procs g_jmpTargetProcs; + extern Procs g_newProcs; extern bool g_isHooked; } diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index b55c7c4..8b82041 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -82,7 +83,9 @@ namespace { if (!Dll::g_isHooked) { + Dll::g_isHooked = true; DDraw::SuppressResourceFormatLogs suppressResourceFormatLogs; + Overlay::Steam::installHooks(); LOG_INFO << "Installing display mode hooks"; Win32::DisplayMode::installHooks(); LOG_INFO << "Installing registry hooks"; @@ -129,7 +132,6 @@ namespace Gdi::installHooks(); Compat::closeDbgEng(); LOG_INFO << "Finished installing hooks"; - Dll::g_isHooked = true; } } @@ -244,6 +246,8 @@ namespace Dll::g_origProcs.proc = Compat::getProcAddress(origModule, #proc); #define HOOK_DDRAW_PROC(proc) \ + Dll::g_newProcs.proc = reinterpret_cast( \ + static_cast(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>)); \ Compat::hookFunction( \ reinterpret_cast(Dll::g_origProcs.proc), \ static_cast(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>), \ @@ -302,7 +306,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return FALSE; } - Dll::g_origDDrawModule = LoadLibraryW((systemPath / "ddraw.dll").c_str()); + auto origDDrawModulePath = systemPath / "ddraw.dll"; + Dll::g_origDDrawModule = LoadLibraryW(origDDrawModulePath.c_str()); if (!Dll::g_origDDrawModule) { LOG_INFO << "ERROR: Failed to load system ddraw.dll from " << systemPath.u8string(); @@ -323,6 +328,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } Dll::g_jmpTargetProcs = Dll::g_origProcs; + Overlay::Steam::init(origDDrawModulePath.c_str()); VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC); Compat::hookFunction(reinterpret_cast(Dll::g_origProcs.SetAppCompatData), diff --git a/DDrawCompat/Gdi/GuiThread.cpp b/DDrawCompat/Gdi/GuiThread.cpp index bd422da..eae3d1a 100644 --- a/DDrawCompat/Gdi/GuiThread.cpp +++ b/DDrawCompat/Gdi/GuiThread.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -178,16 +179,13 @@ namespace LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - LOG_FUNC("messageWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam)); - if (WM_USER_EXECUTE == uMsg) { auto& func = *reinterpret_cast*>(lParam); func(); - return LOG_RESULT(0); + return 0; } - - return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam)); + return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam); } unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/) @@ -230,7 +228,6 @@ namespace MSG msg = {}; while (CALL_ORIG_FUNC(GetMessageA)(&msg, nullptr, 0, 0)) { - TranslateMessage(&msg); DispatchMessage(&msg); } @@ -276,6 +273,7 @@ namespace Gdi void destroyWindow(HWND hwnd) { + Overlay::Steam::onDestroyWindow(hwnd); PostMessage(hwnd, WM_CLOSE, 0, 0); } diff --git a/DDrawCompat/Gdi/PresentationWindow.cpp b/DDrawCompat/Gdi/PresentationWindow.cpp index 3ce95b1..d4a7252 100644 --- a/DDrawCompat/Gdi/PresentationWindow.cpp +++ b/DDrawCompat/Gdi/PresentationWindow.cpp @@ -12,7 +12,7 @@ namespace LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LOG_FUNC("presentationWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam)); - return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); + return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam)); } } @@ -27,7 +27,7 @@ namespace Gdi GuiThread::execute([&]() { presentationWindow = GuiThread::createWindow( - WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | (owner ? 0 : WS_EX_TOOLWINDOW), + WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | WS_EX_NOACTIVATE | (owner ? 0 : WS_EX_TOOLWINDOW), reinterpret_cast(g_classAtom), nullptr, WS_DISABLED | WS_POPUP, @@ -56,6 +56,7 @@ namespace Gdi WNDCLASS wc = {}; wc.lpfnWndProc = &presentationWindowProc; wc.hInstance = Dll::g_currentModule; + wc.hCursor = CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_ARROW); wc.lpszClassName = "DDrawCompatPresentationWindow"; g_classAtom = CALL_ORIG_FUNC(RegisterClassA)(&wc); } diff --git a/DDrawCompat/Gdi/User32WndProcs.cpp b/DDrawCompat/Gdi/User32WndProcs.cpp index d24cc87..422e8ea 100644 --- a/DDrawCompat/Gdi/User32WndProcs.cpp +++ b/DDrawCompat/Gdi/User32WndProcs.cpp @@ -206,22 +206,22 @@ namespace { case HTLEFT: case HTRIGHT: - SetCursor(LoadCursor(nullptr, IDC_SIZEWE)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZEWE)); return TRUE; case HTTOP: case HTBOTTOM: - SetCursor(LoadCursor(nullptr, IDC_SIZENS)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENS)); return TRUE; case HTTOPLEFT: case HTBOTTOMRIGHT: - SetCursor(LoadCursor(nullptr, IDC_SIZENWSE)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENWSE)); return TRUE; case HTBOTTOMLEFT: case HTTOPRIGHT: - SetCursor(LoadCursor(nullptr, IDC_SIZENESW)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENESW)); return TRUE; } @@ -247,7 +247,7 @@ namespace } else { - SetCursor(LoadCursor(nullptr, IDC_ARROW)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_ARROW)); } return FALSE; } @@ -530,7 +530,7 @@ namespace case WM_SETCURSOR: if (CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP)) { - SetCursor(LoadCursor(nullptr, IDC_SIZENWSE)); + SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENWSE)); } return TRUE; } diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 99b5b5b..61e775d 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -153,19 +153,13 @@ namespace Gdi return nullptr; } - auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*primary); - if (!resource) + auto repo = DDraw::DirectDrawSurface::getSurfaceRepository(*DDraw::PrimarySurface::getPrimary()); + if (!repo) { return nullptr; } - auto device = D3dDdi::Device::findDeviceByResource(resource); - if (!device) - { - return nullptr; - } - - auto dd(device->getRepo().getDirectDraw()); + auto dd(repo->getDirectDraw()); if (!dd) { return nullptr; diff --git a/DDrawCompat/Input/Input.cpp b/DDrawCompat/Input/Input.cpp index d2e106f..9b98b47 100644 --- a/DDrawCompat/Input/Input.cpp +++ b/DDrawCompat/Input/Input.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -157,6 +158,12 @@ namespace return 1; } } + + auto steamWindow = Overlay::Steam::getWindow(); + if (steamWindow) + { + PostMessage(steamWindow, wParam, llHook->vkCode, 0); + } } } return CallNextHookEx(nullptr, nCode, wParam, lParam); diff --git a/DDrawCompat/Overlay/ConfigWindow.cpp b/DDrawCompat/Overlay/ConfigWindow.cpp index 4e0e56d..ed577cc 100644 --- a/DDrawCompat/Overlay/ConfigWindow.cpp +++ b/DDrawCompat/Overlay/ConfigWindow.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace { @@ -275,6 +276,11 @@ namespace Overlay { if (isVisible != Window::isVisible()) { + if (isVisible && Overlay::Steam::isOverlayOpen()) + { + return; + } + Window::setVisible(isVisible); Input::setCapture(isVisible ? this : nullptr); setFocus(nullptr); diff --git a/DDrawCompat/Overlay/Steam.cpp b/DDrawCompat/Overlay/Steam.cpp new file mode 100644 index 0000000..cb1c4cd --- /dev/null +++ b/DDrawCompat/Overlay/Steam.cpp @@ -0,0 +1,395 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + decltype(&DirectDrawCreateEx) g_steamDirectDrawCreateEx = nullptr; + D3dDdi::Adapter* g_adapter = nullptr; + IDirectDraw7* g_dd = nullptr; + IDirect3D7* g_d3d = nullptr; + IDirectDrawSurface7* g_rt = nullptr; + D3dDdi::Resource* g_rtResource = nullptr; + D3dDdi::Resource* g_bbResource = nullptr; + UINT g_bbSubResourceIndex = 0; + IDirect3DDevice7* g_dev = nullptr; + UINT g_width = 0; + UINT g_height = 0; + bool g_isOverlayOpen = false; + long long g_qpcLastRender = 0; + HWND g_window = nullptr; + + void releaseDevice(); + void* getTargetFunc(void* hookedFunc); + + BOOL WINAPI flushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize) + { + LOG_FUNC("FlushInstructionCache", hProcess, lpBaseAddress, dwSize); + auto hookedFunc = const_cast(static_cast(lpBaseAddress)); + if ((Dll::g_jmpTargetProcs.DirectDrawCreate == lpBaseAddress || + Dll::g_jmpTargetProcs.DirectDrawCreateEx == lpBaseAddress) && + 0xE9 == hookedFunc[0] && 5 == dwSize) + { + int& jmpOffset = *reinterpret_cast(hookedFunc + 1); + decltype(&DirectDrawCreateEx) directDrawCreateEx = nullptr; + if (!g_steamDirectDrawCreateEx && Dll::g_jmpTargetProcs.DirectDrawCreateEx == lpBaseAddress) + { + directDrawCreateEx = reinterpret_cast(hookedFunc + 5 + jmpOffset); + } + + auto targetFunc = getTargetFunc(hookedFunc); + auto gameOverlayRenderer = GetModuleHandle("GameOverlayRenderer.dll"); + if (gameOverlayRenderer && Compat::getModuleHandleFromAddress(targetFunc) == gameOverlayRenderer) + { + if (directDrawCreateEx) + { + g_steamDirectDrawCreateEx = directDrawCreateEx; + LOG_INFO << "Steam overlay support activated"; + } + + LOG_DEBUG << "Restoring hook: " << Compat::funcPtrToStr(lpBaseAddress); + DWORD oldProtect = 0; + VirtualProtect(hookedFunc, 5, PAGE_EXECUTE_READWRITE, &oldProtect); + auto newFunc = Dll::g_jmpTargetProcs.DirectDrawCreate == lpBaseAddress + ? Dll::g_newProcs.DirectDrawCreate : Dll::g_newProcs.DirectDrawCreateEx; + jmpOffset = reinterpret_cast(newFunc) - (hookedFunc + 5); + VirtualProtect(hookedFunc, 5, PAGE_EXECUTE_READ, &oldProtect); + } + } + return LOG_RESULT(CALL_ORIG_FUNC(FlushInstructionCache)(hProcess, lpBaseAddress, dwSize)); + } + + HWND WINAPI getActiveWindow() + { + LOG_FUNC("steamGetActiveWindow"); + return LOG_RESULT(nullptr); + } + + BOOL WINAPI getClientRect(HWND hWnd, LPRECT lpRect) + { + LOG_FUNC("steamGetClientRect", hWnd, lpRect); + Win32::ScopedDpiAwareness dpiAwareness; + return LOG_RESULT(GetClientRect(hWnd, lpRect)); + } + + HWND WINAPI getForegroundWindow() + { + LOG_FUNC("steamGetForegroundWindow"); + HWND result = GetForegroundWindow(); + if (result) + { + HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); + if (presentationWindow && GetParent(presentationWindow) == result) + { + g_window = presentationWindow; + return LOG_RESULT(presentationWindow); + } + } + return LOG_RESULT(nullptr); + } + + void* getTargetFunc(void* hookedFunc) + { + auto targetFunc = reinterpret_cast(hookedFunc); + while (0xE9 == targetFunc[0]) + { + targetFunc += 5 + *reinterpret_cast(targetFunc + 1); + } + return targetFunc; + } + + template + void release(Intf*& intf) + { + if (intf) + { + intf->lpVtbl->Release(intf); + intf = nullptr; + } + } + + void releaseAll() + { + releaseDevice(); + release(g_d3d); + release(g_dd); + g_adapter = nullptr; + } + + void releaseDevice() + { + release(g_dev); + release(g_rt); + g_rtResource = nullptr; + g_width = 0; + g_height = 0; + } + + void* removeHook(HMODULE gameOverlayRenderer, const wchar_t* origDDrawModulePath, void* hookedFunc) + { + LOG_FUNC("Steam::removeHook", gameOverlayRenderer, origDDrawModulePath, hookedFunc); + auto targetFunc = getTargetFunc(hookedFunc); + if (targetFunc != hookedFunc && Compat::getModuleHandleFromAddress(targetFunc) == gameOverlayRenderer) + { + auto offset = Compat::getModuleFileOffset(hookedFunc); + if (0 == offset) + { + return LOG_RESULT(nullptr); + } + + std::ifstream f(origDDrawModulePath, std::ios::in | std::ios::binary); + f.seekg(offset); + char instructions[20] = {}; + f.read(instructions, sizeof(instructions)); + f.close(); + + unsigned totalInstructionSize = 0; + while (totalInstructionSize < 5) + { + unsigned instructionSize = Compat::getInstructionSize(instructions + totalInstructionSize); + if (0 == instructionSize) + { + return LOG_RESULT(nullptr); + } + totalInstructionSize += instructionSize; + } + + DWORD oldProtect = 0; + VirtualProtect(hookedFunc, totalInstructionSize, PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(hookedFunc, instructions, totalInstructionSize); + VirtualProtect(hookedFunc, totalInstructionSize, PAGE_EXECUTE_READ, &oldProtect); + CALL_ORIG_FUNC(FlushInstructionCache)(GetCurrentProcess(), hookedFunc, totalInstructionSize); + + return LOG_RESULT(targetFunc); + } + return LOG_RESULT(nullptr); + } + + LONG WINAPI setClassLongW(HWND hWnd, int nIndex, LONG dwNewLong) + { + LOG_FUNC("steamSetClassLongW", hWnd, nIndex, dwNewLong); + if (GCLP_HCURSOR == nIndex) + { + HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); + if (presentationWindow && presentationWindow == hWnd) + { + g_isOverlayOpen = 0 == dwNewLong; + LOG_DEBUG << "Steam overlay is " << (g_isOverlayOpen ? "opening" : "closing"); + + auto exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hWnd, GWL_EXSTYLE); + CALL_ORIG_FUNC(SetWindowLongA)(hWnd, GWL_EXSTYLE, + g_isOverlayOpen ? (exStyle & ~WS_EX_TRANSPARENT) : (exStyle | WS_EX_TRANSPARENT)); + + if (g_isOverlayOpen) + { + auto configWindow = Gdi::GuiThread::getConfigWindow(); + if (configWindow) + { + configWindow->setVisible(false); + } + Gdi::Cursor::setEmulated(false); + } + } + } + return LOG_RESULT(CALL_ORIG_FUNC(SetWindowLongW)(hWnd, nIndex, dwNewLong)); + } + + bool updateDevice(D3dDdi::Resource& resource) + { + auto adapter = &resource.getDevice().getAdapter(); + if (adapter != g_adapter) + { + releaseAll(); + g_adapter = adapter; + } + + if (!g_dd) + { + auto result = g_steamDirectDrawCreateEx( + adapter->getGuid(), reinterpret_cast(&g_dd), IID_IDirectDraw7, nullptr); + if (FAILED(result)) + { + LOG_ONCE("Failed to create DirectDraw object for Steam overlay: " << Compat::hex(result)); + return false; + } + + result = g_dd->lpVtbl->SetCooperativeLevel(g_dd, nullptr, DDSCL_NORMAL); + if (FAILED(result)) + { + LOG_ONCE("Failed to set cooperative level for Steam overlay: " << Compat::hex(result)); + release(g_dd); + return false; + } + } + + if (!g_d3d) + { + auto result = g_dd->lpVtbl->QueryInterface(g_dd, IID_IDirect3D7, reinterpret_cast(&g_d3d)); + if (FAILED(result)) + { + LOG_ONCE("Failed to create Direct3D object for Steam overlay: " << Compat::hex(result)); + return false; + } + } + + auto& si = resource.getFixedDesc().pSurfList[0]; + if (!g_rt || si.Width != g_width || si.Height != g_height || FAILED(g_rt->lpVtbl->IsLost(g_rt))) + { + releaseDevice(); + + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + desc.dwWidth = si.Width; + desc.dwHeight = si.Height; + desc.ddpfPixelFormat = D3dDdi::getPixelFormat(D3DDDIFMT_X8R8G8B8); + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY; + + auto& formats = adapter->getInfo().formatOps; + if (formats.find(D3dDdi::FOURCC_NULL) != formats.end()) + { + D3dDdi::Resource::setFormatOverride(D3dDdi::FOURCC_NULL); + } + D3dDdi::Resource::enableConfig(false); + auto result = g_dd->lpVtbl->CreateSurface(g_dd, &desc, &g_rt, nullptr); + D3dDdi::Resource::enableConfig(true); + D3dDdi::Resource::setFormatOverride(D3DDDIFMT_UNKNOWN); + + if (FAILED(result)) + { + LOG_ONCE("Failed to create DirectDrawSurface object for Steam overlay: " << Compat::hex(result)); + return false; + } + + g_width = si.Width; + g_height = si.Height; + g_rtResource = D3dDdi::Device::findResource(DDraw::DirectDrawSurface::getDriverResourceHandle(*g_rt)); + } + + if (!g_dev) + { + auto result = g_d3d->lpVtbl->CreateDevice(g_d3d, IID_IDirect3DHALDevice, g_rt, &g_dev); + if (FAILED(result)) + { + LOG_ONCE("Failed to create Direct3DDevice for Steam overlay: " << Compat::hex(result)); + return false; + } + + g_dev->lpVtbl->BeginScene(g_dev); + g_dev->lpVtbl->Clear(g_dev, 0, nullptr, D3DCLEAR_TARGET, 0, 0, 0); + g_dev->lpVtbl->EndScene(g_dev); + } + + return true; + } +} + +namespace Overlay +{ + namespace Steam + { + void flush() + { + if (!g_steamDirectDrawCreateEx) + { + return; + } + + auto qpcNow = Time::queryPerformanceCounter(); + if (g_isOverlayOpen || qpcNow - g_qpcLastRender > Time::g_qpcFrequency / 20) + { + DDraw::RealPrimarySurface::scheduleOverlayUpdate(); + } + } + + Resources getResources() + { + Resources resources = {}; + resources.rtResource = g_rtResource; + resources.bbResource = g_bbResource; + resources.bbSubResourceIndex = g_bbSubResourceIndex; + return resources; + } + + HWND getWindow() + { + return g_window; + } + + void init(const wchar_t* origDDrawModulePath) + { + HOOK_FUNCTION(kernel32, FlushInstructionCache, flushInstructionCache); + + auto gameOverlayRenderer = GetModuleHandle("GameOverlayRenderer.dll"); + if (!gameOverlayRenderer) + { + return; + } + + removeHook(gameOverlayRenderer, origDDrawModulePath, Dll::g_jmpTargetProcs.DirectDrawCreate); + g_steamDirectDrawCreateEx = static_cast( + removeHook(gameOverlayRenderer, origDDrawModulePath, Dll::g_jmpTargetProcs.DirectDrawCreateEx)); + + if (g_steamDirectDrawCreateEx) + { + LOG_INFO << "Steam overlay support activated"; + } + } + + void installHooks() + { + auto gameOverlayRenderer = GetModuleHandle("GameOverlayRenderer.dll"); + if (!gameOverlayRenderer) + { + return; + } + + LOG_INFO << "Installing Steam overlay hooks"; + Compat::hookIatFunction(gameOverlayRenderer, "GetActiveWindow", getActiveWindow); + Compat::hookIatFunction(gameOverlayRenderer, "GetClientRect", getClientRect); + Compat::hookIatFunction(gameOverlayRenderer, "GetForegroundWindow", getForegroundWindow); + Compat::hookIatFunction(gameOverlayRenderer, "SetClassLongW", setClassLongW); + } + + bool isOverlayOpen() + { + return g_isOverlayOpen; + } + + void onDestroyWindow(HWND hwnd) + { + if (hwnd == g_window) + { + g_window = nullptr; + } + } + + void render(D3dDdi::Resource& resource, unsigned subResourceIndex) + { + LOG_FUNC("Steam::render", resource, subResourceIndex); + if (!g_steamDirectDrawCreateEx || !updateDevice(resource)) + { + return; + } + + g_bbResource = &resource; + g_bbSubResourceIndex = subResourceIndex; + g_dev->lpVtbl->BeginScene(g_dev); + g_dev->lpVtbl->EndScene(g_dev); + g_bbResource = nullptr; + g_bbSubResourceIndex = 0; + g_qpcLastRender = Time::queryPerformanceCounter(); + } + } +} diff --git a/DDrawCompat/Overlay/Steam.h b/DDrawCompat/Overlay/Steam.h new file mode 100644 index 0000000..fa9127f --- /dev/null +++ b/DDrawCompat/Overlay/Steam.h @@ -0,0 +1,28 @@ +#pragma once + +namespace D3dDdi +{ + class Resource; +} + +namespace Overlay +{ + namespace Steam + { + struct Resources + { + D3dDdi::Resource* rtResource; + D3dDdi::Resource* bbResource; + UINT bbSubResourceIndex; + }; + + void flush(); + Resources getResources(); + HWND getWindow(); + void init(const wchar_t* origDDrawModulePath); + void installHooks(); + bool isOverlayOpen(); + void onDestroyWindow(HWND hwnd); + void render(D3dDdi::Resource& resource, unsigned subResourceIndex); + } +}