Exemplo n.º 1
0
static ULONG __stdcall myRelease(IDirect3DDevice9 *idd) {
	Mutex m;

	DevMapType::iterator it = devMap.find(idd);
	DevState *ds = it != devMap.end() ? it->second : NULL;
	if (ds) {
		// Release is called very often. Thus, we do not want to always log here.
		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
		ods("D3D9: Using own Refcount implementation for call to Release.");
		#endif

		if (ds->dwMyThread == GetCurrentThreadId()) {
			ds->myRefCount--;
			return ds->initRefCount + ds->refCount;
		} else {
			ds->refCount--;
		}

		if (ds->refCount <= 1) {
			ds->disconnect();
		}

		if (ds->refCount >= 0) {
			return ds->initRefCount + ds->refCount;
		}

		ods("D3D9: Final release is following. MyRefs = %d, Tot = %d", ds->myRefCount, ds->refCount);

		if (ds->dwMyThread != 0) {
			ods("D3D9: finalRelease from other thread");
		}

		// Codeblock for stashing threadid
		{
			Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId());

			ds->releaseAll();
		}

		ods("D3D9: Final release of %p. MyRefs = %d Tot = %d", idd, ds->myRefCount, ds->refCount);

		devMap.erase(it);
		delete ds;
		ds = NULL;
	}

	//TODO: Move logic to HardHook.
	// Call base without active hook in case of no trampoline.
	ReleaseType oRelease = (ReleaseType) hhRelease.call;
	hhRelease.restore();
	ULONG res = oRelease(idd);
	hhRelease.inject();

	// Release is called very often. Thus, we do not want to always log here.
	#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
	ods("D3D9: Chained Release with result %d", res);
	#endif

	return res;
}
Exemplo n.º 2
0
static ULONG __stdcall myWin8AddRef(IDirect3DDevice9 *idd) {
	Mutex m;

	DevMapType::iterator it = devMap.find(idd);
	DevState *ds = it != devMap.end() ? it->second : NULL;
	if (ds && ds->dwMyThread == GetCurrentThreadId()) {
		// AddRef is called very often. Thus, we do not want to always log here.
		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
		ods("D3D9: Using own Refcount implementation for call to AddRef (Win8).");
		#endif

		ds->myRefCount++;
		return ds->refCount;
	}

	//TODO: Move logic to HardHook.
	// Call base without active hook in case of no trampoline.
	AddRefType oAddRef = (AddRefType) hhAddRef.call;
	hhAddRef.restore();
	ULONG res = oAddRef(idd);
	hhAddRef.inject();

	if (ds)
		ds->refCount = res;

	// AddRef is called very often. Thus, we do not want to always log here.
	#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
	ods("D3D9: Chained AddRef (Win8) with result %d", res);
	#endif

	return res;
}
Exemplo n.º 3
0
static HRESULT __stdcall myResetEx(IDirect3DDevice9Ex *idd, D3DPRESENT_PARAMETERS *param, D3DDISPLAYMODEEX *param2) {
	ods("D3D9: Chaining ResetEx");

	DevMapType::iterator it = devMap.find(idd);
	DevState *ds = it != devMap.end() ? it->second : NULL;
	if (ds) {
		if (ds->dwMyThread) {
			ods("D3D9: myResetEx from other thread");
		}
		Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId());

		ds->releaseAll();
	}

	//TODO: Move logic to HardHook.
	// Call base without active hook in case of no trampoline.
	ResetExType oResetEx = (ResetExType) hhResetEx.call;
	hhResetEx.restore();
	HRESULT hr = oResetEx(idd, param, param2);
	hhResetEx.inject();

	if (ds)
		ds->createCleanState();

	return hr;
}
Exemplo n.º 4
0
static void doPresent(IDirect3DDevice9 *idd) {
	DevMapType::iterator it = devMap.find(idd);
	DevState *ds = it != devMap.end() ? it->second : NULL;

	if (ds && ds->pSB) {
		if (ds->dwMyThread != 0) {
			ods("D3D9: doPresent from other thread");
		}
		Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId());

		IDirect3DSurface9 *pTarget = NULL;
		IDirect3DSurface9 *pRenderTarget = NULL;
		idd->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTarget);
		idd->GetRenderTarget(0, &pRenderTarget);

		// Present is called for each frame. Thus, we do not want to always log here.
		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
		ods("D3D9: doPresent BackB %p RenderT %p", pTarget, pRenderTarget);
		#endif

		IDirect3DStateBlock9* pStateBlock = NULL;
		idd->CreateStateBlock(D3DSBT_ALL, &pStateBlock);
		pStateBlock->Capture();

		ds->pSB->Apply();

		if (pTarget != pRenderTarget)
			idd->SetRenderTarget(0, pTarget);

		idd->BeginScene();
		ds->draw();
		idd->EndScene();

		pStateBlock->Apply();
		pStateBlock->Release();

		pRenderTarget->Release();
		pTarget->Release();

//		ods("D3D9: Finished ref is %d %d", ds->myRefCount, ds->refCount);
	}
}
Exemplo n.º 5
0
static HRESULT __stdcall myCreateDeviceEx(IDirect3D9Ex *id3d, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface) {
	Mutex m;
	ods("D3D9: Chaining CreateDeviceEx");

//	BehaviorFlags &= ~D3DCREATE_PUREDEVICE;

	//TODO: Move logic to HardHook.
	// Call base without active hook in case of no trampoline.
	CreateDeviceExType oCreateDeviceEx = (CreateDeviceExType) hhCreateDeviceEx.call;
	hhCreateDeviceEx.restore();
	HRESULT hr = oCreateDeviceEx(id3d, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, ppReturnedDeviceInterface);
	hhCreateDeviceEx.inject();

	if (FAILED(hr))
		return hr;

	IDirect3DDevice9Ex *idd = *ppReturnedDeviceInterface;

	DevState *ds = new DevState;
	ds->dev = idd;

	idd->AddRef();
	ds->initRefCount = idd->Release();

	DevMapType::iterator it = devMap.find(idd);
	if (it != devMap.end()) {
		ods("Device exists in devMap already - canceling injection into device. Thread prev: %d ; new: %d", it->second->dwMyThread, GetCurrentThreadId());
		delete ds;

		return hr;
	}
	devMap[idd] = ds;

	// The offsets are dependent on the declaration order of the struct.
	// See IDirect3DDevice9 (2nd, 3rd, 17th, 18th functions)
	const unsigned int offsetAddref = 1;
	const unsigned int offsetRelease = 2;
	const unsigned int offsetReset = 16;
	const unsigned int offsetPresent = 17;
	// On IDirect3DDevice9Ex
	const unsigned int offsetPresentEx = 121;
	const unsigned int offsetResetEx = 132;
	if (bIsWin8) {
		hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myWin8AddRef));
		hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myWin8Release));
	} else {
		hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myAddRef));
		hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myRelease));
	}
	hhReset.setupInterface(idd, offsetReset, reinterpret_cast<voidFunc>(myReset));
	hhResetEx.setupInterface(idd, offsetResetEx, reinterpret_cast<voidFunc>(myResetEx));
	hhPresent.setupInterface(idd, offsetPresent, reinterpret_cast<voidFunc>(myPresent));
	hhPresentEx.setupInterface(idd, offsetPresentEx, reinterpret_cast<voidFunc>(myPresentEx));

	IDirect3DSwapChain9 *pSwap = NULL;
	idd->GetSwapChain(0, &pSwap);
	if (pSwap) {
		// The offset is dependent on the declaration order of the struct.
		// See IDirect3DSwapChain9 (Present is the fourth function)
		const unsigned int offsetPresent = 3;
		hhSwapPresent.setupInterface(pSwap, offsetPresent, reinterpret_cast<voidFunc>(mySwapPresent));
		pSwap->Release();
	} else {
		ods("D3D9: Failed to get swapchain for DevEx");
	}

	ds->createCleanState();
	return hr;
}
Exemplo n.º 6
0
/// Present the overlay.
///
/// If called via IDirect3DDevice9::present() or IDirect3DDevice9Ex::present(),
/// idd will be non-NULL and ids ill be NULL.
///
/// If called via IDirect3DSwapChain9::present(), both idd and ids will be
/// non-NULL.
///
/// The doPresent function expects the following assumptions to be valid:
///
/// - Only one swap chain used at the same time.
/// - Windowed? IDirect3D9SwapChain::present() is used. ("Additional swap chain" is used)
/// - Full screen? IDirect3D9Device::present() is used. (Implicit swap chain for IDirect3D9Device is used)
///
/// It's either/or.
///
/// If doPresent is called multiple times per frame (say, for different swap chains),
/// the overlay will break badly when DevState::draw() is called. FPS counting will be off,
/// different render targets with different sizes will cause a size-renegotiation with Mumble
/// every frame, etc.
static void doPresent(IDirect3DDevice9 *idd, IDirect3DSwapChain9 *ids) {
	DevMapType::iterator it = devMap.find(idd);
	DevState *ds = it != devMap.end() ? it->second : NULL;
	HRESULT hres;

	if (ds && ds->pSB) {
		if (ds->dwMyThread != 0) {
			ods("D3D9: doPresent from other thread");
		}
		Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId());

		// Get the back buffer.
		// If we're called via IDirect3DSwapChain9, acquire it via the swap chain object.
		// Otherwise, acquire it via the device itself.
		IDirect3DSurface9 *pTarget = NULL;
		if (ids) {
			hres = ids->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pTarget);
			if (FAILED(hres)) {
				if (hres == D3DERR_INVALIDCALL) {
					ods("D3D9: IDirect3DSwapChain9::GetBackBuffer failed. BackBuffer index equals or exceeds the total number of back buffers");
				} else {
					ods("D3D9: IDirect3DSwapChain9::GetBackBuffer failed");
				}
			}
		} else {
			hres = idd->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTarget);
			if (FAILED(hres)) {
				if (hres == D3DERR_INVALIDCALL) {
					ods("D3D9: IDirect3DDevice9::GetBackBuffer failed. BackBuffer index equals or exceeds the total number of back buffers");
				} else {
					ods("D3D9: IDirect3DDevice9::GetBackBuffer failed");
				}
			}
		}

		IDirect3DSurface9 *pRenderTarget = NULL;
		hres = idd->GetRenderTarget(0, &pRenderTarget);
		if (FAILED(hres)) {
			if (hres == D3DERR_NOTFOUND) {
				ods("D3D9: IDirect3DDevice9::GetRenderTarget failed. There is no render target with the specified index");
			} else if (hres == D3DERR_INVALIDCALL) {
				ods("D3D9: IDirect3DDevice9::GetRenderTarget failed. One of the passed arguments was invalid");
			} else {
				ods("D3D9: IDirect3DDevice9::GetRenderTarget failed");
			}
		}

		// Present is called for each frame. Thus, we do not want to always log here.
		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
		ods("D3D9: doPresent BackB %p RenderT %p", pTarget, pRenderTarget);
		#endif

		IDirect3DStateBlock9* pStateBlock = NULL;
		idd->CreateStateBlock(D3DSBT_ALL, &pStateBlock);
		pStateBlock->Capture();

		ds->pSB->Apply();

		if (pTarget != pRenderTarget) {
			hres = idd->SetRenderTarget(0, pTarget);
			if (FAILED(hres)) {
				ods("D3D9: IDirect3DDevice9::SetRenderTarget failed");
			}
		}

		// If we're called via IDirect3DSwapChain9::present(), we have to
		// get the size of the back buffer and manually set the viewport size
		// to match it.
		//
		// Although the call to IDirect3DDevice9::SetRenderTarget() above is
		// documented as updating the device's viewport:
		//
		//     "Setting a new render target will cause the viewport (see Viewports
		//      and Clipping (Direct3D 9)) to be set to the full size of the new
		//      render target."
		//
		//  (via https://msdn.microsoft.com/en-us/library/windows/desktop/bb174455(v=vs.85).aspx)
		//
		// ...this doesn't happen. At least for some programs such as Final Fantasy XIV
		// and Battle.net Launcher. For these programs, we get a viewport of 1x1.
		//
		// The viewport we set here is used in the call below to DevState::draw()
		// as the full size of the screen/window.
		if (ids) {
			D3DPRESENT_PARAMETERS pp;
			hres = ids->GetPresentParameters(&pp);
			if (FAILED(hres)) {
				ods("D3D9: IDirect3DSwapChain9::GetPresentParameters failed");
			} else {
				if (pp.BackBufferWidth != 0 && pp.BackBufferHeight != 0) {
					D3DVIEWPORT9 vp;
					vp.X = 0;
					vp.Y = 0;
					vp.Width = pp.BackBufferWidth;
					vp.Height = pp.BackBufferHeight;
					vp.MinZ = 0.0f;
					vp.MaxZ = 1.0f;

					idd->SetViewport(&vp);
				}
			}
		}

		idd->BeginScene();
		ds->draw();
		idd->EndScene();

		pStateBlock->Apply();
		pStateBlock->Release();

		pRenderTarget->Release();
		pTarget->Release();

//		ods("D3D9: Finished ref is %d %d", ds->myRefCount, ds->refCount);
	}
}