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:
parent
f1f775aaa4
commit
79d2eea9e3
@ -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<unsigned>(endOffset - g_debugBase);
|
||||
}
|
||||
|
||||
void hookFunction(void*& origFuncPtr, void* newFuncPtr, const char* funcName)
|
||||
{
|
||||
BYTE* targetFunc = static_cast<BYTE*>(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<char*>(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<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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 <auto origFunc>
|
||||
decltype(origFunc) g_origFuncPtr = origFunc;
|
||||
|
@ -58,6 +58,8 @@ namespace D3dDdi
|
||||
, m_origVtable(CompatVtable<D3DDDI_ADAPTERFUNCS>::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<IDirectDraw7> repository, bool isPrimary)
|
||||
void Adapter::setRepository(LUID luid, GUID* guid, CompatWeakPtr<IDirectDraw7> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<IDirectDraw7> repository, bool isPrimary);
|
||||
static void setRepository(LUID luid, GUID* guid, CompatWeakPtr<IDirectDraw7> 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<IDirectDraw7> m_repository;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <D3dDdi/Log/DeviceFuncsLog.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/ShaderAssembler.h>
|
||||
#include <Overlay/Steam.h>
|
||||
#include <Shaders/VertexFixup.h>
|
||||
|
||||
#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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <Gdi/Palette.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Overlay/Steam.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -57,8 +57,7 @@ namespace D3dDdi
|
||||
CompatWeakPtr<IDirectDrawSurface7> getWindowedPrimary();
|
||||
CompatPtr<IDirectDrawSurface7> getWindowedSrc(RECT rect);
|
||||
void release(Surface& surface);
|
||||
void setAsPrimaryRepo();
|
||||
void setRepository(CompatWeakPtr<IDirectDraw7> dd) { m_dd = dd; }
|
||||
void setRepository(CompatWeakPtr<IDirectDraw7> dd);
|
||||
|
||||
static SurfaceRepository& get(const Adapter& adapter);
|
||||
static SurfaceRepository& getPrimaryRepo();
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <ddraw.h>
|
||||
#include <ddrawi.h>
|
||||
@ -12,18 +13,26 @@ namespace DDraw
|
||||
{
|
||||
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);
|
||||
void hookDDrawWindowProc(WNDPROC ddrawWndProc);
|
||||
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);
|
||||
void suppressEmulatedDirectDraw(GUID*& guid);
|
||||
|
||||
template <typename TDirectDraw>
|
||||
template <typename TDirectDraw, typename = std::enable_if_t<IsDirectDraw<TDirectDraw>::value>>
|
||||
DDRAWI_DIRECTDRAW_INT& getInt(TDirectDraw& 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)
|
||||
{
|
||||
return &reinterpret_cast<HWND>(getInt(dd).lpLcl->hWnd);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <DDraw/Surfaces/Surface.h>
|
||||
#include <DDraw/Surfaces/SurfaceImpl.h>
|
||||
#include <DDraw/Visitors/DirectDrawSurfaceVtblVisitor.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
|
||||
#define SET_COMPAT_METHOD(method) \
|
||||
vtable.method = &callImpl<decltype(&DDraw::SurfaceImpl<TSurface>::method), &DDraw::SurfaceImpl<TSurface>::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 <typename Vtable>
|
||||
void hookVtable(const Vtable& vtable)
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
@ -8,36 +9,58 @@
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <Common/CompatRef.h>
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
class SurfaceRepository;
|
||||
}
|
||||
|
||||
namespace DDraw
|
||||
{
|
||||
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);
|
||||
|
||||
template <typename TSurface>
|
||||
template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
|
||||
DDRAWI_DDRAWSURFACE_INT& getInt(TSurface& 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)
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(getInt(surface).lpLcl->hDDSurface);
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HANDLE getDriverResourceHandle(TSurface& surface)
|
||||
template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
|
||||
HANDLE& getDriverResourceHandle(TSurface& surface)
|
||||
{
|
||||
return reinterpret_cast<HANDLE*>(getRuntimeResourceHandle(surface))[0];
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
UINT getSubResourceIndex(TSurface& surface)
|
||||
template <typename TSurface, typename = std::enable_if_t<IsSurface<TSurface>::value>>
|
||||
UINT& getSubResourceIndex(TSurface& surface)
|
||||
{
|
||||
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>
|
||||
void hookVtable(const Vtable& vtable);
|
||||
}
|
||||
|
@ -97,9 +97,6 @@ namespace DDraw
|
||||
{
|
||||
void installHooks(CompatPtr<IDirectDraw7> dd7)
|
||||
{
|
||||
DDraw::DirectDraw::onCreate(nullptr, *dd7);
|
||||
RealPrimarySurface::init();
|
||||
|
||||
g_origInitialize = dd7.get()->lpVtbl->Initialize;
|
||||
Compat::hookFunction(reinterpret_cast<void*&>(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();
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/StatsWindow.h>
|
||||
#include <Overlay/Steam.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/DpiAwareness.h>
|
||||
#include <Win32/Thread.h>
|
||||
@ -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;
|
||||
|
||||
{
|
||||
|
@ -325,6 +325,7 @@
|
||||
<ClInclude Include="Overlay\StatsEventRate.h" />
|
||||
<ClInclude Include="Overlay\StatsTimer.h" />
|
||||
<ClInclude Include="Overlay\StatsWindow.h" />
|
||||
<ClInclude Include="Overlay\Steam.h" />
|
||||
<ClInclude Include="Overlay\Window.h" />
|
||||
<ClInclude Include="Win32\DisplayMode.h" />
|
||||
<ClInclude Include="Win32\DpiAwareness.h" />
|
||||
@ -459,6 +460,7 @@
|
||||
<ClCompile Include="Overlay\StatsEventRate.cpp" />
|
||||
<ClCompile Include="Overlay\StatsTimer.cpp" />
|
||||
<ClCompile Include="Overlay\StatsWindow.cpp" />
|
||||
<ClCompile Include="Overlay\Steam.cpp" />
|
||||
<ClCompile Include="Overlay\Window.cpp" />
|
||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||
<ClCompile Include="Win32\DpiAwareness.cpp" />
|
||||
|
@ -708,6 +708,9 @@
|
||||
<ClInclude Include="Win32\DpiAwareness.h">
|
||||
<Filter>Header Files\Win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\Steam.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -1106,6 +1109,9 @@
|
||||
<ClCompile Include="Win32\DpiAwareness.cpp">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\Steam.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DDrawCompat.rc">
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/Steam.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/DpiAwareness.h>
|
||||
#include <Win32/MemoryManagement.h>
|
||||
@ -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<FARPROC>( \
|
||||
static_cast<decltype(&proc)>(&directDrawFunc<&Dll::Procs::proc, decltype(&proc)>)); \
|
||||
Compat::hookFunction( \
|
||||
reinterpret_cast<void*&>(Dll::g_origProcs.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;
|
||||
}
|
||||
|
||||
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<void*&>(Dll::g_origProcs.SetAppCompatData),
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/StatsWindow.h>
|
||||
#include <Overlay/Steam.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/DpiAwareness.h>
|
||||
|
||||
@ -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<const std::function<void()>*>(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);
|
||||
}
|
||||
|
||||
|
@ -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<const wchar_t*>(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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/Steam.h>
|
||||
#include <Overlay/Window.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
@ -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);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/SettingControl.h>
|
||||
#include <Overlay/StatsWindow.h>
|
||||
#include <Overlay/Steam.h>
|
||||
|
||||
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);
|
||||
|
395
DDrawCompat/Overlay/Steam.cpp
Normal file
395
DDrawCompat/Overlay/Steam.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
28
DDrawCompat/Overlay/Steam.h
Normal file
28
DDrawCompat/Overlay/Steam.h
Normal 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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user