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