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