1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #include "lib.h"
7 #include "overlay.hex"
8 #include <d3d10.h>
9 #include <time.h>
10 
11 D3D10Data *d3d10 = NULL;
12 
13 static bool bHooked = false;
14 static HardHook hhAddRef;
15 static HardHook hhRelease;
16 
17 typedef HRESULT(__stdcall *CreateDXGIFactoryType)(REFIID, void **);
18 typedef HRESULT(__stdcall *D3D10CreateDeviceAndSwapChainType)(IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT, UINT, DXGI_SWAP_CHAIN_DESC *, IDXGISwapChain **, ID3D10Device **);
19 
20 typedef HRESULT(__stdcall *D3D10CreateStateBlockType)(ID3D10Device *, D3D10_STATE_BLOCK_MASK *, ID3D10StateBlock **);
21 typedef HRESULT(__stdcall *D3D10StateBlockMaskEnableAllType)(D3D10_STATE_BLOCK_MASK *);
22 typedef HRESULT(__stdcall *D3D10CreateEffectFromMemoryType)(void *, SIZE_T, UINT, ID3D10Device *, ID3D10EffectPool *, ID3D10Effect **);
23 
24 typedef ULONG(__stdcall *AddRefType)(ID3D10Device *);
25 typedef ULONG(__stdcall *ReleaseType)(ID3D10Device *);
26 
27 #define HMODREF(mod, func) func##Type p##func = (func##Type) GetProcAddress(mod, #func)
28 
29 struct SimpleVec3 {
30 	FLOAT x;
31 	FLOAT y;
32 	FLOAT z;
SimpleVec3SimpleVec333 	SimpleVec3(FLOAT _x, FLOAT _y, FLOAT _z) : x(_x), y(_y), z(_z) {}
34 };
35 
36 struct SimpleVec2 {
37 	FLOAT x;
38 	FLOAT y;
SimpleVec2SimpleVec239 	SimpleVec2(FLOAT _x, FLOAT _y) : x(_x), y(_y) {}
40 };
41 
42 struct SimpleVertex {
43 	SimpleVec3 Pos;
44 	SimpleVec2 Tex;
45 };
46 
47 class D10State: protected Pipe {
48 	public:
49 		ULONG lHighMark;
50 
51 		LONG initRefCount;
52 		LONG refCount;
53 		LONG myRefCount;
54 
55 		D3D10_VIEWPORT vp;
56 
57 		ID3D10Device *pDevice;
58 		IDXGISwapChain *pSwapChain;
59 
60 		ID3D10StateBlock *pOrigStateBlock;
61 		ID3D10StateBlock *pMyStateBlock;
62 		ID3D10RenderTargetView *pRTV;
63 		ID3D10Effect *pEffect;
64 		ID3D10EffectTechnique *pTechnique;
65 		ID3D10EffectShaderResourceVariable * pDiffuseTexture;
66 		ID3D10InputLayout *pVertexLayout;
67 		ID3D10Buffer *pVertexBuffer;
68 		ID3D10Buffer *pIndexBuffer;
69 		ID3D10BlendState *pBlendState;
70 
71 		ID3D10Texture2D *pTexture;
72 		ID3D10ShaderResourceView *pSRView;
73 
74 		clock_t timeT;
75 		unsigned int frameCount;
76 
77 		D10State(IDXGISwapChain *, ID3D10Device *);
78 		virtual ~D10State();
79 		bool init();
80 		void draw();
81 
82 		virtual void blit(unsigned int x, unsigned int y, unsigned int w, unsigned int h);
83 		virtual void setRect();
84 		virtual void newTexture(unsigned int w, unsigned int h);
85 };
86 
87 typedef map<IDXGISwapChain *, D10State *> SwapchainMap;
88 SwapchainMap chains;
89 typedef map<ID3D10Device *, D10State *> DeviceMap;
90 DeviceMap devices;
91 
D10State(IDXGISwapChain * pSwapChain,ID3D10Device * pDevice)92 D10State::D10State(IDXGISwapChain *pSwapChain, ID3D10Device *pDevice) {
93 	this->pSwapChain = pSwapChain;
94 	this->pDevice = pDevice;
95 
96 	lHighMark = initRefCount  = refCount = myRefCount = 0;
97 	ZeroMemory(&vp, sizeof(vp));
98 
99 	pOrigStateBlock = NULL;
100 	pMyStateBlock = NULL;
101 	pRTV = NULL;
102 	pEffect = NULL;
103 	pTechnique = NULL;
104 	pDiffuseTexture = NULL;
105 	pVertexLayout = NULL;
106 	pVertexBuffer = NULL;
107 	pIndexBuffer = NULL;
108 	pBlendState = NULL;
109 	pTexture = NULL;
110 	pSRView = NULL;
111 
112 	timeT = clock();
113 	frameCount = 0;
114 
115 	pDevice->AddRef();
116 	initRefCount = pDevice->Release();
117 }
118 
blit(unsigned int x,unsigned int y,unsigned int w,unsigned int h)119 void D10State::blit(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
120 	HRESULT hr;
121 
122 	ods("D3D10: Blit %d %d %d %d", x, y, w, h);
123 
124 	if (! pTexture || ! pSRView || uiLeft == uiRight)
125 		return;
126 
127 	D3D10_MAPPED_TEXTURE2D mappedTex;
128 	hr = pTexture->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex);
129 	if (FAILED(hr)) {
130 		ods("D3D10: Failed map");
131 	}
132 
133 	UCHAR* pTexels = (UCHAR*)mappedTex.pData;
134 
135 	for (unsigned int r=0;r< uiHeight; ++r) {
136 		unsigned char *sptr = a_ucTexture + r * uiWidth * 4;
137 		unsigned char *dptr = reinterpret_cast<unsigned char *>(pTexels) + r * mappedTex.RowPitch;
138 		memcpy(dptr, sptr, uiWidth * 4);
139 	}
140 
141 	pTexture->Unmap(D3D10CalcSubresource(0, 0, 1));
142 }
143 
setRect()144 void D10State::setRect() {
145 	HRESULT hr;
146 
147 	ods("D3D10: SetRect");
148 
149 	float w = static_cast<float>(uiWidth);
150 	float h = static_cast<float>(uiHeight);
151 
152 	float left   = static_cast<float>(uiLeft) - 0.5f;
153 	float top    = static_cast<float>(uiTop) - 0.5f;
154 	float right  = static_cast<float>(uiRight) + 0.5f;
155 	float bottom = static_cast<float>(uiBottom) + 0.5f;
156 
157 	float texl = (left) / w;
158 	float text = (top) / h;
159 	float texr = (right + 1.0f) / w;
160 	float texb = (bottom + 1.0f) / h;
161 
162 	left = 2.0f * (left / vp.Width) - 1.0f;
163 	right = 2.0f * (right / vp.Width) - 1.0f;
164 	top = -2.0f * (top / vp.Height) + 1.0f;
165 	bottom = -2.0f * (bottom / vp.Height) + 1.0f;
166 
167 	ods("D3D10: Vertex (%f %f) (%f %f)", left, top, right, bottom);
168 
169 	// Create vertex buffer
170 	SimpleVertex vertices[] = {
171 		{ SimpleVec3(left, top, 0.5f), SimpleVec2(texl, text) },
172 		{ SimpleVec3(right, top, 0.5f), SimpleVec2(texr, text) },
173 		{ SimpleVec3(right, bottom, 0.5f), SimpleVec2(texr, texb) },
174 		{ SimpleVec3(left, bottom, 0.5f), SimpleVec2(texl, texb) },
175 	};
176 
177 	void *pData = NULL;
178 
179 	hr = pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pData);
180 	memcpy(pData, vertices, sizeof(vertices));
181 	ods("D3D10: Map %lx %d", hr, sizeof(vertices));
182 	pVertexBuffer->Unmap();
183 }
184 
newTexture(unsigned int w,unsigned int h)185 void D10State::newTexture(unsigned int w, unsigned int h) {
186 	HRESULT hr;
187 
188 	ods("D3D10: newTexture %d %d", w, h);
189 
190 	if (pTexture) {
191 		pTexture->Release();
192 		pTexture = NULL;
193 	}
194 	if (pSRView) {
195 		pSRView->Release();
196 		pSRView = NULL;
197 	}
198 
199 	D3D10_TEXTURE2D_DESC desc;
200 	ZeroMemory(&desc, sizeof(desc));
201 
202 	desc.Width = w;
203 	desc.Height = h;
204 	desc.MipLevels = desc.ArraySize = 1;
205 	desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
206 	desc.SampleDesc.Count = 1;
207 	desc.Usage = D3D10_USAGE_DYNAMIC;
208 	desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
209 	desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
210 	hr = pDevice->CreateTexture2D(&desc, NULL, &pTexture);
211 
212 	if (FAILED(hr)) {
213 		pTexture = NULL;
214 		ods("D3D10: Failed to create texture.");
215 		return;
216 	}
217 
218 	D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
219 	ZeroMemory(&srvDesc, sizeof(srvDesc));
220 	srvDesc.Format = desc.Format;
221 	srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
222 	srvDesc.Texture2D.MostDetailedMip = 0;
223 	srvDesc.Texture2D.MipLevels = desc.MipLevels;
224 
225 	hr = pDevice->CreateShaderResourceView(pTexture, &srvDesc, &pSRView);
226 	if (FAILED(hr)) {
227 		pSRView = NULL;
228 		pTexture->Release();
229 		pTexture = NULL;
230 		ods("D3D10: Failed to create resource view.");
231 		return;
232 	}
233 }
234 
init()235 bool D10State::init() {
236 	static HMODREF(GetModuleHandleW(L"D3D10.DLL"), D3D10CreateEffectFromMemory);
237 	static HMODREF(GetModuleHandleW(L"D3D10.DLL"), D3D10CreateStateBlock);
238 	static HMODREF(GetModuleHandleW(L"D3D10.DLL"), D3D10StateBlockMaskEnableAll);
239 
240 	if (pD3D10CreateEffectFromMemory == NULL
241 	    || pD3D10CreateStateBlock == NULL
242 	    || pD3D10StateBlockMaskEnableAll == NULL) {
243 		ods("D3D10: Could not get handles for all required D3D10 state initialization functions");
244 		return false;
245 	}
246 
247 	HRESULT hr;
248 
249 	D3D10_STATE_BLOCK_MASK StateBlockMask;
250 	ZeroMemory(&StateBlockMask, sizeof(StateBlockMask));
251 	hr = pD3D10StateBlockMaskEnableAll(&StateBlockMask);
252 	if (FAILED(hr)) {
253 		ods("D3D10: D3D10StateBlockMaskEnableAll failed");
254 		return false;
255 	}
256 
257 	hr = pD3D10CreateStateBlock(pDevice, &StateBlockMask, &pOrigStateBlock);
258 	if (FAILED(hr)) {
259 		ods("D3D10: D3D10CreateStateBlock for pOrigStateBlock failed");
260 		return false;
261 	}
262 
263 	hr = pD3D10CreateStateBlock(pDevice, &StateBlockMask, &pMyStateBlock);
264 	if (FAILED(hr)) {
265 		ods("D3D10: D3D10CreateStateBlock for pMyStateBlock failed");
266 		return false;
267 	}
268 
269 	hr = pOrigStateBlock->Capture();
270 	if (FAILED(hr)) {
271 		ods("D3D10: Failed to store original state block during init");
272 		return false;
273 	}
274 
275 	ID3D10Texture2D *pBackBuffer = NULL;
276 	hr = pSwapChain->GetBuffer(0, __uuidof(*pBackBuffer), (LPVOID*)&pBackBuffer);
277 	if (FAILED(hr)) {
278 		ods("D3D10: pSwapChain->GetBuffer failure!");
279 		return false;
280 	}
281 
282 	pDevice->ClearState();
283 
284 	D3D10_TEXTURE2D_DESC backBufferSurfaceDesc;
285 	pBackBuffer->GetDesc(&backBufferSurfaceDesc);
286 
287 	ZeroMemory(&vp, sizeof(vp));
288 	vp.Width = backBufferSurfaceDesc.Width;
289 	vp.Height = backBufferSurfaceDesc.Height;
290 	vp.MinDepth = 0;
291 	vp.MaxDepth = 1;
292 	vp.TopLeftX = 0;
293 	vp.TopLeftY = 0;
294 	pDevice->RSSetViewports(1, &vp);
295 
296 	hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRTV);
297 	if (FAILED(hr)) {
298 		ods("D3D10: pDevice->CreateRenderTargetView failed!");
299 		return false;
300 	}
301 
302 	pDevice->OMSetRenderTargets(1, &pRTV, NULL);
303 
304 	// Settings for an "over" operation.
305 	// https://en.wikipedia.org/w/index.php?title=Alpha_compositing&oldid=580659153#Description
306 	D3D10_BLEND_DESC blend;
307 	ZeroMemory(&blend, sizeof(blend));
308 	blend.BlendEnable[0] = TRUE;
309 	blend.SrcBlend = D3D10_BLEND_ONE;
310 	blend.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
311 	blend.BlendOp = D3D10_BLEND_OP_ADD;
312 	blend.SrcBlendAlpha = D3D10_BLEND_ONE;
313 	blend.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
314 	blend.BlendOpAlpha = D3D10_BLEND_OP_ADD;
315 	blend.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
316 
317 	hr = pDevice->CreateBlendState(&blend, &pBlendState);
318 	if (FAILED(hr)) {
319 		ods("D3D10: pDevice->CreateBlendState failed!");
320 		return false;
321 	}
322 
323 	pDevice->OMSetBlendState(pBlendState, NULL, 0xffffffff);
324 
325 	hr = pD3D10CreateEffectFromMemory((void *) g_main, sizeof(g_main), 0, pDevice, NULL, &pEffect);
326 	if (FAILED(hr)) {
327 		ods("D3D10: D3D10CreateEffectFromMemory failed!");
328 		return false;
329 	}
330 
331 	pTechnique = pEffect->GetTechniqueByName("Render");
332 	if (pTechnique == NULL) {
333 		ods("D3D10: Could not get technique for name 'Render'");
334 		return false;
335 	}
336 
337 	pDiffuseTexture = pEffect->GetVariableByName("txDiffuse")->AsShaderResource();
338 	if (pDiffuseTexture == NULL) {
339 		ods("D3D10: Could not get variable by name 'txDiffuse'");
340 		return false;
341 	}
342 
343 	pTexture = NULL;
344 	pSRView = NULL;
345 
346 	// Define the input layout
347 	D3D10_INPUT_ELEMENT_DESC layout[] = {
348 		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
349 		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
350 	};
351 	UINT numElements = sizeof(layout) / sizeof(layout[0]);
352 
353 	// Create the input layout
354 	D3D10_PASS_DESC PassDesc;
355 	hr = pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
356 	if (FAILED(hr)) {
357 		ods("D3D10: Couldn't get pass description for technique");
358 		return false;
359 	}
360 
361 	hr = pDevice->CreateInputLayout(layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pVertexLayout);
362 	if (FAILED(hr)) {
363 		ods("D3D10: pDevice->CreateInputLayout failure!");
364 		return false;
365 	}
366 
367 	pDevice->IASetInputLayout(pVertexLayout);
368 
369 	D3D10_BUFFER_DESC bd;
370 	ZeroMemory(&bd, sizeof(bd));
371 	bd.Usage = D3D10_USAGE_DYNAMIC;
372 	bd.ByteWidth = sizeof(SimpleVertex) * 4;
373 	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
374 	bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
375 	bd.MiscFlags = 0;
376 
377 	hr = pDevice->CreateBuffer(&bd, NULL, &pVertexBuffer);
378 	if (FAILED(hr)) {
379 		ods("D3D10: pDevice->CreateBuffer failure!");
380 		return false;
381 	}
382 
383 	DWORD indices[] = {
384 		0,1,3,
385 		1,2,3,
386 	};
387 
388 	bd.Usage = D3D10_USAGE_DEFAULT;
389 	bd.ByteWidth = sizeof(DWORD) * 6;
390 	bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
391 	bd.CPUAccessFlags = 0;
392 	bd.MiscFlags = 0;
393 	D3D10_SUBRESOURCE_DATA InitData;
394 	ZeroMemory(&InitData, sizeof(InitData));
395 	InitData.pSysMem = indices;
396 
397 	hr = pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer);
398 	if (FAILED(hr)) {
399 		ods("D3D10: pDevice->CreateBuffer failure!");
400 		return false;
401 	}
402 
403 	// Set index buffer
404 	pDevice->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
405 
406 	// Set primitive topology
407 	pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
408 
409 	hr = pMyStateBlock->Capture();
410 	if (FAILED(hr)) {
411 		ods("D3D10: Failed to capture newly created state block");
412 		return false;
413 	}
414 
415 	hr = pOrigStateBlock->Apply();
416 	if (FAILED(hr)) {
417 		ods("D3D10: Failed to restore original state block during init");
418 		return false;
419 	}
420 
421 	pBackBuffer->Release();
422 
423 	return true;
424 }
425 
~D10State()426 D10State::~D10State() {
427 	if (pBlendState != NULL)    pBlendState->Release();
428 	if (pVertexBuffer != NULL)  pVertexBuffer->Release();
429 	if (pIndexBuffer != NULL)   pIndexBuffer->Release();
430 	if (pVertexLayout != NULL)  pVertexLayout->Release();
431 	if (pEffect != NULL)        pEffect->Release();
432 	if (pRTV != NULL)           pRTV->Release();
433 	if (pTexture != NULL)       pTexture->Release();
434 	if (pSRView != NULL)        pSRView->Release();
435 
436 	if (pMyStateBlock) {
437 		pMyStateBlock->ReleaseAllDeviceObjects();
438 		pMyStateBlock->Release();
439 	}
440 
441 	if (pOrigStateBlock) {
442 		pOrigStateBlock->ReleaseAllDeviceObjects();
443 		pOrigStateBlock->Release();
444 	}
445 }
446 
draw()447 void D10State::draw() {
448 	clock_t t = clock();
449 	float elapsed = static_cast<float>(t - timeT) / CLOCKS_PER_SEC;
450 	++frameCount;
451 	if (elapsed > OVERLAY_FPS_INTERVAL) {
452 		OverlayMsg om;
453 		om.omh.uiMagic = OVERLAY_MAGIC_NUMBER;
454 		om.omh.uiType = OVERLAY_MSGTYPE_FPS;
455 		om.omh.iLength = sizeof(OverlayMsgFps);
456 		om.omf.fps = frameCount / elapsed;
457 
458 		sendMessage(om);
459 
460 		frameCount = 0;
461 		timeT = t;
462 	}
463 
464 	checkMessage(vp.Width, vp.Height);
465 
466 	if (a_ucTexture && pSRView && (uiLeft != uiRight)) {
467 		HRESULT hr;
468 		pOrigStateBlock->Capture();
469 		pMyStateBlock->Apply();
470 
471 		D3D10_TECHNIQUE_DESC techDesc;
472 		pTechnique->GetDesc(&techDesc);
473 
474 		// Set vertex buffer
475 		UINT stride = sizeof(SimpleVertex);
476 		UINT offset = 0;
477 		pDevice->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
478 
479 		hr = pDiffuseTexture->SetResource(pSRView);
480 		if (FAILED(hr))
481 			ods("D3D10: Failed to set resource");
482 
483 		for (UINT p = 0; p < techDesc.Passes; ++p) {
484 			pTechnique->GetPassByIndex(p)->Apply(0);
485 			pDevice->DrawIndexed(6, 0, 0);
486 		}
487 		pOrigStateBlock->Apply();
488 	}
489 }
490 
491 // D3D10 specific logic for the Present function.
presentD3D10(IDXGISwapChain * pSwapChain)492 void presentD3D10(IDXGISwapChain *pSwapChain) {
493 
494 	ID3D10Device *pDevice = NULL;
495 	HRESULT hr = pSwapChain->GetDevice(__uuidof(ID3D10Device), (void **) &pDevice);
496 	if (SUCCEEDED(hr) && pDevice) {
497 		SwapchainMap::iterator it = chains.find(pSwapChain);
498 		D10State *ds = it != chains.end() ? it->second : NULL;
499 
500 		if (ds && ds->pDevice != pDevice) {
501 			ods("D3D10: SwapChain device changed");
502 			devices.erase(ds->pDevice);
503 			delete ds;
504 			ds = NULL;
505 		}
506 		if (ds == NULL) {
507 			ods("D3D10: New state");
508 			ds = new D10State(pSwapChain, pDevice);
509 			if (!ds->init()) {
510 				pDevice->Release();
511 				delete ds;
512 				return;
513 			}
514 
515 			chains[pSwapChain] = ds;
516 			devices[pDevice] = ds;
517 
518 		}
519 
520 		ds->draw();
521 		pDevice->Release();
522 	} else {
523 		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
524 		// DXGI is used for multiple D3D versions. Thus, it is possible a device
525 		// associated with the DXGISwapChain may very well not be a D3D10 one,
526 		// in which case we can safely ignore it.
527 		ods("D3D10: Could not draw because ID3D10Device could not be retrieved.");
528 		#endif
529 	}
530 }
531 
resizeD3D10(IDXGISwapChain * pSwapChain)532 void resizeD3D10(IDXGISwapChain *pSwapChain) {
533 	// Remove the D10State from our "cache" (= Invalidate)
534 	SwapchainMap::iterator it = chains.find(pSwapChain);
535 	if (it != chains.end()) {
536 		D10State *ds = it->second;
537 		devices.erase(ds->pDevice);
538 		chains.erase(it);
539 		delete ds;
540 	}
541 }
542 
myAddRef(ID3D10Device * pDevice)543 static ULONG __stdcall myAddRef(ID3D10Device *pDevice) {
544 	//TODO: Move logic to HardHook.
545 	// Call base without active hook in case of no trampoline.
546 	AddRefType oAddRef = (AddRefType) hhAddRef.call;
547 	hhAddRef.restore();
548 	ULONG res = oAddRef(pDevice);
549 	hhAddRef.inject();
550 
551 	Mutex m;
552 	DeviceMap::iterator it = devices.find(pDevice);
553 	if (it != devices.end()) {
554 		it->second->lHighMark = res;
555 	}
556 
557 	return res;
558 }
559 
myRelease(ID3D10Device * pDevice)560 static ULONG __stdcall myRelease(ID3D10Device *pDevice) {
561 	//TODO: Move logic to HardHook.
562 	// Call base without active hook in case of no trampoline.
563 	ReleaseType oRelease = (ReleaseType) hhRelease.call;
564 	hhRelease.restore();
565 	ULONG res = oRelease(pDevice);
566 	hhRelease.inject();
567 
568 	Mutex m;
569 	DeviceMap::iterator it = devices.find(pDevice);
570 	if (it != devices.end()) {
571 		D10State *ds = it->second;
572 		// If we are receiving a lot of subsequent releases lets eagerly drop
573 		// our state object. If the device presents something again a state
574 		// object is created again just fine anyway.
575 		if (res < ds->lHighMark / 2) {
576 			ods("D3D10: Deleting resources %u < 0.5 * %u", res, ds->lHighMark);
577 			devices.erase(it);
578 			chains.erase(ds->pSwapChain);
579 			delete ds;
580 			ods("D3D10: Deleted");
581 			ds = NULL;
582 		}
583 	}
584 
585 	return res;
586 }
587 
HookAddRelease(voidFunc vfAdd,voidFunc vfRelease)588 static void HookAddRelease(voidFunc vfAdd, voidFunc vfRelease) {
589 	ods("D3D10: Injecting device add/remove");
590 	hhAddRef.setup(vfAdd, reinterpret_cast<voidFunc>(myAddRef));
591 	hhRelease.setup(vfRelease, reinterpret_cast<voidFunc>(myRelease));
592 }
593 
594 static void hookD3D10(HMODULE hD3D10, bool preonly);
595 
checkDXGI10Hook(bool preonly)596 void checkDXGI10Hook(bool preonly) {
597 	static bool bCheckHookActive = false;
598 	if (bCheckHookActive) {
599 		ods("D3D10: Recursion in checkDXGI10Hook");
600 		return;
601 	}
602 
603 	if (d3d10->offsetAddRef == 0 || d3d10->offsetRelease == 0) {
604 		return;
605 	}
606 
607 	bCheckHookActive = true;
608 
609 	HMODULE hD3D10 = GetModuleHandleW(L"D3D10CORE.DLL");
610 
611 	if (hD3D10) {
612 		if (! bHooked) {
613 			hookD3D10(hD3D10, preonly);
614 		}
615 	} else {
616 		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
617 		if (hDXGI) {
618 			ods("D3D10: No DXGI.DLL found as loaded. No hooking at this point.");
619 		} else {
620 			ods("D3D10: No D3D10CORE.DLL found as loaded. No hooking at this point.");
621 		}
622 		#endif
623 	}
624 
625 	bCheckHookActive = false;
626 }
627 
628 /// @param hD3D10 must be a valid module handle
hookD3D10(HMODULE hD3D10,bool preonly)629 void hookD3D10(HMODULE hD3D10, bool preonly) {
630 
631 	// Add a ref to ourselves; we do NOT want to get unloaded directly from this process.
632 	HMODULE hTempSelf = NULL;
633 	GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCTSTR>(&hookD3D10), &hTempSelf);
634 
635 	bHooked = true;
636 
637 	wchar_t modulename[MODULEFILEPATH_BUFLEN];
638 	GetModuleFileNameW(hD3D10, modulename, ARRAY_NUM_ELEMENTS(modulename));
639 
640 	if (_wcsicmp(d3d10->wcFileName, modulename) == 0) {
641 		unsigned char *raw = (unsigned char *) hD3D10;
642 		HookAddRelease((voidFunc)(raw + d3d10->offsetAddRef), (voidFunc)(raw + d3d10->offsetRelease));
643 	} else if (! preonly) {
644 		ods("D3D10: Interface changed, can't rawpatch. Current: %ls ; Previously: %ls", modulename, d3d10->wcFileName);
645 	} else {
646 		bHooked = false;
647 	}
648 }
649 
650 /// Prepares DXGI and D3D10 data by trying to determining the module filepath
651 /// and function offsets in memory.
652 /// (This data can later be used for hooking / code injection.
653 ///
654 /// Adjusts the data behind the global variables dxgi and d3d10.
PrepareDXGI10(IDXGIAdapter1 * pAdapter,bool initializeDXGIData)655 void PrepareDXGI10(IDXGIAdapter1 *pAdapter, bool initializeDXGIData) {
656 
657 	if (!dxgi || !d3d10 || !pAdapter)
658 		return;
659 
660 	ods("D3D10: Preparing static data for DXGI and D3D10 Injection");
661 
662 	d3d10->wcFileName[0] = 0;
663 	d3d10->offsetAddRef = 0;
664 	d3d10->offsetRelease = 0;
665 
666 	HMODULE hD3D10 = LoadLibrary("D3D10.DLL");
667 
668 	if (hD3D10 != NULL) {
669 
670 		HWND hwnd = CreateWindowW(L"STATIC", L"Mumble DXGI Window", WS_OVERLAPPEDWINDOW,
671 								  CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0,
672 								  NULL, NULL, 0);
673 
674 		D3D10CreateDeviceAndSwapChainType pD3D10CreateDeviceAndSwapChain = reinterpret_cast<D3D10CreateDeviceAndSwapChainType>(GetProcAddress(hD3D10, "D3D10CreateDeviceAndSwapChain"));
675 
676 		DXGI_SWAP_CHAIN_DESC desc;
677 		ZeroMemory(&desc, sizeof(desc));
678 
679 		RECT rcWnd;
680 		GetClientRect(hwnd, &rcWnd);
681 		desc.BufferDesc.Width = rcWnd.right - rcWnd.left;
682 		desc.BufferDesc.Height = rcWnd.bottom - rcWnd.top;
683 
684 		ods("D3D10: Got ClientRect W %d H %d", desc.BufferDesc.Width, desc.BufferDesc.Height);
685 
686 		desc.BufferDesc.RefreshRate.Numerator = 60;
687 		desc.BufferDesc.RefreshRate.Denominator = 1;
688 		desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
689 		desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
690 		desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
691 
692 		desc.SampleDesc.Count = 1;
693 		desc.SampleDesc.Quality = 0;
694 
695 		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
696 
697 		desc.BufferCount = 2;
698 
699 		desc.OutputWindow = hwnd;
700 
701 		desc.Windowed = true;
702 
703 		desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
704 
705 		IDXGISwapChain *pSwapChain = NULL;
706 		ID3D10Device *pDevice = NULL;
707 		HRESULT hr = pD3D10CreateDeviceAndSwapChain(pAdapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &desc, &pSwapChain, &pDevice);
708 		if (FAILED(hr))
709 			ods("D3D10: pD3D10CreateDeviceAndSwapChain failure!");
710 
711 		if (pDevice && pSwapChain) {
712 
713 			// For VC++ the vtable is located at the base addr. of the object and each function entry is a single pointer. Since p.e. the base classes
714 			// of IDXGISwapChain have a total of 8 functions the 8+Xth entry points to the Xth added function in the derived interface.
715 
716 			void ***vtbl = (void ***) pSwapChain;
717 
718 			void *pPresent = (*vtbl)[8];
719 			boost::optional<size_t> offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pPresent), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "Present");
720 			if (offset) {
721 				if (initializeDXGIData) {
722 					dxgi->offsetPresent = *offset;
723 					ods("D3D10: Successfully found Present offset: %ls: %d", dxgi->wcFileName, dxgi->offsetPresent);
724 				} else {
725 					if (dxgi->offsetPresent == *offset) {
726 						ods("D3D10: Successfully verified Present offset: %ls: %d", dxgi->wcFileName, dxgi->offsetPresent);
727 					} else {
728 						ods("D3D10: Failed to verify Present offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->offsetPresent);
729 					}
730 				}
731 			}
732 
733 			void *pResize = (*vtbl)[13];
734 			offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pResize), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "ResizeBuffers");
735 			if (offset) {
736 				if (initializeDXGIData) {
737 					dxgi->offsetResize = *offset;
738 					ods("D3D10: Successfully found ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->offsetResize);
739 				} else {
740 					if (dxgi->offsetResize == *offset) {
741 						ods("D3D10: Successfully verified ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->offsetResize);
742 					} else {
743 						ods("D3D10: Failed to verify ResizeBuffers offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->offsetResize);
744 					}
745 				}
746 			}
747 
748 			vtbl = (void ***) pDevice;
749 
750 			void *pAddRef = (*vtbl)[1];
751 			offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pAddRef), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "AddRef");
752 			if (offset) {
753 				d3d10->offsetAddRef = *offset;
754 				ods("D3D10: Successfully found AddRef offset: %ls: %d", d3d10->wcFileName, d3d10->offsetAddRef);
755 			}
756 
757 			void *pRelease = (*vtbl)[2];
758 			offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pRelease), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "Release");
759 			if (offset) {
760 				d3d10->offsetRelease = *offset;
761 				ods("D3D10: Successfully found Release offset: %ls: %d", d3d10->wcFileName, d3d10->offsetRelease);
762 			}
763 		}
764 
765 		if (pDevice)
766 			pDevice->Release();
767 		if (pSwapChain)
768 			pSwapChain->Release();
769 		DestroyWindow(hwnd);
770 	} else {
771 		FreeLibrary(hD3D10);
772 	}
773 }
774