OutputManager.cxx 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved
  7. #include "OutputManager.h"
  8. using namespace DirectX;
  9. //
  10. // Constructor NULLs out all pointers & sets appropriate var vals
  11. //
  12. OUTPUTMANAGER::OUTPUTMANAGER() : m_SwapChain(nullptr),
  13. m_Device(nullptr),
  14. m_Factory(nullptr),
  15. m_DeviceContext(nullptr),
  16. m_RTV(nullptr),
  17. m_SamplerLinear(nullptr),
  18. m_BlendState(nullptr),
  19. m_VertexShader(nullptr),
  20. m_PixelShader(nullptr),
  21. m_InputLayout(nullptr),
  22. m_SharedSurf(nullptr),
  23. m_KeyMutex(nullptr),
  24. m_WindowHandle(nullptr),
  25. m_NeedsResize(false),
  26. m_OcclusionCookie(0)
  27. {
  28. }
  29. //
  30. // Destructor which calls CleanRefs to release all references and memory.
  31. //
  32. OUTPUTMANAGER::~OUTPUTMANAGER()
  33. {
  34. CleanRefs();
  35. }
  36. //
  37. // Indicates that window has been resized.
  38. //
  39. void OUTPUTMANAGER::WindowResize()
  40. {
  41. m_NeedsResize = true;
  42. }
  43. //
  44. // Initialize all state
  45. //
  46. DUPL_RETURN OUTPUTMANAGER::InitOutput(HWND Window, INT SingleOutput, _Out_ UINT* OutCount, _Out_ RECT* DeskBounds)
  47. {
  48. HRESULT hr;
  49. // Store window handle
  50. m_WindowHandle = Window;
  51. // Driver types supported
  52. D3D_DRIVER_TYPE DriverTypes[] = {
  53. D3D_DRIVER_TYPE_HARDWARE,
  54. D3D_DRIVER_TYPE_WARP,
  55. D3D_DRIVER_TYPE_REFERENCE,
  56. };
  57. UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
  58. // Feature levels supported
  59. D3D_FEATURE_LEVEL FeatureLevels[] = {
  60. D3D_FEATURE_LEVEL_11_0,
  61. D3D_FEATURE_LEVEL_10_1,
  62. D3D_FEATURE_LEVEL_10_0,
  63. D3D_FEATURE_LEVEL_9_1
  64. };
  65. UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
  66. D3D_FEATURE_LEVEL FeatureLevel;
  67. // Create device
  68. for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex) {
  69. hr = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels, NumFeatureLevels,
  70. D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
  71. if (SUCCEEDED(hr)) {
  72. // Device creation succeeded, no need to loop anymore
  73. break;
  74. }
  75. }
  76. if (FAILED(hr)) {
  77. return ProcessFailure(m_Device, L"Device creation in OUTPUTMANAGER failed", L"Error", hr, SystemTransitionsExpectedErrors);
  78. }
  79. // Get DXGI factory
  80. IDXGIDevice* DxgiDevice = nullptr;
  81. hr = m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice));
  82. if (FAILED(hr)) {
  83. return ProcessFailure(nullptr, L"Failed to QI for DXGI Device", L"Error", hr, nullptr);
  84. }
  85. IDXGIAdapter* DxgiAdapter = nullptr;
  86. hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter));
  87. DxgiDevice->Release();
  88. DxgiDevice = nullptr;
  89. if (FAILED(hr)) {
  90. return ProcessFailure(m_Device, L"Failed to get parent DXGI Adapter", L"Error", hr, SystemTransitionsExpectedErrors);
  91. }
  92. hr = DxgiAdapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&m_Factory));
  93. DxgiAdapter->Release();
  94. DxgiAdapter = nullptr;
  95. if (FAILED(hr)) {
  96. return ProcessFailure(m_Device, L"Failed to get parent DXGI Factory", L"Error", hr, SystemTransitionsExpectedErrors);
  97. }
  98. // Register for occlusion status windows message
  99. if (m_WindowHandle) {
  100. hr = m_Factory->RegisterOcclusionStatusWindow(Window, OCCLUSION_STATUS_MSG, &m_OcclusionCookie);
  101. if (FAILED(hr)) {
  102. return ProcessFailure(m_Device, L"Failed to register for occlusion message", L"Error", hr, SystemTransitionsExpectedErrors);
  103. }
  104. }
  105. // Get window size
  106. RECT WindowRect;
  107. GetClientRect(m_WindowHandle ? m_WindowHandle : GetDesktopWindow(), &WindowRect);
  108. UINT Width = WindowRect.right - WindowRect.left;
  109. UINT Height = WindowRect.bottom - WindowRect.top;
  110. if (m_WindowHandle) {
  111. // Create swapchain for window
  112. DXGI_SWAP_CHAIN_DESC1 SwapChainDesc;
  113. RtlZeroMemory(&SwapChainDesc, sizeof(SwapChainDesc));
  114. SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
  115. SwapChainDesc.BufferCount = 2;
  116. SwapChainDesc.Width = Width;
  117. SwapChainDesc.Height = Height;
  118. SwapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  119. SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  120. SwapChainDesc.SampleDesc.Count = 1;
  121. SwapChainDesc.SampleDesc.Quality = 0;
  122. hr = m_Factory->CreateSwapChainForHwnd(m_Device, Window, &SwapChainDesc, nullptr, nullptr, &m_SwapChain);
  123. if (FAILED(hr)) {
  124. return ProcessFailure(m_Device, L"Failed to create window swapchain", L"Error", hr, SystemTransitionsExpectedErrors);
  125. }
  126. // Disable the ALT-ENTER shortcut for entering full-screen mode
  127. hr = m_Factory->MakeWindowAssociation(Window, DXGI_MWA_NO_ALT_ENTER);
  128. if (FAILED(hr)) {
  129. return ProcessFailure(m_Device, L"Failed to make window association", L"Error", hr, SystemTransitionsExpectedErrors);
  130. }
  131. }
  132. // Create shared texture
  133. DUPL_RETURN Return = CreateSharedSurf(SingleOutput, OutCount, DeskBounds);
  134. if (Return != DUPL_RETURN_SUCCESS) {
  135. return Return;
  136. }
  137. // Make new render target view
  138. if (m_WindowHandle) {
  139. Return = MakeRTV();
  140. if (Return != DUPL_RETURN_SUCCESS) {
  141. return Return;
  142. }
  143. }
  144. // Set view port
  145. SetViewPort(Width, Height);
  146. // Create the sample state
  147. D3D11_SAMPLER_DESC SampDesc;
  148. RtlZeroMemory(&SampDesc, sizeof(SampDesc));
  149. SampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
  150. SampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
  151. SampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
  152. SampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
  153. SampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
  154. SampDesc.MinLOD = 0;
  155. SampDesc.MaxLOD = D3D11_FLOAT32_MAX;
  156. hr = m_Device->CreateSamplerState(&SampDesc, &m_SamplerLinear);
  157. if (FAILED(hr)) {
  158. return ProcessFailure(m_Device, L"Failed to create sampler state in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  159. }
  160. if (m_WindowHandle) {
  161. // Create the blend state
  162. D3D11_BLEND_DESC BlendStateDesc;
  163. BlendStateDesc.AlphaToCoverageEnable = FALSE;
  164. BlendStateDesc.IndependentBlendEnable = FALSE;
  165. BlendStateDesc.RenderTarget[0].BlendEnable = TRUE;
  166. BlendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
  167. BlendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
  168. BlendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
  169. BlendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
  170. BlendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
  171. BlendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
  172. BlendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
  173. hr = m_Device->CreateBlendState(&BlendStateDesc, &m_BlendState);
  174. if (FAILED(hr)) {
  175. return ProcessFailure(m_Device, L"Failed to create blend state in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  176. }
  177. // Initialize shaders
  178. Return = InitShaders();
  179. if (Return != DUPL_RETURN_SUCCESS) {
  180. return Return;
  181. }
  182. GetWindowRect(m_WindowHandle, &WindowRect);
  183. MoveWindow(m_WindowHandle, WindowRect.left, WindowRect.top, (DeskBounds->right - DeskBounds->left) / 2, (DeskBounds->bottom - DeskBounds->top) / 2, TRUE);
  184. }
  185. return Return;
  186. }
  187. //
  188. // Recreate shared texture
  189. //
  190. DUPL_RETURN OUTPUTMANAGER::CreateSharedSurf(INT SingleOutput, _Out_ UINT* OutCount, _Out_ RECT* DeskBounds)
  191. {
  192. HRESULT hr;
  193. // Get DXGI resources
  194. IDXGIDevice* DxgiDevice = nullptr;
  195. hr = m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice));
  196. if (FAILED(hr)) {
  197. return ProcessFailure(nullptr, L"Failed to QI for DXGI Device", L"Error", hr);
  198. }
  199. IDXGIAdapter* DxgiAdapter = nullptr;
  200. hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter));
  201. DxgiDevice->Release();
  202. DxgiDevice = nullptr;
  203. if (FAILED(hr)) {
  204. return ProcessFailure(m_Device, L"Failed to get parent DXGI Adapter", L"Error", hr, SystemTransitionsExpectedErrors);
  205. }
  206. // Set initial values so that we always catch the right coordinates
  207. DeskBounds->left = INT_MAX;
  208. DeskBounds->right = INT_MIN;
  209. DeskBounds->top = INT_MAX;
  210. DeskBounds->bottom = INT_MIN;
  211. IDXGIOutput* DxgiOutput = nullptr;
  212. // Figure out right dimensions for full size desktop texture and # of outputs to duplicate
  213. UINT OutputCount;
  214. if (SingleOutput < 0) {
  215. hr = S_OK;
  216. for (OutputCount = 0; SUCCEEDED(hr); ++OutputCount) {
  217. if (DxgiOutput) {
  218. DxgiOutput->Release();
  219. DxgiOutput = nullptr;
  220. }
  221. hr = DxgiAdapter->EnumOutputs(OutputCount, &DxgiOutput);
  222. if (DxgiOutput && (hr != DXGI_ERROR_NOT_FOUND)) {
  223. DXGI_OUTPUT_DESC DesktopDesc;
  224. DxgiOutput->GetDesc(&DesktopDesc);
  225. DeskBounds->left = min(DesktopDesc.DesktopCoordinates.left, DeskBounds->left);
  226. DeskBounds->top = min(DesktopDesc.DesktopCoordinates.top, DeskBounds->top);
  227. DeskBounds->right = max(DesktopDesc.DesktopCoordinates.right, DeskBounds->right);
  228. DeskBounds->bottom = max(DesktopDesc.DesktopCoordinates.bottom, DeskBounds->bottom);
  229. }
  230. }
  231. --OutputCount;
  232. }
  233. else {
  234. hr = DxgiAdapter->EnumOutputs(SingleOutput, &DxgiOutput);
  235. if (FAILED(hr)) {
  236. DxgiAdapter->Release();
  237. DxgiAdapter = nullptr;
  238. return ProcessFailure(m_Device, L"Output specified to be duplicated does not exist", L"Error", hr);
  239. }
  240. DXGI_OUTPUT_DESC DesktopDesc;
  241. DxgiOutput->GetDesc(&DesktopDesc);
  242. *DeskBounds = DesktopDesc.DesktopCoordinates;
  243. DxgiOutput->Release();
  244. DxgiOutput = nullptr;
  245. OutputCount = 1;
  246. }
  247. DxgiAdapter->Release();
  248. DxgiAdapter = nullptr;
  249. // Set passed in output count variable
  250. *OutCount = OutputCount;
  251. if (OutputCount == 0) {
  252. // We could not find any outputs, the system must be in a transition so return expected error
  253. // so we will attempt to recreate
  254. return DUPL_RETURN_ERROR_EXPECTED;
  255. }
  256. // Create shared texture for all duplication threads to draw into
  257. D3D11_TEXTURE2D_DESC DeskTexD;
  258. RtlZeroMemory(&DeskTexD, sizeof(D3D11_TEXTURE2D_DESC));
  259. DeskTexD.Width = DeskBounds->right - DeskBounds->left;
  260. DeskTexD.Height = DeskBounds->bottom - DeskBounds->top;
  261. DeskTexD.MipLevels = 1;
  262. DeskTexD.ArraySize = 1;
  263. DeskTexD.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  264. DeskTexD.SampleDesc.Count = 1;
  265. DeskTexD.Usage = D3D11_USAGE_DEFAULT;
  266. DeskTexD.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
  267. DeskTexD.CPUAccessFlags = 0;
  268. DeskTexD.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
  269. hr = m_Device->CreateTexture2D(&DeskTexD, nullptr, &m_SharedSurf);
  270. if (FAILED(hr)) {
  271. if (OutputCount != 1) {
  272. // If we are duplicating the complete desktop we try to create a single texture to hold the
  273. // complete desktop image and blit updates from the per output DDA interface. The GPU can
  274. // always support a texture size of the maximum resolution of any single output but there is no
  275. // guarantee that it can support a texture size of the desktop.
  276. // The sample only use this large texture to display the desktop image in a single window using DX
  277. // we could revert back to using GDI to update the window in this failure case.
  278. return ProcessFailure(m_Device, L"Failed to create DirectX shared texture - we are attempting to create a texture the size of the complete desktop and this may be larger than the maximum texture size of your GPU. Please try again using the -output command line parameter to duplicate only 1 monitor or configure your computer to a single monitor configuration", L"Error", hr, SystemTransitionsExpectedErrors);
  279. }
  280. else {
  281. return ProcessFailure(m_Device, L"Failed to create shared texture", L"Error", hr, SystemTransitionsExpectedErrors);
  282. }
  283. }
  284. // Get keyed mutex
  285. hr = m_SharedSurf->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&m_KeyMutex));
  286. if (FAILED(hr)) {
  287. return ProcessFailure(m_Device, L"Failed to query for keyed mutex in OUTPUTMANAGER", L"Error", hr);
  288. }
  289. return DUPL_RETURN_SUCCESS;
  290. }
  291. //
  292. // Present to the application window
  293. //
  294. DUPL_RETURN OUTPUTMANAGER::UpdateApplicationWindow(_In_ PTR_INFO* PointerInfo, _Inout_ bool* Occluded)
  295. {
  296. // In a typical desktop duplication application there would be an application running on one system collecting the desktop images
  297. // and another application running on a different system that receives the desktop images via a network and display the image. This
  298. // sample contains both these aspects into a single application.
  299. // This routine is the part of the sample that displays the desktop image onto the display
  300. // Try and acquire sync on common display buffer
  301. HRESULT hr = m_KeyMutex->AcquireSync(1, 100);
  302. if (hr == static_cast<HRESULT>(WAIT_TIMEOUT)) {
  303. // Another thread has the keyed mutex so try again later
  304. return DUPL_RETURN_SUCCESS;
  305. }
  306. else if (FAILED(hr)) {
  307. return ProcessFailure(m_Device, L"Failed to acquire Keyed mutex in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  308. }
  309. // Got mutex, so draw
  310. DUPL_RETURN Ret = DrawFrame();
  311. if (Ret == DUPL_RETURN_SUCCESS) {
  312. // We have keyed mutex so we can access the mouse info
  313. if (PointerInfo->Visible) {
  314. // Draw mouse into texture
  315. Ret = DrawMouse(PointerInfo);
  316. }
  317. }
  318. // Release keyed mutex
  319. hr = m_KeyMutex->ReleaseSync(0);
  320. if (FAILED(hr)) {
  321. return ProcessFailure(m_Device, L"Failed to Release Keyed mutex in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  322. }
  323. // Present to window if all worked
  324. if (Ret == DUPL_RETURN_SUCCESS) {
  325. // Present to window
  326. if (m_SwapChain) {
  327. hr = m_SwapChain->Present(1, 0);
  328. if (FAILED(hr)) {
  329. return ProcessFailure(m_Device, L"Failed to present", L"Error", hr, SystemTransitionsExpectedErrors);
  330. }
  331. else if (hr == DXGI_STATUS_OCCLUDED) {
  332. *Occluded = true;
  333. }
  334. }
  335. }
  336. return Ret;
  337. }
  338. //
  339. // Returns shared handle
  340. //
  341. HANDLE OUTPUTMANAGER::GetSharedHandle()
  342. {
  343. HANDLE Hnd = nullptr;
  344. // QI IDXGIResource interface to synchronized shared surface.
  345. IDXGIResource* DXGIResource = nullptr;
  346. HRESULT hr = m_SharedSurf->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void**>(&DXGIResource));
  347. if (SUCCEEDED(hr)) {
  348. // Obtain handle to IDXGIResource object.
  349. DXGIResource->GetSharedHandle(&Hnd);
  350. DXGIResource->Release();
  351. DXGIResource = nullptr;
  352. }
  353. return Hnd;
  354. }
  355. //
  356. // Draw frame into backbuffer
  357. //
  358. DUPL_RETURN OUTPUTMANAGER::DrawFrame()
  359. {
  360. HRESULT hr;
  361. // If window was resized, resize swapchain
  362. if (m_NeedsResize) {
  363. DUPL_RETURN Ret = ResizeSwapChain();
  364. if (Ret != DUPL_RETURN_SUCCESS) {
  365. return Ret;
  366. }
  367. m_NeedsResize = false;
  368. }
  369. // Vertices for drawing whole texture
  370. VERTEX Vertices[NUMVERTICES] = {
  371. {XMFLOAT3(-1.0f, -1.0f, 0), XMFLOAT2(0.0f, 1.0f)},
  372. {XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},
  373. {XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},
  374. {XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},
  375. {XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},
  376. {XMFLOAT3(1.0f, 1.0f, 0), XMFLOAT2(1.0f, 0.0f)},
  377. };
  378. D3D11_TEXTURE2D_DESC FrameDesc;
  379. m_SharedSurf->GetDesc(&FrameDesc);
  380. D3D11_SHADER_RESOURCE_VIEW_DESC ShaderDesc;
  381. ShaderDesc.Format = FrameDesc.Format;
  382. ShaderDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  383. ShaderDesc.Texture2D.MostDetailedMip = FrameDesc.MipLevels - 1;
  384. ShaderDesc.Texture2D.MipLevels = FrameDesc.MipLevels;
  385. // Create new shader resource view
  386. ID3D11ShaderResourceView* ShaderResource = nullptr;
  387. hr = m_Device->CreateShaderResourceView(m_SharedSurf, &ShaderDesc, &ShaderResource);
  388. if (FAILED(hr)) {
  389. return ProcessFailure(m_Device, L"Failed to create shader resource when drawing a frame", L"Error", hr, SystemTransitionsExpectedErrors);
  390. }
  391. // Set resources
  392. UINT Stride = sizeof(VERTEX);
  393. UINT Offset = 0;
  394. FLOAT blendFactor[4] = {0.f, 0.f, 0.f, 0.f};
  395. m_DeviceContext->OMSetBlendState(nullptr, blendFactor, 0xffffffff);
  396. m_DeviceContext->OMSetRenderTargets(1, &m_RTV, nullptr);
  397. m_DeviceContext->VSSetShader(m_VertexShader, nullptr, 0);
  398. m_DeviceContext->PSSetShader(m_PixelShader, nullptr, 0);
  399. m_DeviceContext->PSSetShaderResources(0, 1, &ShaderResource);
  400. m_DeviceContext->PSSetSamplers(0, 1, &m_SamplerLinear);
  401. m_DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  402. D3D11_BUFFER_DESC BufferDesc;
  403. RtlZeroMemory(&BufferDesc, sizeof(BufferDesc));
  404. BufferDesc.Usage = D3D11_USAGE_DEFAULT;
  405. BufferDesc.ByteWidth = sizeof(VERTEX) * NUMVERTICES;
  406. BufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  407. BufferDesc.CPUAccessFlags = 0;
  408. D3D11_SUBRESOURCE_DATA InitData;
  409. RtlZeroMemory(&InitData, sizeof(InitData));
  410. InitData.pSysMem = Vertices;
  411. ID3D11Buffer* VertexBuffer = nullptr;
  412. // Create vertex buffer
  413. hr = m_Device->CreateBuffer(&BufferDesc, &InitData, &VertexBuffer);
  414. if (FAILED(hr)) {
  415. ShaderResource->Release();
  416. ShaderResource = nullptr;
  417. return ProcessFailure(m_Device, L"Failed to create vertex buffer when drawing a frame", L"Error", hr, SystemTransitionsExpectedErrors);
  418. }
  419. m_DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &Stride, &Offset);
  420. // Draw textured quad onto render target
  421. m_DeviceContext->Draw(NUMVERTICES, 0);
  422. VertexBuffer->Release();
  423. VertexBuffer = nullptr;
  424. // Release shader resource
  425. ShaderResource->Release();
  426. ShaderResource = nullptr;
  427. return DUPL_RETURN_SUCCESS;
  428. }
  429. //
  430. // Process both masked and monochrome pointers
  431. //
  432. DUPL_RETURN OUTPUTMANAGER::ProcessMonoMask(bool IsMono, _Inout_ PTR_INFO* PtrInfo, _Out_ INT* PtrWidth, _Out_ INT* PtrHeight, _Out_ INT* PtrLeft, _Out_ INT* PtrTop, _Outptr_result_bytebuffer_(*PtrHeight **PtrWidth * BPP) BYTE** InitBuffer, _Out_ D3D11_BOX* Box)
  433. {
  434. // Desktop dimensions
  435. D3D11_TEXTURE2D_DESC FullDesc;
  436. m_SharedSurf->GetDesc(&FullDesc);
  437. INT DesktopWidth = FullDesc.Width;
  438. INT DesktopHeight = FullDesc.Height;
  439. // Pointer position
  440. INT GivenLeft = PtrInfo->Position.x;
  441. INT GivenTop = PtrInfo->Position.y;
  442. // Figure out if any adjustment is needed for out of bound positions
  443. if (GivenLeft < 0) {
  444. *PtrWidth = GivenLeft + static_cast<INT>(PtrInfo->ShapeInfo.Width);
  445. }
  446. else if ((GivenLeft + static_cast<INT>(PtrInfo->ShapeInfo.Width)) > DesktopWidth) {
  447. *PtrWidth = DesktopWidth - GivenLeft;
  448. }
  449. else {
  450. *PtrWidth = static_cast<INT>(PtrInfo->ShapeInfo.Width);
  451. }
  452. if (IsMono) {
  453. PtrInfo->ShapeInfo.Height = PtrInfo->ShapeInfo.Height / 2;
  454. }
  455. if (GivenTop < 0) {
  456. *PtrHeight = GivenTop + static_cast<INT>(PtrInfo->ShapeInfo.Height);
  457. }
  458. else if ((GivenTop + static_cast<INT>(PtrInfo->ShapeInfo.Height)) > DesktopHeight) {
  459. *PtrHeight = DesktopHeight - GivenTop;
  460. }
  461. else {
  462. *PtrHeight = static_cast<INT>(PtrInfo->ShapeInfo.Height);
  463. }
  464. if (IsMono) {
  465. PtrInfo->ShapeInfo.Height = PtrInfo->ShapeInfo.Height * 2;
  466. }
  467. *PtrLeft = (GivenLeft < 0) ? 0 : GivenLeft;
  468. *PtrTop = (GivenTop < 0) ? 0 : GivenTop;
  469. // Staging buffer/texture
  470. D3D11_TEXTURE2D_DESC CopyBufferDesc;
  471. CopyBufferDesc.Width = *PtrWidth;
  472. CopyBufferDesc.Height = *PtrHeight;
  473. CopyBufferDesc.MipLevels = 1;
  474. CopyBufferDesc.ArraySize = 1;
  475. CopyBufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  476. CopyBufferDesc.SampleDesc.Count = 1;
  477. CopyBufferDesc.SampleDesc.Quality = 0;
  478. CopyBufferDesc.Usage = D3D11_USAGE_STAGING;
  479. CopyBufferDesc.BindFlags = 0;
  480. CopyBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  481. CopyBufferDesc.MiscFlags = 0;
  482. ID3D11Texture2D* CopyBuffer = nullptr;
  483. HRESULT hr = m_Device->CreateTexture2D(&CopyBufferDesc, nullptr, &CopyBuffer);
  484. if (FAILED(hr)) {
  485. return ProcessFailure(m_Device, L"Failed creating staging texture for pointer", L"Error", hr, SystemTransitionsExpectedErrors);
  486. }
  487. // Copy needed part of desktop image
  488. Box->left = *PtrLeft;
  489. Box->top = *PtrTop;
  490. Box->right = *PtrLeft + *PtrWidth;
  491. Box->bottom = *PtrTop + *PtrHeight;
  492. m_DeviceContext->CopySubresourceRegion(CopyBuffer, 0, 0, 0, 0, m_SharedSurf, 0, Box);
  493. // QI for IDXGISurface
  494. IDXGISurface* CopySurface = nullptr;
  495. hr = CopyBuffer->QueryInterface(__uuidof(IDXGISurface), (void **)&CopySurface);
  496. CopyBuffer->Release();
  497. CopyBuffer = nullptr;
  498. if (FAILED(hr)) {
  499. return ProcessFailure(nullptr, L"Failed to QI staging texture into IDXGISurface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);
  500. }
  501. // Map pixels
  502. DXGI_MAPPED_RECT MappedSurface;
  503. hr = CopySurface->Map(&MappedSurface, DXGI_MAP_READ);
  504. if (FAILED(hr)) {
  505. CopySurface->Release();
  506. CopySurface = nullptr;
  507. return ProcessFailure(m_Device, L"Failed to map surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);
  508. }
  509. // New mouseshape buffer
  510. *InitBuffer = new (std::nothrow) BYTE[*PtrWidth **PtrHeight * BPP];
  511. if (!(*InitBuffer)) {
  512. return ProcessFailure(nullptr, L"Failed to allocate memory for new mouse shape buffer.", L"Error", E_OUTOFMEMORY);
  513. }
  514. UINT* InitBuffer32 = reinterpret_cast<UINT*>(*InitBuffer);
  515. UINT* Desktop32 = reinterpret_cast<UINT*>(MappedSurface.pBits);
  516. UINT DesktopPitchInPixels = MappedSurface.Pitch / sizeof(UINT);
  517. // What to skip (pixel offset)
  518. UINT SkipX = (GivenLeft < 0) ? (-1 * GivenLeft) : (0);
  519. UINT SkipY = (GivenTop < 0) ? (-1 * GivenTop) : (0);
  520. if (IsMono) {
  521. for (INT Row = 0; Row < *PtrHeight; ++Row) {
  522. // Set mask
  523. BYTE Mask = 0x80;
  524. Mask = Mask >> (SkipX % 8);
  525. for (INT Col = 0; Col < *PtrWidth; ++Col) {
  526. // Get masks using appropriate offsets
  527. BYTE AndMask = PtrInfo->PtrShapeBuffer[((Col + SkipX) / 8) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch))] & Mask;
  528. BYTE XorMask = PtrInfo->PtrShapeBuffer[((Col + SkipX) / 8) + ((Row + SkipY + (PtrInfo->ShapeInfo.Height / 2)) * (PtrInfo->ShapeInfo.Pitch))] & Mask;
  529. UINT AndMask32 = (AndMask) ? 0xFFFFFFFF : 0xFF000000;
  530. UINT XorMask32 = (XorMask) ? 0x00FFFFFF : 0x00000000;
  531. // Set new pixel
  532. InitBuffer32[(Row **PtrWidth) + Col] = (Desktop32[(Row * DesktopPitchInPixels) + Col] & AndMask32) ^ XorMask32;
  533. // Adjust mask
  534. if (Mask == 0x01) {
  535. Mask = 0x80;
  536. }
  537. else {
  538. Mask = Mask >> 1;
  539. }
  540. }
  541. }
  542. }
  543. else {
  544. UINT* Buffer32 = reinterpret_cast<UINT*>(PtrInfo->PtrShapeBuffer);
  545. // Iterate through pixels
  546. for (INT Row = 0; Row < *PtrHeight; ++Row) {
  547. for (INT Col = 0; Col < *PtrWidth; ++Col) {
  548. // Set up mask
  549. UINT MaskVal = 0xFF000000 & Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))];
  550. if (MaskVal) {
  551. // Mask was 0xFF
  552. InitBuffer32[(Row **PtrWidth) + Col] = (Desktop32[(Row * DesktopPitchInPixels) + Col] ^ Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))]) | 0xFF000000;
  553. }
  554. else {
  555. // Mask was 0x00
  556. InitBuffer32[(Row **PtrWidth) + Col] = Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))] | 0xFF000000;
  557. }
  558. }
  559. }
  560. }
  561. // Done with resource
  562. hr = CopySurface->Unmap();
  563. CopySurface->Release();
  564. CopySurface = nullptr;
  565. if (FAILED(hr)) {
  566. return ProcessFailure(m_Device, L"Failed to unmap surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);
  567. }
  568. return DUPL_RETURN_SUCCESS;
  569. }
  570. //
  571. // Draw mouse provided in buffer to backbuffer
  572. //
  573. DUPL_RETURN OUTPUTMANAGER::DrawMouse(_In_ PTR_INFO* PtrInfo)
  574. {
  575. // Vars to be used
  576. ID3D11Texture2D* MouseTex = nullptr;
  577. ID3D11ShaderResourceView* ShaderRes = nullptr;
  578. ID3D11Buffer* VertexBufferMouse = nullptr;
  579. D3D11_SUBRESOURCE_DATA InitData;
  580. D3D11_TEXTURE2D_DESC Desc;
  581. D3D11_SHADER_RESOURCE_VIEW_DESC SDesc;
  582. // Position will be changed based on mouse position
  583. VERTEX Vertices[NUMVERTICES] = {
  584. {XMFLOAT3(-1.0f, -1.0f, 0), XMFLOAT2(0.0f, 1.0f)},
  585. {XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},
  586. {XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},
  587. {XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},
  588. {XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},
  589. {XMFLOAT3(1.0f, 1.0f, 0), XMFLOAT2(1.0f, 0.0f)},
  590. };
  591. D3D11_TEXTURE2D_DESC FullDesc;
  592. m_SharedSurf->GetDesc(&FullDesc);
  593. INT DesktopWidth = FullDesc.Width;
  594. INT DesktopHeight = FullDesc.Height;
  595. // Center of desktop dimensions
  596. INT CenterX = (DesktopWidth / 2);
  597. INT CenterY = (DesktopHeight / 2);
  598. // Clipping adjusted coordinates / dimensions
  599. INT PtrWidth = 0;
  600. INT PtrHeight = 0;
  601. INT PtrLeft = 0;
  602. INT PtrTop = 0;
  603. // Buffer used if necessary (in case of monochrome or masked pointer)
  604. BYTE* InitBuffer = nullptr;
  605. // Used for copying pixels
  606. D3D11_BOX Box;
  607. Box.front = 0;
  608. Box.back = 1;
  609. Desc.MipLevels = 1;
  610. Desc.ArraySize = 1;
  611. Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  612. Desc.SampleDesc.Count = 1;
  613. Desc.SampleDesc.Quality = 0;
  614. Desc.Usage = D3D11_USAGE_DEFAULT;
  615. Desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  616. Desc.CPUAccessFlags = 0;
  617. Desc.MiscFlags = 0;
  618. // Set shader resource properties
  619. SDesc.Format = Desc.Format;
  620. SDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  621. SDesc.Texture2D.MostDetailedMip = Desc.MipLevels - 1;
  622. SDesc.Texture2D.MipLevels = Desc.MipLevels;
  623. switch (PtrInfo->ShapeInfo.Type) {
  624. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR: {
  625. PtrLeft = PtrInfo->Position.x;
  626. PtrTop = PtrInfo->Position.y;
  627. PtrWidth = static_cast<INT>(PtrInfo->ShapeInfo.Width);
  628. PtrHeight = static_cast<INT>(PtrInfo->ShapeInfo.Height);
  629. break;
  630. }
  631. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME: {
  632. ProcessMonoMask(true, PtrInfo, &PtrWidth, &PtrHeight, &PtrLeft, &PtrTop, &InitBuffer, &Box);
  633. break;
  634. }
  635. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: {
  636. ProcessMonoMask(false, PtrInfo, &PtrWidth, &PtrHeight, &PtrLeft, &PtrTop, &InitBuffer, &Box);
  637. break;
  638. }
  639. default:
  640. break;
  641. }
  642. // VERTEX creation
  643. Vertices[0].Pos.x = (PtrLeft - CenterX) / (FLOAT)CenterX;
  644. Vertices[0].Pos.y = -1 * ((PtrTop + PtrHeight) - CenterY) / (FLOAT)CenterY;
  645. Vertices[1].Pos.x = (PtrLeft - CenterX) / (FLOAT)CenterX;
  646. Vertices[1].Pos.y = -1 * (PtrTop - CenterY) / (FLOAT)CenterY;
  647. Vertices[2].Pos.x = ((PtrLeft + PtrWidth) - CenterX) / (FLOAT)CenterX;
  648. Vertices[2].Pos.y = -1 * ((PtrTop + PtrHeight) - CenterY) / (FLOAT)CenterY;
  649. Vertices[3].Pos.x = Vertices[2].Pos.x;
  650. Vertices[3].Pos.y = Vertices[2].Pos.y;
  651. Vertices[4].Pos.x = Vertices[1].Pos.x;
  652. Vertices[4].Pos.y = Vertices[1].Pos.y;
  653. Vertices[5].Pos.x = ((PtrLeft + PtrWidth) - CenterX) / (FLOAT)CenterX;
  654. Vertices[5].Pos.y = -1 * (PtrTop - CenterY) / (FLOAT)CenterY;
  655. // Set texture properties
  656. Desc.Width = PtrWidth;
  657. Desc.Height = PtrHeight;
  658. // Set up init data
  659. InitData.pSysMem = (PtrInfo->ShapeInfo.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) ? PtrInfo->PtrShapeBuffer : InitBuffer;
  660. InitData.SysMemPitch = (PtrInfo->ShapeInfo.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) ? PtrInfo->ShapeInfo.Pitch : PtrWidth * BPP;
  661. InitData.SysMemSlicePitch = 0;
  662. // Create mouseshape as texture
  663. HRESULT hr = m_Device->CreateTexture2D(&Desc, &InitData, &MouseTex);
  664. if (FAILED(hr)) {
  665. return ProcessFailure(m_Device, L"Failed to create mouse pointer texture", L"Error", hr, SystemTransitionsExpectedErrors);
  666. }
  667. // Create shader resource from texture
  668. hr = m_Device->CreateShaderResourceView(MouseTex, &SDesc, &ShaderRes);
  669. if (FAILED(hr)) {
  670. MouseTex->Release();
  671. MouseTex = nullptr;
  672. return ProcessFailure(m_Device, L"Failed to create shader resource from mouse pointer texture", L"Error", hr, SystemTransitionsExpectedErrors);
  673. }
  674. D3D11_BUFFER_DESC BDesc;
  675. ZeroMemory(&BDesc, sizeof(D3D11_BUFFER_DESC));
  676. BDesc.Usage = D3D11_USAGE_DEFAULT;
  677. BDesc.ByteWidth = sizeof(VERTEX) * NUMVERTICES;
  678. BDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  679. BDesc.CPUAccessFlags = 0;
  680. ZeroMemory(&InitData, sizeof(D3D11_SUBRESOURCE_DATA));
  681. InitData.pSysMem = Vertices;
  682. // Create vertex buffer
  683. hr = m_Device->CreateBuffer(&BDesc, &InitData, &VertexBufferMouse);
  684. if (FAILED(hr)) {
  685. ShaderRes->Release();
  686. ShaderRes = nullptr;
  687. MouseTex->Release();
  688. MouseTex = nullptr;
  689. return ProcessFailure(m_Device, L"Failed to create mouse pointer vertex buffer in OutputManager", L"Error", hr, SystemTransitionsExpectedErrors);
  690. }
  691. // Set resources
  692. FLOAT BlendFactor[4] = {0.f, 0.f, 0.f, 0.f};
  693. UINT Stride = sizeof(VERTEX);
  694. UINT Offset = 0;
  695. m_DeviceContext->IASetVertexBuffers(0, 1, &VertexBufferMouse, &Stride, &Offset);
  696. m_DeviceContext->OMSetBlendState(m_BlendState, BlendFactor, 0xFFFFFFFF);
  697. m_DeviceContext->OMSetRenderTargets(1, &m_RTV, nullptr);
  698. m_DeviceContext->VSSetShader(m_VertexShader, nullptr, 0);
  699. m_DeviceContext->PSSetShader(m_PixelShader, nullptr, 0);
  700. m_DeviceContext->PSSetShaderResources(0, 1, &ShaderRes);
  701. m_DeviceContext->PSSetSamplers(0, 1, &m_SamplerLinear);
  702. // Draw
  703. m_DeviceContext->Draw(NUMVERTICES, 0);
  704. // Clean
  705. if (VertexBufferMouse) {
  706. VertexBufferMouse->Release();
  707. VertexBufferMouse = nullptr;
  708. }
  709. if (ShaderRes) {
  710. ShaderRes->Release();
  711. ShaderRes = nullptr;
  712. }
  713. if (MouseTex) {
  714. MouseTex->Release();
  715. MouseTex = nullptr;
  716. }
  717. if (InitBuffer) {
  718. delete [] InitBuffer;
  719. InitBuffer = nullptr;
  720. }
  721. return DUPL_RETURN_SUCCESS;
  722. }
  723. //
  724. // Initialize shaders for drawing to screen
  725. //
  726. DUPL_RETURN OUTPUTMANAGER::InitShaders()
  727. {
  728. HRESULT hr;
  729. UINT Size = ARRAYSIZE(g_VS);
  730. hr = m_Device->CreateVertexShader(g_VS, Size, nullptr, &m_VertexShader);
  731. if (FAILED(hr)) {
  732. return ProcessFailure(m_Device, L"Failed to create vertex shader in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  733. }
  734. D3D11_INPUT_ELEMENT_DESC Layout[] = {
  735. {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  736. {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
  737. };
  738. UINT NumElements = ARRAYSIZE(Layout);
  739. hr = m_Device->CreateInputLayout(Layout, NumElements, g_VS, Size, &m_InputLayout);
  740. if (FAILED(hr)) {
  741. return ProcessFailure(m_Device, L"Failed to create input layout in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  742. }
  743. m_DeviceContext->IASetInputLayout(m_InputLayout);
  744. Size = ARRAYSIZE(g_PS);
  745. hr = m_Device->CreatePixelShader(g_PS, Size, nullptr, &m_PixelShader);
  746. if (FAILED(hr)) {
  747. return ProcessFailure(m_Device, L"Failed to create pixel shader in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  748. }
  749. return DUPL_RETURN_SUCCESS;
  750. }
  751. //
  752. // Reset render target view
  753. //
  754. DUPL_RETURN OUTPUTMANAGER::MakeRTV()
  755. {
  756. // Get backbuffer
  757. ID3D11Texture2D* BackBuffer = nullptr;
  758. HRESULT hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&BackBuffer));
  759. if (FAILED(hr)) {
  760. return ProcessFailure(m_Device, L"Failed to get backbuffer for making render target view in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  761. }
  762. // Create a render target view
  763. hr = m_Device->CreateRenderTargetView(BackBuffer, nullptr, &m_RTV);
  764. BackBuffer->Release();
  765. if (FAILED(hr)) {
  766. return ProcessFailure(m_Device, L"Failed to create render target view in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  767. }
  768. // Set new render target
  769. m_DeviceContext->OMSetRenderTargets(1, &m_RTV, nullptr);
  770. return DUPL_RETURN_SUCCESS;
  771. }
  772. //
  773. // Set new viewport
  774. //
  775. void OUTPUTMANAGER::SetViewPort(UINT Width, UINT Height)
  776. {
  777. D3D11_VIEWPORT VP;
  778. VP.Width = static_cast<FLOAT>(Width);
  779. VP.Height = static_cast<FLOAT>(Height);
  780. VP.MinDepth = 0.0f;
  781. VP.MaxDepth = 1.0f;
  782. VP.TopLeftX = 0;
  783. VP.TopLeftY = 0;
  784. m_DeviceContext->RSSetViewports(1, &VP);
  785. }
  786. //
  787. // Resize swapchain
  788. //
  789. DUPL_RETURN OUTPUTMANAGER::ResizeSwapChain()
  790. {
  791. if (m_RTV) {
  792. m_RTV->Release();
  793. m_RTV = nullptr;
  794. }
  795. RECT WindowRect;
  796. GetClientRect(m_WindowHandle, &WindowRect);
  797. UINT Width = WindowRect.right - WindowRect.left;
  798. UINT Height = WindowRect.bottom - WindowRect.top;
  799. // Resize swapchain
  800. DXGI_SWAP_CHAIN_DESC SwapChainDesc;
  801. m_SwapChain->GetDesc(&SwapChainDesc);
  802. HRESULT hr = m_SwapChain->ResizeBuffers(SwapChainDesc.BufferCount, Width, Height, SwapChainDesc.BufferDesc.Format, SwapChainDesc.Flags);
  803. if (FAILED(hr)) {
  804. return ProcessFailure(m_Device, L"Failed to resize swapchain buffers in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
  805. }
  806. // Make new render target view
  807. DUPL_RETURN Ret = MakeRTV();
  808. if (Ret != DUPL_RETURN_SUCCESS) {
  809. return Ret;
  810. }
  811. // Set new viewport
  812. SetViewPort(Width, Height);
  813. return Ret;
  814. }
  815. //
  816. // Releases all references
  817. //
  818. void OUTPUTMANAGER::CleanRefs()
  819. {
  820. if (m_VertexShader) {
  821. m_VertexShader->Release();
  822. m_VertexShader = nullptr;
  823. }
  824. if (m_PixelShader) {
  825. m_PixelShader->Release();
  826. m_PixelShader = nullptr;
  827. }
  828. if (m_InputLayout) {
  829. m_InputLayout->Release();
  830. m_InputLayout = nullptr;
  831. }
  832. if (m_RTV) {
  833. m_RTV->Release();
  834. m_RTV = nullptr;
  835. }
  836. if (m_SamplerLinear) {
  837. m_SamplerLinear->Release();
  838. m_SamplerLinear = nullptr;
  839. }
  840. if (m_BlendState) {
  841. m_BlendState->Release();
  842. m_BlendState = nullptr;
  843. }
  844. if (m_DeviceContext) {
  845. m_DeviceContext->Release();
  846. m_DeviceContext = nullptr;
  847. }
  848. if (m_Device) {
  849. m_Device->Release();
  850. m_Device = nullptr;
  851. }
  852. if (m_SwapChain) {
  853. m_SwapChain->Release();
  854. m_SwapChain = nullptr;
  855. }
  856. if (m_SharedSurf) {
  857. m_SharedSurf->Release();
  858. m_SharedSurf = nullptr;
  859. }
  860. if (m_KeyMutex) {
  861. m_KeyMutex->Release();
  862. m_KeyMutex = nullptr;
  863. }
  864. if (m_Factory) {
  865. if (m_OcclusionCookie) {
  866. m_Factory->UnregisterOcclusionStatus(m_OcclusionCookie);
  867. m_OcclusionCookie = 0;
  868. }
  869. m_Factory->Release();
  870. m_Factory = nullptr;
  871. }
  872. }