1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Added support for Steam overlay in fullscreen mode

This commit is contained in:
narzoul 2024-04-13 16:44:33 +02:00
parent f1f775aaa4
commit 79d2eea9e3
29 changed files with 659 additions and 98 deletions

View File

@ -105,28 +105,6 @@ namespace
return ntHeaders; 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<unsigned>(endOffset - g_debugBase);
}
void hookFunction(void*& origFuncPtr, void* newFuncPtr, const char* funcName) void hookFunction(void*& origFuncPtr, void* newFuncPtr, const char* funcName)
{ {
BYTE* targetFunc = static_cast<BYTE*>(origFuncPtr); BYTE* targetFunc = static_cast<BYTE*>(origFuncPtr);
@ -193,7 +171,7 @@ namespace
BYTE* dst = trampoline; BYTE* dst = trampoline;
while (src - targetFunc < 5) while (src - targetFunc < 5)
{ {
unsigned instructionSize = getInstructionSize(src); unsigned instructionSize = Compat::getInstructionSize(src);
if (0 == instructionSize) if (0 == instructionSize)
{ {
return; return;
@ -223,13 +201,12 @@ namespace
memset(targetFunc + 5, 0xCC, src - targetFunc - 5); memset(targetFunc + 5, 0xCC, src - targetFunc - 5);
VirtualProtect(targetFunc, src - targetFunc, PAGE_EXECUTE_READ, &oldProtect); VirtualProtect(targetFunc, src - targetFunc, PAGE_EXECUTE_READ, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), nullptr, 0); origFuncPtr = trampoline;
CALL_ORIG_FUNC(FlushInstructionCache)(GetCurrentProcess(), nullptr, 0);
HMODULE module = nullptr; HMODULE module = nullptr;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
reinterpret_cast<char*>(targetFunc), &module); reinterpret_cast<char*>(targetFunc), &module);
origFuncPtr = trampoline;
} }
bool initDbgEng() bool initDbgEng()
@ -339,7 +316,7 @@ namespace Compat
g_isDbgEngInitialized = false; g_isDbgEngInitialized = false;
} }
std::string funcPtrToStr(void* funcPtr) std::string funcPtrToStr(const void* funcPtr)
{ {
std::ostringstream oss; std::ostringstream oss;
HMODULE module = Compat::getModuleHandleFromAddress(funcPtr); HMODULE module = Compat::getModuleHandleFromAddress(funcPtr);
@ -355,11 +332,63 @@ namespace Compat
return oss.str(); 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<unsigned>(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<const BYTE*>(address) - reinterpret_cast<const BYTE*>(mod);
auto sectionHeader = reinterpret_cast<IMAGE_SECTION_HEADER*>(
&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; HMODULE module = nullptr;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
static_cast<char*>(address), &module); static_cast<const char*>(address), &module);
return module; return module;
} }

View File

@ -14,8 +14,10 @@
namespace Compat namespace Compat
{ {
void closeDbgEng(); void closeDbgEng();
std::string funcPtrToStr(void* funcPtr); std::string funcPtrToStr(const void* funcPtr);
HMODULE getModuleHandleFromAddress(void* address); unsigned getInstructionSize(void* instruction);
DWORD getModuleFileOffset(const void* address);
HMODULE getModuleHandleFromAddress(const void* address);
template <auto origFunc> template <auto origFunc>
decltype(origFunc) g_origFuncPtr = origFunc; decltype(origFunc) g_origFuncPtr = origFunc;

View File

@ -58,6 +58,8 @@ namespace D3dDdi
, m_origVtable(CompatVtable<D3DDDI_ADAPTERFUNCS>::s_origVtable) , m_origVtable(CompatVtable<D3DDDI_ADAPTERFUNCS>::s_origVtable)
, m_runtimeVersion(data.Version) , m_runtimeVersion(data.Version)
, m_driverVersion(data.DriverVersion) , m_driverVersion(data.DriverVersion)
, m_guid(nullptr)
, m_guidBuf{}
, m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid) , m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid)
, m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().deviceName) , m_deviceName(KernelModeThunks::getLastOpenAdapterInfo().deviceName)
, m_repository{} , m_repository{}
@ -496,19 +498,20 @@ namespace D3dDdi
return result; return result;
} }
void Adapter::setRepository(LUID luid, CompatWeakPtr<IDirectDraw7> repository, bool isPrimary) void Adapter::setRepository(LUID luid, GUID* guid, CompatWeakPtr<IDirectDraw7> repository)
{ {
for (auto& adapter : s_adapters) for (auto& adapter : s_adapters)
{ {
if (adapter.second.m_luid == luid) 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; adapter.second.m_repository = repository;
auto& surfaceRepo = SurfaceRepository::get(adapter.second); auto& surfaceRepo = SurfaceRepository::get(adapter.second);
surfaceRepo.setRepository(repository); surfaceRepo.setRepository(repository);
if (isPrimary)
{
surfaceRepo.setAsPrimaryRepo();
}
} }
} }
} }

View File

@ -36,6 +36,7 @@ namespace D3dDdi
operator HANDLE() const { return m_adapter; } operator HANDLE() const { return m_adapter; }
SIZE getAspectRatio() const; SIZE getAspectRatio() const;
GUID* getGuid() const { return m_guid; }
const AdapterInfo& getInfo() const { return m_info; } const AdapterInfo& getInfo() const { return m_info; }
LUID getLuid() const { return m_luid; } LUID getLuid() const { return m_luid; }
const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } 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 void add(const D3DDDIARG_OPENADAPTER& data) { s_adapters.emplace(data.hAdapter, data); }
static Adapter& get(HANDLE adapter) { return s_adapters.find(adapter)->second; } static Adapter& get(HANDLE adapter) { return s_adapters.find(adapter)->second; }
static void setRepository(LUID luid, CompatWeakPtr<IDirectDraw7> repository, bool isPrimary); static void setRepository(LUID luid, GUID* guid, CompatWeakPtr<IDirectDraw7> repository);
private: private:
const AdapterInfo& findInfo() const; const AdapterInfo& findInfo() const;
@ -74,6 +75,8 @@ namespace D3dDdi
D3DDDI_ADAPTERFUNCS m_origVtable; D3DDDI_ADAPTERFUNCS m_origVtable;
UINT m_runtimeVersion; UINT m_runtimeVersion;
UINT m_driverVersion; UINT m_driverVersion;
GUID* m_guid;
GUID m_guidBuf;
LUID m_luid; LUID m_luid;
std::wstring m_deviceName; std::wstring m_deviceName;
CompatWeakPtr<IDirectDraw7> m_repository; CompatWeakPtr<IDirectDraw7> m_repository;

View File

@ -13,6 +13,7 @@
#include <D3dDdi/Log/DeviceFuncsLog.h> #include <D3dDdi/Log/DeviceFuncsLog.h>
#include <D3dDdi/Resource.h> #include <D3dDdi/Resource.h>
#include <D3dDdi/ShaderAssembler.h> #include <D3dDdi/ShaderAssembler.h>
#include <Overlay/Steam.h>
#include <Shaders/VertexFixup.h> #include <Shaders/VertexFixup.h>
#define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": " #define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": "
@ -1117,7 +1118,19 @@ namespace D3dDdi
auto depthStencil = m_app.depthStencil; auto depthStencil = m_app.depthStencil;
bool isTransformed = getVertexDecl().isTransformed; 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) if (resource)
{ {
auto customResource = resource->getCustomResource(); auto customResource = resource->getCustomResource();
@ -1129,11 +1142,11 @@ namespace D3dDdi
if (isTransformed) if (isTransformed)
{ {
scissorRect = makeRect(scaledVp); scissorRect = makeRect(scaledVp);
auto& si = resource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; auto& si = resource->getFixedDesc().pSurfList[renderTarget.SubResourceIndex];
vp = { 0, 0, si.Width, si.Height }; vp = { 0, 0, si.Width, si.Height };
if (customResource) if (customResource)
{ {
auto& scaledSi = customResource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; auto& scaledSi = customResource->getFixedDesc().pSurfList[renderTarget.SubResourceIndex];
scaledVp = { 0, 0, scaledSi.Width, scaledSi.Height }; scaledVp = { 0, 0, scaledSi.Width, scaledSi.Height };
} }
else else

View File

@ -273,6 +273,27 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETVERTEXSHADERCONST&
<< val.Count; << 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) std::ostream& operator<<(std::ostream& os, const D3DDDIARG_TEXTURESTAGESTATE& val)
{ {
return Compat::LogStruct(os) return Compat::LogStruct(os)

View File

@ -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_SETSTREAMSOURCE& val);
std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCEUM& 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_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_TEXTURESTAGESTATE& val);
std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val);
std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UPDATEPALETTE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UPDATEPALETTE& val);

View File

@ -25,6 +25,7 @@
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
#include <Overlay/Steam.h>
namespace namespace
{ {
@ -244,7 +245,14 @@ namespace D3dDdi
return S_OK; 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); return bltViaCpu(data, *srcResource);
} }
@ -1014,7 +1022,7 @@ namespace D3dDdi
HRESULT Resource::lock(D3DDDIARG_LOCK& data) 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; return E_FAIL;
} }
@ -1325,6 +1333,8 @@ namespace D3dDdi
presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex),
Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor); Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor);
Overlay::Steam::render(*this, data.DstSubResourceIndex);
return LOG_RESULT(S_OK); return LOG_RESULT(S_OK);
} }

View File

@ -431,9 +431,13 @@ namespace D3dDdi
} }
} }
void SurfaceRepository::setAsPrimaryRepo() void SurfaceRepository::setRepository(CompatWeakPtr<IDirectDraw7> dd)
{ {
g_primaryRepository = this; m_dd = dd;
if (!g_primaryRepository)
{
g_primaryRepository = this;
}
} }
bool SurfaceRepository::s_inCreateSurface = false; bool SurfaceRepository::s_inCreateSurface = false;

View File

@ -57,8 +57,7 @@ namespace D3dDdi
CompatWeakPtr<IDirectDrawSurface7> getWindowedPrimary(); CompatWeakPtr<IDirectDrawSurface7> getWindowedPrimary();
CompatPtr<IDirectDrawSurface7> getWindowedSrc(RECT rect); CompatPtr<IDirectDrawSurface7> getWindowedSrc(RECT rect);
void release(Surface& surface); void release(Surface& surface);
void setAsPrimaryRepo(); void setRepository(CompatWeakPtr<IDirectDraw7> dd);
void setRepository(CompatWeakPtr<IDirectDraw7> dd) { m_dd = dd; }
static SurfaceRepository& get(const Adapter& adapter); static SurfaceRepository& get(const Adapter& adapter);
static SurfaceRepository& getPrimaryRepo(); static SurfaceRepository& getPrimaryRepo();

View File

@ -343,7 +343,7 @@ namespace DDraw
} }
repo.get()->lpVtbl->SetCooperativeLevel(repo, nullptr, DDSCL_NORMAL); repo.get()->lpVtbl->SetCooperativeLevel(repo, nullptr, DDSCL_NORMAL);
it = repositories.insert({ adapterInfo.luid, repo }).first; 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(); repo.detach();
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <type_traits>
#include <ddraw.h> #include <ddraw.h>
#include <ddrawi.h> #include <ddrawi.h>
@ -12,18 +13,26 @@ namespace DDraw
{ {
namespace DirectDraw namespace DirectDraw
{ {
template <typename TSurface>
struct IsDirectDraw : std::false_type {};
template <> struct IsDirectDraw<IDirectDraw> : std::true_type {};
template <> struct IsDirectDraw<IDirectDraw2> : std::true_type {};
template <> struct IsDirectDraw<IDirectDraw4> : std::true_type {};
template <> struct IsDirectDraw<IDirectDraw7> : std::true_type {};
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp); DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
void hookDDrawWindowProc(WNDPROC ddrawWndProc); void hookDDrawWindowProc(WNDPROC ddrawWndProc);
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd); void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);
void suppressEmulatedDirectDraw(GUID*& guid); void suppressEmulatedDirectDraw(GUID*& guid);
template <typename TDirectDraw> template <typename TDirectDraw, typename = std::enable_if_t<IsDirectDraw<TDirectDraw>::value>>
DDRAWI_DIRECTDRAW_INT& getInt(TDirectDraw& dd) DDRAWI_DIRECTDRAW_INT& getInt(TDirectDraw& dd)
{ {
return reinterpret_cast<DDRAWI_DIRECTDRAW_INT&>(dd); return reinterpret_cast<DDRAWI_DIRECTDRAW_INT&>(dd);
} }
template <typename TDirectDraw> template <typename TDirectDraw, typename = std::enable_if_t<IsDirectDraw<TDirectDraw>::value>>
HWND* getDeviceWindowPtr(TDirectDraw& dd) HWND* getDeviceWindowPtr(TDirectDraw& dd)
{ {
return &reinterpret_cast<HWND>(getInt(dd).lpLcl->hWnd); return &reinterpret_cast<HWND>(getInt(dd).lpLcl->hWnd);

View File

@ -6,6 +6,8 @@
#include <DDraw/Surfaces/Surface.h> #include <DDraw/Surfaces/Surface.h>
#include <DDraw/Surfaces/SurfaceImpl.h> #include <DDraw/Surfaces/SurfaceImpl.h>
#include <DDraw/Visitors/DirectDrawSurfaceVtblVisitor.h> #include <DDraw/Visitors/DirectDrawSurfaceVtblVisitor.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/SurfaceRepository.h>
#define SET_COMPAT_METHOD(method) \ #define SET_COMPAT_METHOD(method) \
vtable.method = &callImpl<decltype(&DDraw::SurfaceImpl<TSurface>::method), &DDraw::SurfaceImpl<TSurface>::method, \ vtable.method = &callImpl<decltype(&DDraw::SurfaceImpl<TSurface>::method), &DDraw::SurfaceImpl<TSurface>::method, \
@ -92,6 +94,12 @@ namespace DDraw
return context.surfaces; return context.surfaces;
} }
D3dDdi::SurfaceRepository* getSurfaceRepository(HANDLE resource)
{
auto device = D3dDdi::Device::findDeviceByResource(resource);
return device ? &device->getRepo() : nullptr;
}
template <typename Vtable> template <typename Vtable>
void hookVtable(const Vtable& vtable) void hookVtable(const Vtable& vtable)
{ {

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <type_traits>
#include <vector> #include <vector>
#include <Windows.h> #include <Windows.h>
@ -8,36 +9,58 @@
#include <Common/CompatPtr.h> #include <Common/CompatPtr.h>
#include <Common/CompatRef.h> #include <Common/CompatRef.h>
namespace D3dDdi
{
class SurfaceRepository;
}
namespace DDraw namespace DDraw
{ {
namespace DirectDrawSurface namespace DirectDrawSurface
{ {
template <typename TSurface>
struct IsSurface : std::false_type {};
template <> struct IsSurface<IDirectDrawSurface> : std::true_type {};
template <> struct IsSurface<IDirectDrawSurface2> : std::true_type {};
template <> struct IsSurface<IDirectDrawSurface3> : std::true_type {};
template <> struct IsSurface<IDirectDrawSurface4> : std::true_type {};
template <> struct IsSurface<IDirectDrawSurface7> : std::true_type {};
std::vector<CompatPtr<IDirectDrawSurface7>> getAllAttachedSurfaces(CompatRef<IDirectDrawSurface7> surface); std::vector<CompatPtr<IDirectDrawSurface7>> getAllAttachedSurfaces(CompatRef<IDirectDrawSurface7> surface);
template <typename TSurface> template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
DDRAWI_DDRAWSURFACE_INT& getInt(TSurface& surface) DDRAWI_DDRAWSURFACE_INT& getInt(TSurface& surface)
{ {
return reinterpret_cast<DDRAWI_DDRAWSURFACE_INT&>(surface); return reinterpret_cast<DDRAWI_DDRAWSURFACE_INT&>(surface);
} }
template <typename TSurface> template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
HANDLE getRuntimeResourceHandle(TSurface& surface) HANDLE getRuntimeResourceHandle(TSurface& surface)
{ {
return reinterpret_cast<HANDLE>(getInt(surface).lpLcl->hDDSurface); return reinterpret_cast<HANDLE>(getInt(surface).lpLcl->hDDSurface);
} }
template <typename TSurface> template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
HANDLE getDriverResourceHandle(TSurface& surface) HANDLE& getDriverResourceHandle(TSurface& surface)
{ {
return reinterpret_cast<HANDLE*>(getRuntimeResourceHandle(surface))[0]; return reinterpret_cast<HANDLE*>(getRuntimeResourceHandle(surface))[0];
} }
template <typename TSurface> template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
UINT getSubResourceIndex(TSurface& surface) UINT& getSubResourceIndex(TSurface& surface)
{ {
return reinterpret_cast<UINT*>(getRuntimeResourceHandle(surface))[1]; return reinterpret_cast<UINT*>(getRuntimeResourceHandle(surface))[1];
} }
D3dDdi::SurfaceRepository* getSurfaceRepository(HANDLE resource);
template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
D3dDdi::SurfaceRepository* getSurfaceRepository(TSurface& surface)
{
return getSurfaceRepository(getDriverResourceHandle(surface));
}
template <typename Vtable> template <typename Vtable>
void hookVtable(const Vtable& vtable); void hookVtable(const Vtable& vtable);
} }

View File

@ -97,9 +97,6 @@ namespace DDraw
{ {
void installHooks(CompatPtr<IDirectDraw7> dd7) void installHooks(CompatPtr<IDirectDraw7> dd7)
{ {
DDraw::DirectDraw::onCreate(nullptr, *dd7);
RealPrimarySurface::init();
g_origInitialize = dd7.get()->lpVtbl->Initialize; g_origInitialize = dd7.get()->lpVtbl->Initialize;
Compat::hookFunction(reinterpret_cast<void*&>(g_origInitialize), initialize, "IDirectDrawVtbl::Initialize"); Compat::hookFunction(reinterpret_cast<void*&>(g_origInitialize), initialize, "IDirectDrawVtbl::Initialize");
@ -107,5 +104,8 @@ namespace DDraw
hookDirectDrawClipper(*dd7); hookDirectDrawClipper(*dd7);
hookDirectDrawPalette(*dd7); hookDirectDrawPalette(*dd7);
hookDirectDrawSurface(*dd7); hookDirectDrawSurface(*dd7);
DDraw::DirectDraw::onCreate(nullptr, *dd7);
DDraw::RealPrimarySurface::init();
} }
} }

View File

@ -38,6 +38,7 @@
#include <Gdi/WinProc.h> #include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Overlay/Steam.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h> #include <Win32/DpiAwareness.h>
#include <Win32/Thread.h> #include <Win32/Thread.h>
@ -276,18 +277,7 @@ namespace
D3dDdi::SurfaceRepository* repo = nullptr; D3dDdi::SurfaceRepository* repo = nullptr;
if (src) if (src)
{ {
auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*frontBuffer); repo = DDraw::DirectDrawSurface::getSurfaceRepository(*frontBuffer);
if (!resource)
{
return;
}
auto device = D3dDdi::Device::findDeviceByResource(resource);
if (!device)
{
return;
}
repo = &device->getRepo();
} }
else else
{ {
@ -364,7 +354,7 @@ namespace
} }
Gdi::Cursor::setMonitorClipRect(clipRect); Gdi::Cursor::setMonitorClipRect(clipRect);
Gdi::Cursor::setEmulated(true); Gdi::Cursor::setEmulated(!Overlay::Steam::isOverlayOpen());
} }
} }
@ -568,6 +558,7 @@ namespace DDraw
static UINT lastOverlayCheckVsyncCount = 0; static UINT lastOverlayCheckVsyncCount = 0;
if (vsyncCount != lastOverlayCheckVsyncCount) if (vsyncCount != lastOverlayCheckVsyncCount)
{ {
updatePresentationParams();
setPresentationWindowTopmost(); setPresentationWindowTopmost();
Gdi::Cursor::update(); Gdi::Cursor::update();
Gdi::Caret::blink(); Gdi::Caret::blink();
@ -577,11 +568,10 @@ namespace DDraw
statsWindow->updateStats(); statsWindow->updateStats();
g_qpcLastUpdate = Time::queryPerformanceCounter(); g_qpcLastUpdate = Time::queryPerformanceCounter();
} }
Overlay::Steam::flush();
lastOverlayCheckVsyncCount = vsyncCount; lastOverlayCheckVsyncCount = vsyncCount;
} }
updatePresentationParams();
bool isOverlayOnly = false; bool isOverlayOnly = false;
{ {

View File

@ -325,6 +325,7 @@
<ClInclude Include="Overlay\StatsEventRate.h" /> <ClInclude Include="Overlay\StatsEventRate.h" />
<ClInclude Include="Overlay\StatsTimer.h" /> <ClInclude Include="Overlay\StatsTimer.h" />
<ClInclude Include="Overlay\StatsWindow.h" /> <ClInclude Include="Overlay\StatsWindow.h" />
<ClInclude Include="Overlay\Steam.h" />
<ClInclude Include="Overlay\Window.h" /> <ClInclude Include="Overlay\Window.h" />
<ClInclude Include="Win32\DisplayMode.h" /> <ClInclude Include="Win32\DisplayMode.h" />
<ClInclude Include="Win32\DpiAwareness.h" /> <ClInclude Include="Win32\DpiAwareness.h" />
@ -459,6 +460,7 @@
<ClCompile Include="Overlay\StatsEventRate.cpp" /> <ClCompile Include="Overlay\StatsEventRate.cpp" />
<ClCompile Include="Overlay\StatsTimer.cpp" /> <ClCompile Include="Overlay\StatsTimer.cpp" />
<ClCompile Include="Overlay\StatsWindow.cpp" /> <ClCompile Include="Overlay\StatsWindow.cpp" />
<ClCompile Include="Overlay\Steam.cpp" />
<ClCompile Include="Overlay\Window.cpp" /> <ClCompile Include="Overlay\Window.cpp" />
<ClCompile Include="Win32\DisplayMode.cpp" /> <ClCompile Include="Win32\DisplayMode.cpp" />
<ClCompile Include="Win32\DpiAwareness.cpp" /> <ClCompile Include="Win32\DpiAwareness.cpp" />

View File

@ -708,6 +708,9 @@
<ClInclude Include="Win32\DpiAwareness.h"> <ClInclude Include="Win32\DpiAwareness.h">
<Filter>Header Files\Win32</Filter> <Filter>Header Files\Win32</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Overlay\Steam.h">
<Filter>Header Files\Overlay</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp"> <ClCompile Include="Gdi\Gdi.cpp">
@ -1106,6 +1109,9 @@
<ClCompile Include="Win32\DpiAwareness.cpp"> <ClCompile Include="Win32\DpiAwareness.cpp">
<Filter>Source Files\Win32</Filter> <Filter>Source Files\Win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Overlay\Steam.cpp">
<Filter>Source Files\Overlay</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="DDrawCompat.rc"> <ResourceCompile Include="DDrawCompat.rc">

View File

@ -10,6 +10,7 @@ namespace Dll
HMODULE g_origDciman32Module = nullptr; HMODULE g_origDciman32Module = nullptr;
Procs g_origProcs = {}; Procs g_origProcs = {};
Procs g_jmpTargetProcs = {}; Procs g_jmpTargetProcs = {};
Procs g_newProcs = {};
bool g_isHooked = false; bool g_isHooked = false;
HANDLE createThread(unsigned(__stdcall* threadProc)(void*), unsigned int* threadId, int priority, unsigned initFlags) HANDLE createThread(unsigned(__stdcall* threadProc)(void*), unsigned int* threadId, int priority, unsigned initFlags)

View File

@ -80,6 +80,7 @@ namespace Dll
extern HMODULE g_origDciman32Module; extern HMODULE g_origDciman32Module;
extern Procs g_origProcs; extern Procs g_origProcs;
extern Procs g_jmpTargetProcs; extern Procs g_jmpTargetProcs;
extern Procs g_newProcs;
extern bool g_isHooked; extern bool g_isHooked;
} }

View File

@ -27,6 +27,7 @@
#include <Gdi/PresentationWindow.h> #include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Input/Input.h> #include <Input/Input.h>
#include <Overlay/Steam.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h> #include <Win32/DpiAwareness.h>
#include <Win32/MemoryManagement.h> #include <Win32/MemoryManagement.h>
@ -82,7 +83,9 @@ namespace
{ {
if (!Dll::g_isHooked) if (!Dll::g_isHooked)
{ {
Dll::g_isHooked = true;
DDraw::SuppressResourceFormatLogs suppressResourceFormatLogs; DDraw::SuppressResourceFormatLogs suppressResourceFormatLogs;
Overlay::Steam::installHooks();
LOG_INFO << "Installing display mode hooks"; LOG_INFO << "Installing display mode hooks";
Win32::DisplayMode::installHooks(); Win32::DisplayMode::installHooks();
LOG_INFO << "Installing registry hooks"; LOG_INFO << "Installing registry hooks";
@ -129,7 +132,6 @@ namespace
Gdi::installHooks(); Gdi::installHooks();
Compat::closeDbgEng(); Compat::closeDbgEng();
LOG_INFO << "Finished installing hooks"; LOG_INFO << "Finished installing hooks";
Dll::g_isHooked = true;
} }
} }
@ -244,6 +246,8 @@ namespace
Dll::g_origProcs.proc = Compat::getProcAddress(origModule, #proc); Dll::g_origProcs.proc = Compat::getProcAddress(origModule, #proc);
#define HOOK_DDRAW_PROC(proc) \ #define HOOK_DDRAW_PROC(proc) \
Dll::g_newProcs.proc = reinterpret_cast<FARPROC>( \
static_cast<decltype(&proc)>(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>)); \
Compat::hookFunction( \ Compat::hookFunction( \
reinterpret_cast<void*&>(Dll::g_origProcs.proc), \ reinterpret_cast<void*&>(Dll::g_origProcs.proc), \
static_cast<decltype(&proc)>(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>), \ static_cast<decltype(&proc)>(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>), \
@ -302,7 +306,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return FALSE; 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) if (!Dll::g_origDDrawModule)
{ {
LOG_INFO << "ERROR: Failed to load system ddraw.dll from " << systemPath.u8string(); 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; Dll::g_jmpTargetProcs = Dll::g_origProcs;
Overlay::Steam::init(origDDrawModulePath.c_str());
VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC); VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC);
Compat::hookFunction(reinterpret_cast<void*&>(Dll::g_origProcs.SetAppCompatData), Compat::hookFunction(reinterpret_cast<void*&>(Dll::g_origProcs.SetAppCompatData),

View File

@ -13,6 +13,7 @@
#include <Gdi/WinProc.h> #include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Overlay/Steam.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h> #include <Win32/DpiAwareness.h>
@ -178,16 +179,13 @@ namespace
LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 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) if (WM_USER_EXECUTE == uMsg)
{ {
auto& func = *reinterpret_cast<const std::function<void()>*>(lParam); auto& func = *reinterpret_cast<const std::function<void()>*>(lParam);
func(); func();
return LOG_RESULT(0); return 0;
} }
return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam);
return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam));
} }
unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/) unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/)
@ -230,7 +228,6 @@ namespace
MSG msg = {}; MSG msg = {};
while (CALL_ORIG_FUNC(GetMessageA)(&msg, nullptr, 0, 0)) while (CALL_ORIG_FUNC(GetMessageA)(&msg, nullptr, 0, 0))
{ {
TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
@ -276,6 +273,7 @@ namespace Gdi
void destroyWindow(HWND hwnd) void destroyWindow(HWND hwnd)
{ {
Overlay::Steam::onDestroyWindow(hwnd);
PostMessage(hwnd, WM_CLOSE, 0, 0); PostMessage(hwnd, WM_CLOSE, 0, 0);
} }

View File

@ -12,7 +12,7 @@ namespace
LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
LOG_FUNC("presentationWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, 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([&]() GuiThread::execute([&]()
{ {
presentationWindow = GuiThread::createWindow( 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<const wchar_t*>(g_classAtom), reinterpret_cast<const wchar_t*>(g_classAtom),
nullptr, nullptr,
WS_DISABLED | WS_POPUP, WS_DISABLED | WS_POPUP,
@ -56,6 +56,7 @@ namespace Gdi
WNDCLASS wc = {}; WNDCLASS wc = {};
wc.lpfnWndProc = &presentationWindowProc; wc.lpfnWndProc = &presentationWindowProc;
wc.hInstance = Dll::g_currentModule; wc.hInstance = Dll::g_currentModule;
wc.hCursor = CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_ARROW);
wc.lpszClassName = "DDrawCompatPresentationWindow"; wc.lpszClassName = "DDrawCompatPresentationWindow";
g_classAtom = CALL_ORIG_FUNC(RegisterClassA)(&wc); g_classAtom = CALL_ORIG_FUNC(RegisterClassA)(&wc);
} }

View File

@ -206,22 +206,22 @@ namespace
{ {
case HTLEFT: case HTLEFT:
case HTRIGHT: case HTRIGHT:
SetCursor(LoadCursor(nullptr, IDC_SIZEWE)); SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZEWE));
return TRUE; return TRUE;
case HTTOP: case HTTOP:
case HTBOTTOM: case HTBOTTOM:
SetCursor(LoadCursor(nullptr, IDC_SIZENS)); SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENS));
return TRUE; return TRUE;
case HTTOPLEFT: case HTTOPLEFT:
case HTBOTTOMRIGHT: case HTBOTTOMRIGHT:
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE)); SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENWSE));
return TRUE; return TRUE;
case HTBOTTOMLEFT: case HTBOTTOMLEFT:
case HTTOPRIGHT: case HTTOPRIGHT:
SetCursor(LoadCursor(nullptr, IDC_SIZENESW)); SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_SIZENESW));
return TRUE; return TRUE;
} }
@ -247,7 +247,7 @@ namespace
} }
else else
{ {
SetCursor(LoadCursor(nullptr, IDC_ARROW)); SetCursor(CALL_ORIG_FUNC(LoadCursorA)(nullptr, IDC_ARROW));
} }
return FALSE; return FALSE;
} }
@ -530,7 +530,7 @@ namespace
case WM_SETCURSOR: case WM_SETCURSOR:
if (CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP)) 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; return TRUE;
} }

View File

@ -153,19 +153,13 @@ namespace Gdi
return nullptr; return nullptr;
} }
auto resource = DDraw::DirectDrawSurface::getDriverResourceHandle(*primary); auto repo = DDraw::DirectDrawSurface::getSurfaceRepository(*DDraw::PrimarySurface::getPrimary());
if (!resource) if (!repo)
{ {
return nullptr; return nullptr;
} }
auto device = D3dDdi::Device::findDeviceByResource(resource); auto dd(repo->getDirectDraw());
if (!device)
{
return nullptr;
}
auto dd(device->getRepo().getDirectDraw());
if (!dd) if (!dd)
{ {
return nullptr; return nullptr;

View File

@ -17,6 +17,7 @@
#include <Gdi/PresentationWindow.h> #include <Gdi/PresentationWindow.h>
#include <Input/Input.h> #include <Input/Input.h>
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/Steam.h>
#include <Overlay/Window.h> #include <Overlay/Window.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
@ -157,6 +158,12 @@ namespace
return 1; return 1;
} }
} }
auto steamWindow = Overlay::Steam::getWindow();
if (steamWindow)
{
PostMessage(steamWindow, wParam, llHook->vkCode, 0);
}
} }
} }
return CallNextHookEx(nullptr, nCode, wParam, lParam); return CallNextHookEx(nullptr, nCode, wParam, lParam);

View File

@ -32,6 +32,7 @@
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/SettingControl.h> #include <Overlay/SettingControl.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Overlay/Steam.h>
namespace namespace
{ {
@ -275,6 +276,11 @@ namespace Overlay
{ {
if (isVisible != Window::isVisible()) if (isVisible != Window::isVisible())
{ {
if (isVisible && Overlay::Steam::isOverlayOpen())
{
return;
}
Window::setVisible(isVisible); Window::setVisible(isVisible);
Input::setCapture(isVisible ? this : nullptr); Input::setCapture(isVisible ? this : nullptr);
setFocus(nullptr); setFocus(nullptr);

View File

@ -0,0 +1,395 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Common/Time.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <Dll/Dll.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/Cursor.h>
#include <Gdi/GuiThread.h>
#include <Overlay/ConfigWindow.h>
#include <Overlay/Steam.h>
#include <Win32/DpiAwareness.h>
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<BYTE*>(static_cast<const BYTE*>(lpBaseAddress));
if ((Dll::g_jmpTargetProcs.DirectDrawCreate == lpBaseAddress ||
Dll::g_jmpTargetProcs.DirectDrawCreateEx == lpBaseAddress) &&
0xE9 == hookedFunc[0] && 5 == dwSize)
{
int& jmpOffset = *reinterpret_cast<int*>(hookedFunc + 1);
decltype(&DirectDrawCreateEx) directDrawCreateEx = nullptr;
if (!g_steamDirectDrawCreateEx && Dll::g_jmpTargetProcs.DirectDrawCreateEx == lpBaseAddress)
{
directDrawCreateEx = reinterpret_cast<decltype(&DirectDrawCreateEx)>(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<BYTE*>(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<BYTE*>(hookedFunc);
while (0xE9 == targetFunc[0])
{
targetFunc += 5 + *reinterpret_cast<int*>(targetFunc + 1);
}
return targetFunc;
}
template <typename Intf>
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<void**>(&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<void**>(&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<decltype(&DirectDrawCreateEx)>(
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();
}
}
}

View File

@ -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);
}
}