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 /* Copyright (C) 2010-2013, Benjamin Jemlich <pcgod@users.sourceforge.net>
7    Copyright (C) 2011-2013, Nye Liu <nyet@nyet.org>
8    Copyright (C) 2011-2013, Kissaki <kissaki@gmx.de>
9 
10    All rights reserved.
11 
12    Redistribution and use in source and binary forms, with or without
13    modification, are permitted provided that the following conditions
14    are met:
15 
16    - Redistributions of source code must retain the above copyright notice,
17      this list of conditions and the following disclaimer.
18    - Redistributions in binary form must reproduce the above copyright notice,
19      this list of conditions and the following disclaimer in the documentation
20      and/or other materials provided with the distribution.
21    - Neither the name of the Mumble Developers nor the names of its
22      contributors may be used to endorse or promote products derived from this
23      software without specific prior written permission.
24 
25    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
29    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 
38 #include "lib.h"
39 #include "D11StateBlock.h"
40 #include "overlay11.vs.h"
41 #include "overlay11.ps.h"
42 #include <d3d11.h>
43 #include <time.h>
44 
45 D3D11Data *d3d11 = NULL;
46 
47 static bool bHooked = false;
48 static HardHook hhAddRef;
49 static HardHook hhRelease;
50 
51 typedef HRESULT(__stdcall *CreateDXGIFactory1Type)(REFIID, void **);
52 typedef HRESULT(__stdcall *D3D11CreateDeviceAndSwapChainType)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE Software, UINT Flags, const D3D_FEATURE_LEVEL *, UINT, UINT, const DXGI_SWAP_CHAIN_DESC *, IDXGISwapChain **, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **);
53 
54 typedef ULONG(__stdcall *AddRefType)(ID3D11Device *);
55 typedef ULONG(__stdcall *ReleaseType)(ID3D11Device *);
56 
57 struct SimpleVec3 {
58 	FLOAT x;
59 	FLOAT y;
60 	FLOAT z;
SimpleVec3SimpleVec361 	SimpleVec3(FLOAT _x, FLOAT _y, FLOAT _z) : x(_x), y(_y), z(_z) {}
62 };
63 
64 struct SimpleVec2 {
65 	FLOAT x;
66 	FLOAT y;
SimpleVec2SimpleVec267 	SimpleVec2(FLOAT _x, FLOAT _y) : x(_x), y(_y) {}
68 };
69 
70 struct SimpleVertex {
71 	SimpleVec3 Pos;
72 	SimpleVec2 Tex;
73 };
74 
75 static const int VERTEXBUFFER_SIZE = 4 * sizeof(SimpleVertex);
76 
77 class D11State: protected Pipe {
78 	public:
79 		ULONG lHighMark;
80 
81 		LONG initRefCount;
82 		LONG refCount;
83 		LONG myRefCount;
84 
85 		D3D11_VIEWPORT vp;
86 
87 		ID3D11Device *pDevice;
88 		ID3D11DeviceContext *pDeviceContext;
89 		bool bDeferredContext;
90 		IDXGISwapChain *pSwapChain;
91 
92 		D11StateBlock *pOrigStateBlock;
93 		D11StateBlock *pMyStateBlock;
94 		ID3D11RenderTargetView *pRTV;
95 		ID3D11VertexShader *pVertexShader;
96 		ID3D11PixelShader *pPixelShader;
97 		ID3D11InputLayout *pVertexLayout;
98 		ID3D11Buffer *pVertexBuffer;
99 		ID3D11Buffer *pIndexBuffer;
100 		ID3D11BlendState *pBlendState;
101 
102 		ID3D11Texture2D *pTexture;
103 		ID3D11ShaderResourceView *pSRView;
104 
105 		clock_t timeT;
106 		unsigned int frameCount;
107 
108 		D11State(IDXGISwapChain *, ID3D11Device *);
109 		virtual ~D11State();
110 		bool init();
111 		void draw();
112 
113 		virtual void blit(unsigned int x, unsigned int y, unsigned int w, unsigned int h);
114 		virtual void setRect();
115 		virtual void newTexture(unsigned int w, unsigned int h);
116 };
117 
118 typedef map<IDXGISwapChain *, D11State *> SwapchainMap;
119 SwapchainMap chains;
120 typedef map<ID3D11Device *, D11State *> DeviceMap;
121 DeviceMap devices;
122 
D11State(IDXGISwapChain * pSwapChain,ID3D11Device * pDevice)123 D11State::D11State(IDXGISwapChain *pSwapChain, ID3D11Device *pDevice)
124 	: bDeferredContext(false) {
125 	this->pSwapChain = pSwapChain;
126 	this->pDevice = pDevice;
127 
128 	lHighMark = initRefCount  = refCount = myRefCount = 0;
129 
130 	ZeroMemory(&vp, sizeof(vp));
131 
132 	pOrigStateBlock = NULL;
133 	pMyStateBlock = NULL;
134 	pRTV = NULL;
135 	pVertexShader = NULL;
136 	pPixelShader = NULL;
137 	pVertexLayout = NULL;
138 	pVertexBuffer = NULL;
139 	pIndexBuffer = NULL;
140 	pBlendState = NULL;
141 	pTexture = NULL;
142 	pSRView = NULL;
143 	pDeviceContext = NULL;
144 
145 	timeT = clock();
146 	frameCount = 0;
147 
148 	pDevice->AddRef();
149 	initRefCount = pDevice->Release();
150 }
151 
blit(unsigned int x,unsigned int y,unsigned int w,unsigned int h)152 void D11State::blit(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
153 	HRESULT hr;
154 
155 	ods("D3D11: Blit %d %d %d %d", x, y, w, h);
156 
157 	if (! pTexture || ! pSRView || uiLeft == uiRight)
158 		return;
159 
160 	D3D11_MAPPED_SUBRESOURCE mappedTex;
161 	hr = pDeviceContext->Map(pTexture, D3D11CalcSubresource(0, 0, 1), D3D11_MAP_WRITE_DISCARD, 0, &mappedTex);
162 	if (FAILED(hr)) {
163 		ods("D3D11: Failed map");
164 	}
165 
166 	UCHAR* pTexels = (UCHAR*)mappedTex.pData;
167 
168 	for (unsigned int r=0;r< uiHeight; ++r) {
169 		unsigned char *sptr = a_ucTexture + r * uiWidth * 4;
170 		unsigned char *dptr = reinterpret_cast<unsigned char *>(pTexels) + r * mappedTex.RowPitch;
171 		memcpy(dptr, sptr, uiWidth * 4);
172 	}
173 
174 	pDeviceContext->Unmap(pTexture, D3D11CalcSubresource(0, 0, 1));
175 }
176 
setRect()177 void D11State::setRect() {
178 	HRESULT hr;
179 
180 	ods("D3D11: SetRect");
181 
182 	float w = static_cast<float>(uiWidth);
183 	float h = static_cast<float>(uiHeight);
184 
185 	float left   = static_cast<float>(uiLeft) - 0.5f;
186 	float top    = static_cast<float>(uiTop) - 0.5f;
187 	float right  = static_cast<float>(uiRight) + 0.5f;
188 	float bottom = static_cast<float>(uiBottom) + 0.5f;
189 
190 	float texl = (left) / w;
191 	float text = (top) / h;
192 	float texr = (right + 1.0f) / w;
193 	float texb = (bottom + 1.0f) / h;
194 
195 	left = 2.0f * (left / vp.Width) - 1.0f;
196 	right = 2.0f * (right / vp.Width) - 1.0f;
197 	top = -2.0f * (top / vp.Height) + 1.0f;
198 	bottom = -2.0f * (bottom / vp.Height) + 1.0f;
199 
200 	ods("D3D11: Vertex (%f %f) (%f %f)", left, top, right, bottom);
201 
202 	// Create vertex buffer
203 	SimpleVertex vertices[] = {
204 		{ SimpleVec3(left, top, 0.5f), SimpleVec2(texl, text) },
205 		{ SimpleVec3(right, top, 0.5f), SimpleVec2(texr, text) },
206 		{ SimpleVec3(right, bottom, 0.5f), SimpleVec2(texr, texb) },
207 		{ SimpleVec3(left, bottom, 0.5f), SimpleVec2(texl, texb) },
208 	};
209 
210 	// map/unmap to temporarily deny GPU access to the resource pVertexBuffer
211 	D3D11_MAPPED_SUBRESOURCE res;
212 	hr = pDeviceContext->Map(pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
213 
214 	const int verticesSize = sizeof(vertices);
215 	static_assert(verticesSize == VERTEXBUFFER_SIZE, "The vertex buffer size differs from the locally created vertex buffer.");
216 	memcpy(res.pData, vertices, verticesSize);
217 	ods("D3D11: Map: %lx %d", hr, sizeof(vertices));
218 	pDeviceContext->Unmap(pVertexBuffer, 0);
219 }
220 
newTexture(unsigned int w,unsigned int h)221 void D11State::newTexture(unsigned int w, unsigned int h) {
222 	HRESULT hr;
223 
224 	ods("D3D11: newTex %d %d", w, h);
225 
226 	if (pTexture) {
227 		pTexture->Release();
228 		pTexture = NULL;
229 	}
230 	if (pSRView) {
231 		pSRView->Release();
232 		pSRView = NULL;
233 	}
234 
235 	D3D11_TEXTURE2D_DESC desc;
236 	ZeroMemory(&desc, sizeof(desc));
237 
238 	desc.Width = w;
239 	desc.Height = h;
240 	desc.MipLevels = desc.ArraySize = 1;
241 	desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
242 	desc.SampleDesc.Count = 1;
243 	desc.Usage = D3D11_USAGE_DYNAMIC;
244 	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
245 	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
246 	hr = pDevice->CreateTexture2D(&desc, NULL, &pTexture);
247 
248 	if (FAILED(hr)) {
249 		pTexture = NULL;
250 		ods("D3D11: Failed to create texture.");
251 		return;
252 	}
253 
254 	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
255 	ZeroMemory(&srvDesc, sizeof(srvDesc));
256 	srvDesc.Format = desc.Format;
257 	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
258 	srvDesc.Texture2D.MostDetailedMip = 0;
259 	srvDesc.Texture2D.MipLevels = desc.MipLevels;
260 
261 	hr = pDevice->CreateShaderResourceView(pTexture, &srvDesc, &pSRView);
262 	if (FAILED(hr)) {
263 		pSRView = NULL;
264 		pTexture->Release();
265 		pTexture = NULL;
266 		ods("D3D11: Failed to create resource view.");
267 		return;
268 	}
269 }
270 
init()271 bool D11State::init() {
272 	HRESULT hr;
273 
274 	ID3D11Texture2D* pBackBuffer = NULL;
275 	hr = pSwapChain->GetBuffer(0, __uuidof(*pBackBuffer), (LPVOID*)&pBackBuffer);
276 	if (FAILED(hr)) {
277 		ods("D3D11: pSwapChain->GetBuffer failure!");
278 		return false;
279 	}
280 
281 	hr = pDevice->CreateDeferredContext(0, &pDeviceContext);
282 	// Depending on the device settings a deferred context may not be createable
283 	// for example if it is a SINGLETHREADED device.
284 	// (See http://msdn.microsoft.com/en-us/library/windows/desktop/ff476505%28v=vs.85%29.aspx)
285 	// We handle the expected failure and failure fallback in the same way -
286 	// by trying to use an immediate context.
287 	if (FAILED(hr) || !pDeviceContext) {
288 		ods("D3D11: Failed to create DeferredContext (0x%x). Getting ImmediateContext", hr);
289 		pDevice->GetImmediateContext(&pDeviceContext);
290 		D11CreateStateBlock(pDeviceContext, &pOrigStateBlock);
291 		D11CreateStateBlock(pDeviceContext, &pMyStateBlock);
292 
293 		pOrigStateBlock->Capture();
294 		bDeferredContext = false;
295 	} else {
296 		bDeferredContext = true;
297 	}
298 
299 	D3D11_TEXTURE2D_DESC backBufferSurfaceDesc;
300 	pBackBuffer->GetDesc(&backBufferSurfaceDesc);
301 
302 	ZeroMemory(&vp, sizeof(vp));
303 	vp.Width = static_cast<float>(backBufferSurfaceDesc.Width);
304 	vp.Height = static_cast<float>(backBufferSurfaceDesc.Height);
305 	vp.MinDepth = 0;
306 	vp.MaxDepth = 1;
307 	vp.TopLeftX = 0;
308 	vp.TopLeftY = 0;
309 	pDeviceContext->RSSetViewports(1, &vp);
310 
311 	hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRTV);
312 	if (FAILED(hr)) {
313 		ods("D3D11: pDevice->CreateRenderTargetView failed!");
314 		return false;
315 	}
316 
317 	pDeviceContext->OMSetRenderTargets(1, &pRTV, NULL);
318 
319 	// Settings for an "over" operation.
320 	// https://en.wikipedia.org/w/index.php?title=Alpha_compositing&oldid=580659153#Description
321 	D3D11_BLEND_DESC blend;
322 	ZeroMemory(&blend, sizeof(blend));
323 	blend.RenderTarget[0].BlendEnable = TRUE;
324 	blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
325 	blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
326 	blend.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
327 	blend.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
328 	blend.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
329 	blend.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
330 	blend.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
331 
332 	pDevice->CreateBlendState(&blend, &pBlendState);
333 	if (FAILED(hr)) {
334 		ods("D3D11: pDevice->CreateBlendState failed!");
335 		return false;
336 	}
337 
338 	pDeviceContext->OMSetBlendState(pBlendState, NULL, 0xffffffff);
339 
340 	hr = pDevice->CreateVertexShader(g_vertex_shader, sizeof(g_vertex_shader), NULL, &pVertexShader);
341 	if (FAILED(hr)) {
342 		ods("D3D11: Failed to create vertex shader.");
343 		return false;
344 	}
345 
346 	hr = pDevice->CreatePixelShader(g_pixel_shader, sizeof(g_pixel_shader), NULL, &pPixelShader);
347 	if (FAILED(hr)) {
348 		ods("D3D11: Failed to create pixel shader.");
349 		return false;
350 	}
351 
352 	pTexture = NULL;
353 	pSRView = NULL;
354 
355 	// Define the input layout
356 	D3D11_INPUT_ELEMENT_DESC layout[] = {
357 		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
358 		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
359 	};
360 
361 	hr = pDevice->CreateInputLayout(layout, ARRAY_NUM_ELEMENTS(layout), g_vertex_shader, sizeof(g_vertex_shader), &pVertexLayout);
362 	if (FAILED(hr)) {
363 		ods("D3D11: pDevice->CreateInputLayout failure!");
364 		return false;
365 	}
366 
367 	pDeviceContext->IASetInputLayout(pVertexLayout);
368 
369 	D3D11_BUFFER_DESC bd;
370 	ZeroMemory(&bd, sizeof(bd));
371 	bd.Usage = D3D11_USAGE_DYNAMIC;
372 	bd.ByteWidth = VERTEXBUFFER_SIZE;
373 	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
374 	bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
375 	bd.MiscFlags = 0;
376 
377 	hr = pDevice->CreateBuffer(&bd, NULL, &pVertexBuffer);
378 	if (FAILED(hr)) {
379 		ods("D3D11: pDevice->CreateBuffer failure!");
380 		return false;
381 	}
382 
383 	DWORD indices[] = {
384 		0,1,3,
385 		1,2,3,
386 	};
387 
388 	ZeroMemory(&bd, sizeof(bd));
389 	bd.Usage = D3D11_USAGE_IMMUTABLE;
390 	bd.ByteWidth = sizeof(DWORD) * 6;
391 	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
392 	bd.CPUAccessFlags = 0;
393 	bd.MiscFlags = 0;
394 	D3D11_SUBRESOURCE_DATA InitData;
395 	ZeroMemory(&InitData, sizeof(InitData));
396 	InitData.pSysMem = indices;
397 
398 	hr = pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer);
399 	if (FAILED(hr)) {
400 		ods("D3D11: pDevice->CreateBuffer failure!");
401 		return false;
402 	}
403 
404 	// Set index buffer
405 	pDeviceContext->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
406 
407 	// Set primitive topology
408 	pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
409 
410 	if (!bDeferredContext) {
411 		pMyStateBlock->Capture();
412 		pOrigStateBlock->Apply();
413 	}
414 	pBackBuffer->Release();
415 
416 	return true;
417 }
418 
~D11State()419 D11State::~D11State() {
420 	if (pBlendState)
421 		pBlendState->Release();
422 	if (pVertexBuffer)
423 		pVertexBuffer->Release();
424 	if (pIndexBuffer)
425 		pIndexBuffer->Release();
426 	if (pVertexLayout)
427 		pVertexLayout->Release();
428 	if (pVertexShader)
429 		pVertexShader->Release();
430 	if (pPixelShader)
431 		pPixelShader->Release();
432 	if (pRTV)
433 		pRTV->Release();
434 
435 	if (pTexture)
436 		pTexture->Release();
437 	if (pSRView)
438 		pSRView->Release();
439 
440 	delete pMyStateBlock;
441 	pMyStateBlock = NULL;
442 	delete pOrigStateBlock;
443 	pOrigStateBlock = NULL;
444 
445 	if (pDeviceContext)
446 		pDeviceContext->Release();
447 }
448 
draw()449 void D11State::draw() {
450 	clock_t t = clock();
451 	float elapsed = static_cast<float>(t - timeT) / CLOCKS_PER_SEC;
452 	++frameCount;
453 	if (elapsed > OVERLAY_FPS_INTERVAL) {
454 		OverlayMsg om;
455 		om.omh.uiMagic = OVERLAY_MAGIC_NUMBER;
456 		om.omh.uiType = OVERLAY_MSGTYPE_FPS;
457 		om.omh.iLength = sizeof(OverlayMsgFps);
458 		om.omf.fps = frameCount / elapsed;
459 
460 		sendMessage(om);
461 
462 		frameCount = 0;
463 		timeT = t;
464 	}
465 
466 	checkMessage(static_cast<unsigned int>(vp.Width), static_cast<unsigned int>(vp.Height));
467 
468 	if (a_ucTexture && pSRView && (uiLeft != uiRight)) {
469 		if (!bDeferredContext) {
470 			pOrigStateBlock->Capture();
471 			pMyStateBlock->Apply();
472 		}
473 
474 		// Set vertex buffer
475 		UINT stride = sizeof(SimpleVertex);
476 		UINT offset = 0;
477 		pDeviceContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
478 
479 		pDeviceContext->VSSetShader(pVertexShader, NULL, 0);
480 		pDeviceContext->GSSetShader(NULL, NULL, 0);
481 		pDeviceContext->PSSetShaderResources(0, 1, &pSRView);
482 		pDeviceContext->PSSetShader(pPixelShader, NULL, 0);
483 		pDeviceContext->DrawIndexed(6, 0, 0);
484 
485 		if (bDeferredContext) {
486 			ID3D11CommandList *pCommandList;
487 			pDeviceContext->FinishCommandList(TRUE, &pCommandList);
488 			ID3D11DeviceContext *ctx = NULL;
489 			pDevice->GetImmediateContext(&ctx);
490 			ctx->ExecuteCommandList(pCommandList, TRUE);
491 			ctx->Release();
492 			pCommandList->Release();
493 		} else {
494 			pDeviceContext->Flush();
495 			pMyStateBlock->Capture();
496 			pOrigStateBlock->Apply();
497 		}
498 	}
499 }
500 
501 
502 // D3D11 specific logic for the Present function.
presentD3D11(IDXGISwapChain * pSwapChain)503 extern void presentD3D11(IDXGISwapChain *pSwapChain) {
504 
505 	ID3D11Device *pDevice = NULL;
506 	HRESULT hr = pSwapChain->GetDevice(__uuidof(ID3D11Device), (void **) &pDevice);
507 	if (SUCCEEDED(hr) && pDevice) {
508 		SwapchainMap::iterator it = chains.find(pSwapChain);
509 		D11State *ds = it != chains.end() ? it->second : NULL;
510 		if (ds && ds->pDevice != pDevice) {
511 			ods("D3D11: SwapChain device changed");
512 			devices.erase(ds->pDevice);
513 			delete ds;
514 			ds = NULL;
515 		}
516 		if (ds == NULL) {
517 			ods("D3D11: New state");
518 			ds = new D11State(pSwapChain, pDevice);
519 			if (!ds->init()) {
520 				pDevice->Release();
521 				delete ds;
522 				return;
523 			}
524 
525 			chains[pSwapChain] = ds;
526 			devices[pDevice] = ds;
527 		}
528 
529 		ds->draw();
530 		pDevice->Release();
531 	} else {
532 		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
533 		// DXGI is used for multiple D3D versions. Thus, this is expected if
534 		// another version is used (like D3D10).
535 		ods("D3D11: Could not draw because ID3D11Device could not be retrieved.");
536 		#endif
537 	}
538 }
539 
resizeD3D11(IDXGISwapChain * pSwapChain)540 extern void resizeD3D11(IDXGISwapChain *pSwapChain) {
541 	// Remove the D11State from our "cache" (= Invalidate)
542 	SwapchainMap::iterator it = chains.find(pSwapChain);
543 	if (it != chains.end()) {
544 		D11State *ds = it->second;
545 		devices.erase(ds->pDevice);
546 		chains.erase(pSwapChain);
547 		delete ds;
548 	}
549 }
550 
myAddRef(ID3D11Device * pDevice)551 static ULONG __stdcall myAddRef(ID3D11Device *pDevice) {
552 	//TODO: Move logic to HardHook.
553 	// Call base without active hook in case of no trampoline.
554 	AddRefType oAddRef = (AddRefType) hhAddRef.call;
555 	hhAddRef.restore();
556 	ULONG res = oAddRef(pDevice);
557 	hhAddRef.inject();
558 
559 	Mutex m;
560 	DeviceMap::iterator it = devices.find(pDevice);
561 	if (it != devices.end()) {
562 		it->second->lHighMark = res;
563 	}
564 
565 	return res;
566 }
567 
myRelease(ID3D11Device * pDevice)568 static ULONG __stdcall myRelease(ID3D11Device *pDevice) {
569 	//TODO: Move logic to HardHook.
570 	// Call base without active hook in case of no trampoline.
571 	ReleaseType oRelease = (ReleaseType) hhRelease.call;
572 	hhRelease.restore();
573 	ULONG res = oRelease(pDevice);
574 	hhRelease.inject();
575 
576 	Mutex m;
577 	DeviceMap::iterator it = devices.find(pDevice);
578 	if (it != devices.end()) {
579 		D11State *ds = it->second;
580 		// If we are receiving a lot of subsequent releases lets eagerly drop
581 		// our state object. If the device presents something again a state
582 		// object is created again just fine anyway.
583 		if (res < ds->lHighMark / 2) {
584 			ods("D3D11: Deleting resources %u < 0.5 * %u", res, ds->lHighMark);
585 			devices.erase(it);
586 			chains.erase(ds->pSwapChain);
587 			delete ds;
588 			ods("D3D11: Deleted");
589 			ds = NULL;
590 		}
591 	}
592 
593 	return res;
594 }
595 
HookAddRelease(voidFunc vfAdd,voidFunc vfRelease)596 static void HookAddRelease(voidFunc vfAdd, voidFunc vfRelease) {
597 	ods("D3D11: Injecting device add/remove");
598 	hhAddRef.setup(vfAdd, reinterpret_cast<voidFunc>(myAddRef));
599 	hhRelease.setup(vfRelease, reinterpret_cast<voidFunc>(myRelease));
600 }
601 
602 void hookD3D11(HMODULE hD3D11, bool preonly);
603 
checkDXGI11Hook(bool preonly)604 void checkDXGI11Hook(bool preonly) {
605 	static bool bCheckHookActive = false;
606 	if (bCheckHookActive) {
607 		ods("D3D11: Recursion in checkDXGI11Hook");
608 		return;
609 	}
610 
611 	if (d3d11->offsetAddRef == 0 || d3d11->offsetRelease == 0) {
612 		return;
613 	}
614 
615 	bCheckHookActive = true;
616 
617 	HMODULE hDXGI = GetModuleHandleW(L"DXGI.DLL");
618 	HMODULE hD3D11 = GetModuleHandleW(L"D3D11.DLL");
619 
620 	if (hDXGI && hD3D11) {
621 		if (! bHooked) {
622 			hookD3D11(hD3D11, preonly);
623 		}
624 	} else {
625 		#ifdef EXTENDED_OVERLAY_DEBUGOUTPUT
626 		if (hDXGI) {
627 			ods("D3D11: No DXGI.DLL found as loaded. No hooking at this point.");
628 		} else {
629 			ods("D3D11: No D3D11.DLL found as loaded. No hooking at this point.");
630 		}
631 		#endif
632 	}
633 
634 	bCheckHookActive = false;
635 }
636 
637 /// @param hD3D11 must be a valid module handle
hookD3D11(HMODULE hD3D11,bool preonly)638 void hookD3D11(HMODULE hD3D11, bool preonly) {
639 
640 	// Add a ref to ourselves; we do NOT want to get unloaded directly from this process.
641 	HMODULE hTempSelf = NULL;
642 	GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCTSTR>(&hookD3D11), &hTempSelf);
643 
644 	bHooked = true;
645 
646 	const int modulenamesize = MODULEFILEPATH_BUFLEN;
647 	wchar_t modulename[modulenamesize];
648 	GetModuleFileNameW(hD3D11, modulename, modulenamesize);
649 
650 	if (_wcsicmp(d3d11->wcFileName, modulename) == 0) {
651 		unsigned char *raw = (unsigned char *) hD3D11;
652 		HookAddRelease((voidFunc)(raw + d3d11->offsetAddRef), (voidFunc)(raw + d3d11->offsetRelease));
653 	} else if (! preonly) {
654 		ods("D3D11: Interface changed, can't rawpatch. Current: %ls ; Previously: %ls", modulename, d3d11->wcFileName);
655 	} else {
656 		bHooked = false;
657 	}
658 }
659 
660 /// Prepares DXGI and D3D11 data by trying to determine the module filepath
661 /// and function offsets in memory.
662 /// (This data can later be used for hooking / code injection.)
663 ///
664 /// Adjusts the data behind the global variables dxgi and d3d11.
PrepareDXGI11(IDXGIAdapter1 * pAdapter,bool initializeDXGIData)665 void PrepareDXGI11(IDXGIAdapter1* pAdapter, bool initializeDXGIData) {
666 
667 	if (!dxgi || !d3d11 || !pAdapter)
668 		return;
669 
670 	ods("D3D11: Preparing static data for DXGI and D3D11 Injection");
671 
672 	d3d11->wcFileName[0] = 0;
673 	d3d11->offsetAddRef = 0;
674 	d3d11->offsetRelease = 0;
675 
676 	HMODULE hD3D11 = LoadLibrary("D3D11.DLL");
677 
678 	if (hD3D11 != NULL) {
679 
680 		HWND hwnd = CreateWindowW(L"STATIC", L"Mumble DXGI Window", WS_OVERLAPPEDWINDOW,
681 								  CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0,
682 								  NULL, NULL, 0);
683 
684 		D3D11CreateDeviceAndSwapChainType pD3D11CreateDeviceAndSwapChain = reinterpret_cast<D3D11CreateDeviceAndSwapChainType>(GetProcAddress(hD3D11, "D3D11CreateDeviceAndSwapChain"));
685 
686 		DXGI_SWAP_CHAIN_DESC desc;
687 		ZeroMemory(&desc, sizeof(desc));
688 
689 		RECT rcWnd;
690 		BOOL success = GetClientRect(hwnd, &rcWnd);
691 		if (success) {
692 			desc.BufferDesc.Width = rcWnd.right - rcWnd.left;
693 			desc.BufferDesc.Height = rcWnd.bottom - rcWnd.top;
694 
695 			ods("D3D11: Got ClientRect W %d H %d", desc.BufferDesc.Width, desc.BufferDesc.Height);
696 
697 			desc.BufferDesc.RefreshRate.Numerator = 60;
698 			desc.BufferDesc.RefreshRate.Denominator = 1;
699 			desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
700 			desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
701 			desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
702 
703 			desc.SampleDesc.Count = 1;
704 			desc.SampleDesc.Quality = 0;
705 
706 			desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
707 
708 			desc.BufferCount = 2;
709 
710 			desc.OutputWindow = hwnd;
711 
712 			desc.Windowed = true;
713 
714 			desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
715 
716 			IDXGISwapChain *pSwapChain = NULL;
717 			ID3D11Device *pDevice = NULL;
718 			D3D_FEATURE_LEVEL featureLevel;
719 			ID3D11DeviceContext *pDeviceContext = NULL;
720 			HRESULT hr = pD3D11CreateDeviceAndSwapChain(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &desc, &pSwapChain, &pDevice, &featureLevel, &pDeviceContext);
721 			if (FAILED(hr))
722 				ods("D3D11: pD3D11CreateDeviceAndSwapChain failure!");
723 
724 			if (pDevice && pDeviceContext && pSwapChain) {
725 
726 				// 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
727 				// of IDXGISwapChain have a total of 8 functions the 8+Xth entry points to the Xth added function in the derived interface.
728 
729 				void ***vtbl = (void ***) pSwapChain;
730 
731 				void *pPresent = (*vtbl)[8];
732 				boost::optional<size_t> offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pPresent), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D11", "Present");
733 				if (offset) {
734 					if (initializeDXGIData) {
735 						dxgi->offsetPresent = *offset;
736 						ods("D3D11: Successfully found Present offset: %ls: %d", dxgi->wcFileName, dxgi->offsetPresent);
737 					} else {
738 						if (dxgi->offsetPresent == *offset) {
739 							ods("D3D11: Successfully verified Present offset: %ls: %d", dxgi->wcFileName, dxgi->offsetPresent);
740 						} else {
741 							ods("D3D11: Failed to verify Present offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->offsetPresent);
742 						}
743 					}
744 				}
745 
746 				void *pResize = (*vtbl)[13];
747 				offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pResize), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D11", "ResizeBuffers");
748 				if (offset) {
749 					if (initializeDXGIData) {
750 						dxgi->offsetResize = *offset;
751 						ods("D3D11: Successfully found ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->offsetResize);
752 					} else {
753 						if (dxgi->offsetResize == *offset) {
754 							ods("D3D11: Successfully verified ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->offsetResize);
755 						} else {
756 							ods("D3D11: Failed to verify ResizeBuffers offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->offsetResize);
757 						}
758 					}
759 				}
760 
761 				vtbl = (void ***) pDevice;
762 
763 				void *pAddRef = (*vtbl)[1];
764 				offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pAddRef), d3d11->wcFileName, ARRAY_NUM_ELEMENTS(d3d11->wcFileName), "D3D11", "AddRef");
765 				if (offset) {
766 					d3d11->offsetAddRef = *offset;
767 					ods("D3D11: Successfully found AddRef offset: %ls: %d", d3d11->wcFileName, d3d11->offsetAddRef);
768 				}
769 
770 				void *pRelease = (*vtbl)[2];
771 				offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pRelease), d3d11->wcFileName, ARRAY_NUM_ELEMENTS(d3d11->wcFileName), "D3D11", "Release");
772 				if (offset) {
773 					d3d11->offsetRelease = *offset;
774 					ods("D3D11: Successfully found Release offset: %ls: %d", d3d11->wcFileName, d3d11->offsetRelease);
775 				}
776 			}
777 
778 			if (pDevice)
779 				pDevice->Release();
780 			if (pDeviceContext)
781 				pDeviceContext->Release();
782 			if (pSwapChain)
783 				pSwapChain->Release();
784 
785 		} else {
786 			FreeLibrary(hD3D11);
787 		}
788 
789 		DestroyWindow(hwnd);
790 	} else {
791 		FreeLibrary(hD3D11);
792 	}
793 }
794