Repository: Microsoft/WPFDXInterop Branch: master Commit: 83527f8df97d Files: 54 Total size: 267.6 KB Directory structure: gitextract_7_bjs1s0/ ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── samples/ │ └── D3D11Image/ │ ├── D3D11Visualization/ │ │ ├── D3DVisualization.cpp │ │ ├── D3DVisualization.fx │ │ ├── D3DVisualization.h │ │ ├── D3DVisualization.rc │ │ ├── D3DVisualization.vcxproj │ │ ├── D3DVisualization.vcxproj.filters │ │ ├── D3DVisualization_dxsdk.vcxproj │ │ ├── D3DVisualization_dxsdk.vcxproj.filters │ │ ├── D3DVisualization_winsdk.vcxproj │ │ ├── D3DVisualization_winsdk.vcxproj.filters │ │ ├── DX11Utils.cpp │ │ ├── DX11Utils.h │ │ ├── OrbitCamera.cpp │ │ ├── OrbitCamera.h │ │ └── Resource.h │ ├── WpfD3D11Interop/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── Properties/ │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resources.Designer.cs │ │ │ ├── Resources.resx │ │ │ ├── Settings.Designer.cs │ │ │ └── Settings.settings │ │ ├── WpfD3D11Interop.csproj │ │ ├── app.config │ │ └── packages.config │ ├── WpfD3D11Interop_dxsdk.sln │ └── WpfD3D11Interop_winsdk.sln ├── scripts/ │ ├── BuildNuGetPackage.cmd │ └── Microsoft.Wpf.Interop.DirectX.nuspec └── src/ ├── Microsoft.Wpf.Interop.DirectX/ │ ├── AssemblyInfo.cpp │ ├── D3D11Image.cpp │ ├── D3D11Image.h │ ├── Microsoft.Wpf.Interop.DirectX_dxsdk.vcxproj │ ├── Microsoft.Wpf.Interop.DirectX_winsdk.vcxproj │ ├── Stdafx.cpp │ ├── Stdafx.h │ ├── SurfaceDevice10.cpp │ ├── SurfaceDevice11.cpp │ ├── SurfaceDevice9.cpp │ ├── SurfaceQueue.cpp │ ├── SurfaceQueue.h │ ├── SurfaceQueue.inl │ ├── SurfaceQueueImpl.h │ ├── SurfaceQueueInteropHelper.cpp │ ├── SurfaceQueueInteropHelper.h │ └── version.rc ├── Microsoft.Wpf.Interop.DirectX_dxsdk.sln └── Microsoft.Wpf.Interop.DirectX_winsdk.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/visualstudio ### VisualStudio ### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # Windows Azure Build Output csx/ *.build.csdef # Windows Store app package directory AppPackages/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Microsoft Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # **WPF DirectX Extensions** WPF DirectX Extensions allow you to easily host DirectX 10 and DirectX 11 content in WPF applications. Getting Started ------------------- **Where to get it** - NuGet package - [x86](https://www.nuget.org/packages/Microsoft.Wpf.Interop.DirectX-x86/0.9.0-beta-22856) - [x64](https://www.nuget.org/packages/Microsoft.Wpf.Interop.DirectX-x64/0.9.0-beta-22856) - [Source Code](https://github.com/Microsoft/WPFDXInterop) **Resources** - [Documentation](https://github.com/Microsoft/WPFDXInterop/wiki) - [Samples](/samples) **More Info** - [Report a bug or ask a question](https://github.com/Microsoft/WPFDXInterop/issues) - [License](http://opensource.org/licenses/MIT) Code Example ------------ ***XAML*** ``` ``` ***C#*** The C# portions of interfacing with a native component that generates the DX visualization is not concise enough to host as an example. We would recommend that you look at sample code [here](https://github.com/Microsoft/WPFDXInterop/blob/master/samples/D3D11Image/WpfD3D11Interop/MainWindow.xaml.cs) to get a detailed understanding of the code required Using WPF DirectX Extensions ------------------- The [documentation](https://github.com/Microsoft/WPFDXInterop/wiki) explains how to install Visual Studio, add the WPF DirectX Extension NuGet package to your project, and get started using the API. Building WPF DirectX Extensions from Source ------------------------------ **What You Need** - [Visual Studio 2015](https://www.visualstudio.com/features/wpf-vs) - [DirectX SDK](http://www.microsoft.com/en-us/download/details.aspx?id=6812) - [Windows SDK](https://dev.windows.com/en-us/downloads/windows-10-sdk) **Build and Create WPF DirectX Extensions NuGet** - [Clone the Repository](https://github.com/Microsoft/WPFDXInterop) - Open Microsoft.Wpf.Interop.DirectX_winsdk or Microsoft.Wpf.Interop.DirectX_dxsdk solution from [Source](/src) in Visual Studio - Change Build Configuration to Release and build for x86 and x64 - Run BuildNuGetPackage in [scripts](/scripts) to create nuget packages ================================================ FILE: SECURITY.md ================================================ ## Security Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. ## Reporting Security Issues **Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) * Full paths of source file(s) related to the manifestation of the issue * The location of the affected source code (tag/branch/commit or direct URL) * Any special configuration required to reproduce the issue * Step-by-step instructions to reproduce the issue * Proof-of-concept or exploit code (if possible) * Impact of the issue, including how an attacker might exploit the issue This information will help us triage your report more quickly. If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. ## Preferred Languages We prefer all communications to be in English. ## Policy Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.cpp ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #include "D3DVisualization.h" #ifndef DIRECTX_SDK using namespace DirectX; using namespace DirectX::PackedVector; #endif // Global Variables CCube * pApplication; // Application class //-------------------------------------------------------------------------------------- // Structures //-------------------------------------------------------------------------------------- struct SimpleVertex { XMFLOAT3 Pos; XMFLOAT4 Color; }; struct ConstantBuffer { XMMATRIX mWorld; XMMATRIX mView; XMMATRIX mProjection; }; BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD fwdReason, LPVOID lpvReserved) { return TRUE; } /// /// Init global class instance /// extern HRESULT __cdecl Init() { pApplication = new CCube(); HRESULT hr = S_OK; if ( FAILED( hr = pApplication->InitDevice() ) ) { return hr; } return hr; } /// /// Cleanup global class instance /// extern void __cdecl Cleanup() { delete pApplication; pApplication = NULL; } /// /// Render for global class instance /// extern HRESULT __cdecl Render(void * pResource, bool isNewSurface) { if ( NULL == pApplication ) { return E_FAIL; } return pApplication->Render(pResource, isNewSurface); } /// /// Sets the Radius value of the camera /// extern HRESULT _cdecl SetCameraRadius(float r) { if ( NULL == pApplication ) { return E_FAIL; } pApplication->GetCamera()->SetRadius(r); return 0; } /// /// Sets the Theta value of the camera /// Theta represents the angle (in radians) of the camera around the /// center in the x-y plane /// extern HRESULT _cdecl SetCameraTheta(float theta) { if ( NULL == pApplication ) { return E_FAIL; } pApplication->GetCamera()->SetTheta(theta); return 0; } /// /// Sets the Phi value of the camera /// Phi represents angle (in radians) of the camera around the center /// in the y-z plane (over the top and below the scene) /// extern HRESULT _cdecl SetCameraPhi(float phi) { if ( NULL == pApplication ) { return E_FAIL; } pApplication->GetCamera()->SetPhi(phi); return 0; } /// /// Constructor /// CCube::CCube() { m_Height = 0; m_Width = 0; m_hInst = NULL; m_featureLevel = D3D_FEATURE_LEVEL_11_0; m_pd3dDevice = NULL; m_pImmediateContext = NULL; m_pVertexLayout = NULL; m_pVertexBuffer = NULL; m_pVertexShader = NULL; m_pPixelShader = NULL; } /// /// Destructor /// CCube::~CCube() { if (m_pImmediateContext) { m_pImmediateContext->ClearState(); } SAFE_RELEASE(m_pIndexBuffer); SAFE_RELEASE(m_pPixelShader); SAFE_RELEASE(m_pVertexBuffer); SAFE_RELEASE(m_pVertexLayout); SAFE_RELEASE(m_pVertexShader); SAFE_RELEASE(m_pImmediateContext); SAFE_RELEASE(m_pd3dDevice); } /// /// Compile and set layout for shaders /// /// S_OK for success, or failure code HRESULT CCube::LoadShaders() { HRESULT hr = S_OK; // Compile the pixel shader ID3DBlob* pPSBlob = NULL; hr = CompileShaderFromFile(L"D3DVisualization.fx", "PS", "ps_4_0", &pPSBlob); if (FAILED(hr)) { MessageBox(NULL, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK); return hr; } // Create the pixel shader hr = m_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &m_pPixelShader); pPSBlob->Release(); if (FAILED(hr)) return hr; // Compile the vertex shader ID3DBlob* pVSBlob = NULL; hr = CompileShaderFromFile(L"D3DVisualization.fx", "VS", "vs_4_0", &pVSBlob); if (FAILED(hr)) { MessageBox(NULL, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK); return hr; } // Create the vertex shader hr = m_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pVertexShader); if (FAILED(hr)) { pVSBlob->Release(); return hr; } // Define the input layout D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = ARRAYSIZE(layout); // Create the input layout hr = m_pd3dDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &m_pVertexLayout); pVSBlob->Release(); if (FAILED(hr)) return hr; // Set the input layout m_pImmediateContext->IASetInputLayout(m_pVertexLayout); return hr; } /// /// Create Direct3D device /// /// S_OK for success, or failure code HRESULT CCube::InitDevice() { HRESULT hr = S_OK; UINT createDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = ARRAYSIZE(driverTypes); // DX10 or 11 devices are suitable D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, }; UINT numFeatureLevels = ARRAYSIZE(featureLevels); for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; ++driverTypeIndex) { hr = D3D11CreateDevice(NULL, driverTypes[driverTypeIndex], NULL, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &m_pd3dDevice, &m_featureLevel, &m_pImmediateContext); if ( SUCCEEDED(hr) ) { m_driverType = driverTypes[driverTypeIndex]; break; } } if ( FAILED(hr) ) { MessageBox(NULL, L"Could not create a Direct3D 10 or 11 device.", L"Error", MB_ICONHAND | MB_OK); return hr; } hr = LoadShaders(); if ( FAILED(hr) ) { MessageBox(NULL, L"Could not load shaders.", L"Error", MB_ICONHAND | MB_OK); return hr; } // Create vertex buffer SimpleVertex vertices[] = { { XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 0.5f) }, { XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 0.5f) }, { XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 0.5f) }, { XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 0.5f) }, { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 0.5f) }, { XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 0.5f) }, { XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 0.5f) }, { XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 0.5f) }, }; D3D11_BUFFER_DESC bd; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(SimpleVertex)* 8; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA InitData; ZeroMemory(&InitData, sizeof(InitData)); InitData.pSysMem = vertices; hr = m_pd3dDevice->CreateBuffer(&bd, &InitData, &m_pVertexBuffer); if (FAILED(hr)) return hr; // Set vertex buffer UINT stride = sizeof(SimpleVertex); UINT offset = 0; m_pImmediateContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset); // Create index buffer WORD indices[] = { 3, 1, 0, 2, 1, 3, 0, 5, 4, 1, 5, 0, 3, 4, 7, 0, 4, 3, 1, 6, 5, 2, 6, 1, 2, 7, 6, 3, 7, 2, 6, 4, 5, 7, 4, 6, }; bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(WORD)* 36; // 36 vertices needed for 12 triangles in a triangle list bd.BindFlags = D3D11_BIND_INDEX_BUFFER; bd.CPUAccessFlags = 0; InitData.pSysMem = indices; hr = m_pd3dDevice->CreateBuffer(&bd, &InitData, &m_pIndexBuffer); if (FAILED(hr)) return hr; // Set index buffer m_pImmediateContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0); // Set primitive topology m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Create the constant buffer bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(ConstantBuffer); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; hr = m_pd3dDevice->CreateBuffer(&bd, NULL, &m_pConstantBuffer); if (FAILED(hr)) return hr; // Initialize the world matrix m_World = XMMatrixIdentity(); // Initialize the view matrix XMVECTOR Eye = XMVectorSet(0.0f, 1.0f, -5.0f, 0.0f); XMVECTOR At = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); m_View = XMMatrixLookAtLH(Eye, At, Up); return S_OK; } void CCube::SetUpViewport() { // Setup the viewport D3D11_VIEWPORT vp; vp.Width = (float)m_Width; vp.Height = (float)m_Height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; m_pImmediateContext->RSSetViewports(1, &vp); // Initialize the projection matrix m_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, m_Width / (FLOAT)m_Height, 0.01f, 100.0f); } /// /// Initializes RenderTarget /// /// S_OK for success, or failure code HRESULT CCube::InitRenderTarget(void * pResource) { HRESULT hr = S_OK; IUnknown *pUnk = (IUnknown*)pResource; IDXGIResource * pDXGIResource; hr = pUnk->QueryInterface(__uuidof(IDXGIResource), (void**)&pDXGIResource); if (FAILED(hr)) { return hr; } HANDLE sharedHandle; hr = pDXGIResource->GetSharedHandle(&sharedHandle); if (FAILED(hr)) { return hr; } pDXGIResource->Release(); IUnknown * tempResource11; hr = m_pd3dDevice->OpenSharedResource(sharedHandle, __uuidof(ID3D11Resource), (void**)(&tempResource11)); if (FAILED(hr)) { return hr; } ID3D11Texture2D * pOutputResource; hr = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)(&pOutputResource)); if (FAILED(hr)) { return hr; } tempResource11->Release(); D3D11_RENDER_TARGET_VIEW_DESC rtDesc; rtDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtDesc.Texture2D.MipSlice = 0; hr = m_pd3dDevice->CreateRenderTargetView(pOutputResource, &rtDesc, &m_pRenderTargetView); if (FAILED(hr)) { return hr; } D3D11_TEXTURE2D_DESC outputResourceDesc; pOutputResource->GetDesc(&outputResourceDesc); if ( outputResourceDesc.Width != m_Width || outputResourceDesc.Height != m_Height ) { m_Width = outputResourceDesc.Width; m_Height = outputResourceDesc.Height; SetUpViewport(); } m_pImmediateContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL); if ( NULL != pOutputResource ) { pOutputResource->Release(); } return hr; } /// /// Renders a frame /// /// S_OK for success, or failure code HRESULT CCube::Render(void * pResource, bool isNewSurface) { HRESULT hr = S_OK; // If we've gotten a new Surface, need to initialize the renderTarget. // One of the times that this happens is on a resize. if ( isNewSurface ) { m_pImmediateContext->OMSetRenderTargets(0, NULL, NULL); hr = InitRenderTarget(pResource); if (FAILED(hr)) { return hr; } } // Update our time static float t = 0.0f; if (m_driverType == D3D_DRIVER_TYPE_REFERENCE) { t += (float)XM_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if (dwTimeStart == 0) dwTimeStart = dwTimeCur; t = (dwTimeCur - dwTimeStart) / 1000.0f; } // // Animate the cube // m_World = XMMatrixRotationX(t) * XMMatrixRotationY(t); // Clear the back buffer static float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, ClearColor); // Update the view matrix m_camera.Update(); XMMATRIX viewProjection = XMMatrixMultiply(m_camera.View, m_Projection); ConstantBuffer cb; cb.mWorld = XMMatrixTranspose(m_World); cb.mView = XMMatrixTranspose(m_View); cb.mProjection = XMMatrixTranspose(viewProjection); m_pImmediateContext->UpdateSubresource(m_pConstantBuffer, 0, NULL, &cb, 0, 0); // Renders a triangle m_pImmediateContext->VSSetShader(m_pVertexShader, NULL, 0); m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffer); m_pImmediateContext->PSSetShader(m_pPixelShader, NULL, 0); m_pImmediateContext->DrawIndexed(36, 0, 0); // 36 vertices needed for 12 triangles in a triangle list if ( NULL != m_pImmediateContext ) { m_pImmediateContext->Flush(); } return 0; } /// /// Method for retreiving the camera /// /// Pointer to the camera CCamera* CCube::GetCamera() { return &m_camera; } ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.fx ================================================ //-------------------------------------------------------------------------------------- // File: D3DVisualization.fx // Originally from DirectX SDK - Tutorial 4 sample // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- cbuffer ConstantBuffer : register(b0) { matrix World; matrix View; matrix Projection; } //-------------------------------------------------------------------------------------- struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS(float4 Pos : POSITION, float4 Color : COLOR) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = mul(Pos, World); output.Pos = mul(output.Pos, View); output.Pos = mul(output.Pos, Projection); output.Color = Color; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS(VS_OUTPUT input) : SV_Target { return input.Color; } ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.h ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #pragma once #include #include #ifdef DIRECTX_SDK // requires DirectX SDK June 2010 #include #define DirectX_NS // DirectX SDK requires a blank namespace for several types #else // Windows SDK #include #include #define DirectX_NS DirectX // Windows SDK requires a DirectX namespace for several types #endif #include "OrbitCamera.h" #include "DX11Utils.h" #include "resource.h" extern "C" { __declspec(dllexport) HRESULT __cdecl Init(); } extern "C" { __declspec(dllexport) void __cdecl Cleanup(); } extern "C" { __declspec(dllexport) HRESULT __cdecl Render(void * pResource, bool isNewSurface); } extern "C" { __declspec(dllexport) HRESULT __cdecl SetCameraRadius(float r); } extern "C" { __declspec(dllexport) HRESULT __cdecl SetCameraTheta(float theta); } extern "C" { __declspec(dllexport) HRESULT __cdecl SetCameraPhi(float phi); } class CCube { public: /// /// Constructor /// CCube(); /// /// Destructor /// ~CCube(); /// /// Create Direct3D device and swap chain /// /// S_OK for success, or failure code HRESULT InitDevice(); /// /// Renders a frame /// /// S_OK for success, or failure code HRESULT Render(void * pResource, bool isNewSurface); /// /// Method for retrieving the camera /// /// Pointer to the camera CCamera* GetCamera(); // Special function definitions to ensure alignment between c# and c++ void* operator new(size_t size) { return _aligned_malloc(size, 16); } void operator delete(void *p) { _aligned_free(p); } private: HRESULT InitRenderTarget(void * pResource); void SetUpViewport(); // 3d camera CCamera m_camera; HINSTANCE m_hInst; D3D_DRIVER_TYPE m_driverType; D3D_FEATURE_LEVEL m_featureLevel; ID3D11Device* m_pd3dDevice; ID3D11DeviceContext* m_pImmediateContext; IDXGISwapChain* m_pSwapChain = NULL; ID3D11RenderTargetView* m_pRenderTargetView = NULL; ID3D11InputLayout* m_pVertexLayout; ID3D11Buffer* m_pVertexBuffer; ID3D11Buffer* m_pIndexBuffer = NULL; ID3D11Buffer* m_pConstantBuffer = NULL; DirectX_NS::XMMATRIX m_World; DirectX_NS::XMMATRIX m_View; DirectX_NS::XMMATRIX m_Projection; ID3D11VertexShader* m_pVertexShader; ID3D11PixelShader* m_pPixelShader; // Initial window resolution UINT m_Width; UINT m_Height; /// /// Compile and set layout for shaders /// /// S_OK for success, or failure code HRESULT LoadShaders(); }; ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.rc ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ //Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // Dialog // #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 Document true {3FEB553A-62BD-42E1-9A70-0CD3E45929D0} D3DVisualization D3DVisualization .dll DynamicLibrary true Unicode v120 DynamicLibrary true Unicode v120 DynamicLibrary false true Unicode v120 DynamicLibrary false true Unicode v120 .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x64;$(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(SolutionDir)x64\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x64;$(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(SolutionDir)x64\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 Disabled WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\"" ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Resource Files Source Files Source Files Source Files ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization_dxsdk.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 Document true {3FEB553A-62BD-42E1-9A70-0CD3E45929D0} D3DVisualization D3DVisualization .dll DynamicLibrary true Unicode v120 DynamicLibrary true Unicode v120 DynamicLibrary false true Unicode v120 DynamicLibrary false true Unicode v120 .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x64;$(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(SolutionDir)x64\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x64;$(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(SolutionDir)x64\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 Disabled DIRECTX_SDK;WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\"" ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization_dxsdk.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Resource Files Source Files Source Files Source Files ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization_winsdk.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 Document true {D73DCE48-0DBC-40FE-AC89-2C06AF01060B} D3DVisualization D3DVisualization .dll 10.0.10240.0 DynamicLibrary true Unicode v140 DynamicLibrary true Unicode v140 DynamicLibrary false true Unicode v140 DynamicLibrary false true Unicode v140 .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(ExecutablePath) $(IncludePath) $(LibraryPath) false $(SolutionDir)x64\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x86 false $(SolutionDir)x86\$(Configuration)\ .dll $(DXSDK_DIR)Utilities\bin\x64;$(DXSDK_DIR)Utilities\bin\x86;$(ExecutablePath) $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(SolutionDir)x64\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 Disabled WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x86\$(Configuration)\" Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;D3DXFX_LARGEADDRESS_HANDLE;%(PreprocessorDefinitions) MultiThreadedDLL true true true d3d11.lib;d3dcompiler.lib;d3dx11d.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies) copy d3dvisualization.fx "$(SolutionDir)x64\$(Configuration)\"" ================================================ FILE: samples/D3D11Image/D3D11Visualization/D3DVisualization_winsdk.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Resource Files Source Files Source Files Source Files ================================================ FILE: samples/D3D11Image/D3D11Visualization/DX11Utils.cpp ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #include "DX11Utils.h" #ifdef DIRECTX_SDK // requires DirectX SDK June 2010 #include #else // Windows SDK #include #include #endif /// /// Helper for compiling shaders with D3DX11 /// /// full path to shader to compile /// entry point of shader /// shader model to compile for /// holds result of compilation /// S_OK for success, or failure code HRESULT CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3D10Blob** ppBlobOut) { HRESULT hr = S_OK; ID3D10Blob* pErrorBlob = NULL; #ifdef DIRECTX_SDK // requires DirectX SDK June 2010 hr = D3DX11CompileFromFileW( szFileName, NULL, NULL, szEntryPoint, szShaderModel, 0, 0, NULL, ppBlobOut, &pErrorBlob, NULL ); #else // Windows SDK hr = D3DCompileFromFile(szFileName, NULL, NULL, szEntryPoint, szShaderModel, 0, 0, ppBlobOut, &pErrorBlob); #endif if ( FAILED(hr) ) { if (NULL != pErrorBlob) { OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() ); } } SAFE_RELEASE(pErrorBlob); return hr; } ================================================ FILE: samples/D3D11Image/D3D11Visualization/DX11Utils.h ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #pragma once #include #include #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } } #endif #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } #endif /// /// Helper for compiling shaders with D3DX11 /// /// full path to shader to compile /// entry point of shader /// shader model to compile for /// holds result of compilation /// S_OK for success, or failure code HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3D10Blob** ppBlobOut ); ================================================ FILE: samples/D3D11Image/D3D11Visualization/OrbitCamera.cpp ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #include "OrbitCamera.h" #ifndef DIRECTX_SDK // Windows SDK using namespace DirectX; using namespace DirectX::PackedVector; #endif /// /// Constructor /// CCamera::CCamera() { Reset(); } /// /// Move camera into position /// int CCamera::UpdatePosition() { m_eye = XMVectorSet(r * sinf(theta) * cosf(phi), r * sinf(phi), -r * cosf(theta) * cosf(phi), 0.0F); return 0; } /// /// Reset the camera state to initial values /// void CCamera::Reset() { View = XMMatrixIdentity(); m_eye = XMVectorSet(0.f, 0.f, -0.3f, 0.f); m_at = XMVectorSet(0.f, 0.f, 1.0f, 0.f); m_up = XMVectorSet(0.f, 1.f, 0.f, 0.f); } /// /// Update the view matrix /// void CCamera::Update() { View = XMMatrixLookAtLH(m_eye + m_at, m_at, m_up); } /// /// Sets the center depth of the rendered image /// void CCamera::SetCenterDepth(float depth) { m_at = XMVectorSet(0.0f, 0.0f, depth, 0.0f); } /// /// Sets the R value of the camera from the depth center /// R value represents the distance of the camera from the players /// void CCamera::SetRadius(float r) { this->r = r; UpdatePosition(); } /// /// Sets the Theta value of the camera from around the depth center /// Theta represents the angle (in radians) of the camera around the /// center in the x-y plane (circling around players) /// void CCamera::SetTheta(float theta) { this->theta = theta; UpdatePosition(); } /// /// Sets the Phi value of the camera /// Phi represents angle (in radians) of the camera around the center /// in the y-z plane (over the top and below players) /// void CCamera::SetPhi(float phi) { this->phi = phi; UpdatePosition(); } ================================================ FILE: samples/D3D11Image/D3D11Visualization/OrbitCamera.h ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #pragma once #include #ifdef DIRECTX_SDK // requires DirectX SDK June 2010 #include #define DirectX_NS // DirectX SDK requires a blank namespace for several types #else // Windows SDK #include #include #define DirectX_NS DirectX // Windows SDK requires a DirectX namespace for several types #endif class CCamera { public: DirectX_NS::XMMATRIX View; /// /// Constructor /// CCamera(); /// /// Reset the camera state to initial values /// void Reset(); /// /// Update the view matrix /// void Update(); /// /// Move camera into position /// int UpdatePosition(); /// /// Sets the R value of the camera. /// R value represents the distance of the camera from the center /// void SetRadius(float r); /// /// Sets the Theta value of the camera from around the depth center /// Theta represents the angle (in radians) of the camera around the /// center in the x-y plane (circling around players) /// void SetTheta(float theta); /// /// Sets the Phi value of the camera /// Phi represents angle (in radians) of the camera around the center /// in the y-z plane (over the top and below players) /// void SetPhi(float phi); /// /// Get the camera's up vector /// /// camera's up vector DirectX_NS::XMVECTOR GetUp() { return m_up; } /// /// Get the camera's position vector /// /// camera's position vector DirectX_NS::XMVECTOR GetEye() { return m_eye; } /// /// Sets the center depth of the rendered image /// void SetCenterDepth(float depth); private: float r; float theta; float phi; DirectX_NS::XMVECTOR m_eye; DirectX_NS::XMVECTOR m_at; DirectX_NS::XMVECTOR m_up; }; ================================================ FILE: samples/D3D11Image/D3D11Visualization/Resource.h ================================================ //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Depth-D3D.rc // #define IDS_APP_TITLE 103 #define IDI_APP 107 #define IDC_STATIC -1 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 130 #define _APS_NEXT_RESOURCE_VALUE 129 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/App.xaml ================================================  ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/App.xaml.cs ================================================ namespace Microsoft.Samples.Wpf.D3D11Interop { using System.Windows; /// /// Interaction logic for App.xaml /// public partial class App : Application { } } ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/MainWindow.xaml ================================================  ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/MainWindow.xaml.cs ================================================ namespace Microsoft.Samples.Wpf.D3D11Interop { using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { // Magnifier Image Settings private const double MagImageScale = 1.25; // Scale of image to magnified ellipse private const double MagImageOffset = 0.12; // Offset of magnified ellipse within image // Unit conversion private const float DegreesToRadians = (float)Math.PI / 180; // State Management private bool magnify = true; TimeSpan lastRender; bool lastVisible; // Magnifier Settings (filled by default slider vlaues) private double magSize; private double magScale; public MainWindow() { this.InitializeComponent(); this.host.Loaded += new RoutedEventHandler(this.Host_Loaded); this.host.SizeChanged += new SizeChangedEventHandler(this.Host_SizeChanged); } private static bool Init() { bool initSucceeded = NativeMethods.InvokeWithDllProtection(() => NativeMethods.Init()) >= 0; if (!initSucceeded) { MessageBox.Show("Failed to initialize.", "WPF D3D Interop", MessageBoxButton.OK, MessageBoxImage.Error); if (Application.Current != null) { Application.Current.Shutdown(); } } return initSucceeded; } private static void Cleanup() { NativeMethods.InvokeWithDllProtection(NativeMethods.Cleanup); } private static int Render(IntPtr resourcePointer, bool isNewSurface) { return NativeMethods.InvokeWithDllProtection(() => NativeMethods.Render(resourcePointer, isNewSurface)); } private static int SetCameraRadius(float radius) { return NativeMethods.InvokeWithDllProtection(() => NativeMethods.SetCameraRadius(radius)); } private static int SetCameraTheta(float theta) { return NativeMethods.InvokeWithDllProtection(() => NativeMethods.SetCameraTheta(theta)); } private static int SetCameraPhi(float phi) { return NativeMethods.InvokeWithDllProtection(() => NativeMethods.SetCameraPhi(phi)); } #region Callbacks private void Host_Loaded(object sender, RoutedEventArgs e) { Init(); this.InitializeRendering(); // Setup the Magnifier Size MagEllipse.Height = this.magSize; MagEllipse.Width = this.magSize; Scale.Value = this.magScale; // Add mouse over event host.MouseMove += this.MagElement_MouseMove; ImageHost.MouseMove += this.MagElement_MouseMove; MagEllipse.MouseMove += this.MagElement_MouseMove; MagImage.MouseMove += this.MagElement_MouseMove; host.MouseLeave += this.MagElement_MouseLeave; MagEllipse.MouseLeave += this.MagElement_MouseLeave; ImageHost.MouseLeave += this.MagElement_MouseLeave; MagImage.MouseLeave += this.MagElement_MouseLeave; MagBox.Checked += this.MagBox_Checked; MagBox.Unchecked += this.MagBox_Unchecked; } private void Host_SizeChanged(object sender, SizeChangedEventArgs e) { double dpiScale = 1.0; // default value for 96 dpi // determine DPI // (as of .NET 4.6.1, this returns the DPI of the primary monitor, if you have several different DPIs) var hwndTarget = PresentationSource.FromVisual(this).CompositionTarget as HwndTarget; if (hwndTarget != null) { dpiScale = hwndTarget.TransformToDevice.M11; } int surfWidth = (int)(host.ActualWidth < 0 ? 0 : Math.Ceiling(host.ActualWidth * dpiScale)); int surfHeight = (int)(host.ActualHeight < 0 ? 0 : Math.Ceiling(host.ActualHeight * dpiScale)); // Notify the D3D11Image of the pixel size desired for the DirectX rendering. // The D3DRendering component will determine the size of the new surface it is given, at that point. InteropImage.SetPixelSize(surfWidth, surfHeight); // Stop rendering if the D3DImage isn't visible - currently just if width or height is 0 // TODO: more optimizations possible (scrolled off screen, etc...) bool isVisible = (surfWidth != 0 && surfHeight != 0); if (lastVisible != isVisible) { lastVisible = isVisible; if (lastVisible) { CompositionTarget.Rendering += CompositionTarget_Rendering; } else { CompositionTarget.Rendering -= CompositionTarget_Rendering; } } } private void Scale_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { this.magScale = e.NewValue; } private void Size_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { this.magSize = e.NewValue; // Setup the Magnifier Size this.MagEllipse.Height = this.magSize; this.MagEllipse.Width = this.magSize; } private void MagBox_Checked(object sender, RoutedEventArgs e) { this.magnify = true; MagCurserToggle1.Cursor = System.Windows.Input.Cursors.None; MagCurserToggle2.Cursor = System.Windows.Input.Cursors.None; host.Cursor = System.Windows.Input.Cursors.None; } private void MagBox_Unchecked(object sender, RoutedEventArgs e) { this.magnify = false; MagCurserToggle1.Cursor = System.Windows.Input.Cursors.Arrow; MagCurserToggle2.Cursor = System.Windows.Input.Cursors.Arrow; host.Cursor = System.Windows.Input.Cursors.Arrow; } private void MagElement_MouseMove(object sender, MouseEventArgs e) { if (this.magnify) { Point point = Mouse.GetPosition(host); if (!(point.X < 0 || point.Y < 0 || point.X > host.ActualWidth || point.Y > host.ActualHeight)) { // Draw the Magnified ellipse on top of image System.Windows.Controls.Canvas.SetTop(this.MagEllipse, point.Y - (this.magSize / 2)); System.Windows.Controls.Canvas.SetLeft(this.MagEllipse, point.X - (this.magSize / 2)); // Set the magnifier image on top of magnified ellipse System.Windows.Controls.Canvas.SetTop(this.MagImage, point.Y - (this.magSize * (.5 + MagImageOffset))); System.Windows.Controls.Canvas.SetLeft(this.MagImage, point.X - (this.magSize * (.5 + MagImageOffset))); MagImage.Width = this.magSize * MagImageScale; MagEllipse.Visibility = System.Windows.Visibility.Visible; MagImage.Visibility = System.Windows.Visibility.Visible; double magViewboxSize = this.magSize / this.magScale; MagBrush.Viewbox = new Rect(point.X - (.5 * magViewboxSize), point.Y - (.5 * magViewboxSize), magViewboxSize, magViewboxSize); } else { MagEllipse.Visibility = Visibility.Hidden; MagImage.Visibility = Visibility.Hidden; } } } private void MagElement_MouseLeave(object sender, MouseEventArgs e) { MagEllipse.Visibility = Visibility.Hidden; MagImage.Visibility = Visibility.Hidden; } private void Radius_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { SetCameraRadius((float)e.NewValue); } private void Theta_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { SetCameraTheta((float)e.NewValue * DegreesToRadians); } private void Phi_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { SetCameraPhi((float)e.NewValue * DegreesToRadians); } #endregion Callbacks #region Helpers private void InitializeRendering() { InteropImage.WindowOwner = (new System.Windows.Interop.WindowInteropHelper(this)).Handle; InteropImage.OnRender = this.DoRender; // Set up camera SetCameraRadius((float)RadiusSlider.Value); SetCameraPhi((float)PhiSlider.Value * DegreesToRadians); SetCameraTheta((float)ThetaSlider.Value * DegreesToRadians); // Start rendering now! InteropImage.RequestRender(); } void CompositionTarget_Rendering(object sender, EventArgs e) { RenderingEventArgs args = (RenderingEventArgs)e; // It's possible for Rendering to call back twice in the same frame // so only render when we haven't already rendered in this frame. if (this.lastRender != args.RenderingTime) { InteropImage.RequestRender(); this.lastRender = args.RenderingTime; } } private void UninitializeRendering() { Cleanup(); CompositionTarget.Rendering -= this.CompositionTarget_Rendering; } #endregion Helpers private void DoRender(IntPtr surface, bool isNewSurface) { Render(surface, isNewSurface); } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { this.UninitializeRendering(); host.MouseMove -= this.MagElement_MouseMove; ImageHost.MouseMove -= this.MagElement_MouseMove; MagEllipse.MouseMove -= this.MagElement_MouseMove; MagImage.MouseMove -= this.MagElement_MouseMove; host.MouseLeave -= this.MagElement_MouseLeave; MagEllipse.MouseLeave -= this.MagElement_MouseLeave; ImageHost.MouseLeave -= this.MagElement_MouseLeave; MagImage.MouseLeave -= this.MagElement_MouseLeave; MagBox.Checked -= this.MagBox_Checked; MagBox.Unchecked -= this.MagBox_Unchecked; } private static class NativeMethods { /// /// Variable used to track whether the missing dependency dialog has been displayed, /// used to prevent multiple notifications of the same failure. /// private static bool errorHasDisplayed; [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Init(); [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void Cleanup(); [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Render(IntPtr resourcePointer, bool isNewSurface); [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int SetCameraRadius(float radius); [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int SetCameraTheta(float theta); [DllImport("D3DVisualization.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int SetCameraPhi(float phi); /// /// Method used to invoke an Action that will catch DllNotFoundExceptions and display a warning dialog. /// /// The Action to invoke. public static void InvokeWithDllProtection(Action action) { InvokeWithDllProtection( () => { action.Invoke(); return 0; }); } /// /// Method used to invoke A Func that will catch DllNotFoundExceptions and display a warning dialog. /// /// The Func to invoke. /// The return value of func, or default(T) if a DllNotFoundException was caught. /// The return type of the func. public static T InvokeWithDllProtection(Func func) { try { return func.Invoke(); } catch (DllNotFoundException e) { if (!errorHasDisplayed) { MessageBox.Show("This sample requires:\nManual build of the D3DVisualization project, which requires installation of Windows 10 SDK or DirectX SDK.\n" + "Installation of the DirectX runtime on non-build machines.\n\n"+ "Detailed exception message: " + e.Message, "WPF D3D11 Interop", MessageBoxButton.OK, MessageBoxImage.Error); errorHasDisplayed = true; if (Application.Current != null) { Application.Current.Shutdown(); } } } return default(T); } } } } ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/Properties/AssemblyInfo.cs ================================================ using System; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; using System.Windows; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Wpf D3D11 Interop Sample")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // In order to begin building localizable applications, set // CultureYouAreCodingWith in your .csproj file // inside a . For example, if you are using US english // in your source files, set the to en-US. Then uncomment // the NeutralResourceLanguage attribute below. Update the "en-US" in // the line below to match the UICulture setting in the project file. ////[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] [assembly: ThemeInfo( ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located // (used if a resource is not found in the page, // or application resource dictionaries) ResourceDictionaryLocation.SourceAssembly // where the generic resource dictionary is located // (used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )] [assembly: NeutralResourcesLanguageAttribute("en-US")] [assembly: CLSCompliant(true)] ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/Properties/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Microsoft.Samples.Wpf.D3D11Interop.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("D3D11ImageSample.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/Properties/Settings.Designer.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Microsoft.Samples.Wpf.D3D11Interop.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } } } ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/Properties/Settings.settings ================================================  ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/WpfD3D11Interop.csproj ================================================  Debug x86 8.0.30703 2.0 {19855A82-A7EC-4E95-B0C4-B1A2356732B7} WinExe Properties Microsoft.Samples.Wpf.D3D11Interop WpfD3D11Interop v4.5 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 x86 ..\x86\Debug\ false false false x86 ..\x86\Release\ pdbonly false false x64 ..\x64\Debug\ false false x64 ..\x64\Release\ pdbonly false false ..\packages\Microsoft.Wpf.Interop.DirectX-x64.0.9.0-beta-22856\lib\net45\Microsoft.Wpf.Interop.DirectX.dll 4.0 App.xaml MainWindow.xaml Code True True Resources.resx True Settings.settings True ResXFileCodeGenerator Resources.Designer.cs SettingsSingleFileGenerator Settings.Designer.cs MSBuild:Compile Designer MSBuild:Compile Designer ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/app.config ================================================ ================================================ FILE: samples/D3D11Image/WpfD3D11Interop/packages.config ================================================  ================================================ FILE: samples/D3D11Image/WpfD3D11Interop_dxsdk.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfD3D11Interop", "WpfD3D11Interop\WpfD3D11Interop.csproj", "{19855A82-A7EC-4E95-B0C4-B1A2356732B7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3DVisualization_dxsdk", "D3D11Visualization\D3DVisualization_dxsdk.vcxproj", "{3FEB553A-62BD-42E1-9A70-0CD3E45929D0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x64.ActiveCfg = Debug|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x64.Build.0 = Debug|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x86.ActiveCfg = Debug|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x86.Build.0 = Debug|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x64.ActiveCfg = Release|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x64.Build.0 = Release|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x86.ActiveCfg = Release|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x86.Build.0 = Release|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x64.ActiveCfg = Debug|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x64.Build.0 = Debug|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x86.ActiveCfg = Debug|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x86.Build.0 = Debug|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x64.ActiveCfg = Release|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x64.Build.0 = Release|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x86.ActiveCfg = Release|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x86.Build.0 = Release|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x64.ActiveCfg = Debug|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x64.Build.0 = Debug|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x86.ActiveCfg = Debug|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x86.Build.0 = Debug|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x64.ActiveCfg = Release|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x64.Build.0 = Release|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x86.ActiveCfg = Release|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: samples/D3D11Image/WpfD3D11Interop_winsdk.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfD3D11Interop", "WpfD3D11Interop\WpfD3D11Interop.csproj", "{19855A82-A7EC-4E95-B0C4-B1A2356732B7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3DVisualization_winsdk", "D3D11Visualization\D3DVisualization_winsdk.vcxproj", "{D73DCE48-0DBC-40FE-AC89-2C06AF01060B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x64.ActiveCfg = Debug|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x64.Build.0 = Debug|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x86.ActiveCfg = Debug|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Debug|x86.Build.0 = Debug|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x64.ActiveCfg = Release|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x64.Build.0 = Release|x64 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x86.ActiveCfg = Release|Win32 {19855A82-A7EC-4E95-B0C4-B1A2356732B7}.Release|x86.Build.0 = Release|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x64.ActiveCfg = Debug|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x64.Build.0 = Debug|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x86.ActiveCfg = Debug|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Debug|x86.Build.0 = Debug|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x64.ActiveCfg = Release|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x64.Build.0 = Release|x64 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x86.ActiveCfg = Release|Win32 {3FEB553A-62BD-42E1-9A70-0CD3E45929D0}.Release|x86.Build.0 = Release|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x64.ActiveCfg = Debug|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x64.Build.0 = Debug|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x86.ActiveCfg = Debug|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Debug|x86.Build.0 = Debug|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x64.ActiveCfg = Release|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x64.Build.0 = Release|x64 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x86.ActiveCfg = Release|Win32 {D73DCE48-0DBC-40FE-AC89-2C06AF01060B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: scripts/BuildNuGetPackage.cmd ================================================ nuget.exe pack Microsoft.Wpf.Interop.DirectX.nuspec -Version 0.9.0-beta-99999 -Properties ArchitecturePublicName=x64;NuGetBinaries=..\src\x64\release -symbols nuget.exe pack Microsoft.Wpf.Interop.DirectX.nuspec -Version 0.9.0-beta-99999 -Properties ArchitecturePublicName=x86;NuGetBinaries=..\src\release -symbols ================================================ FILE: scripts/Microsoft.Wpf.Interop.DirectX.nuspec ================================================  Microsoft.Wpf.Interop.DirectX-$ArchitecturePublicName$ Microsoft.Wpf.Interop.DirectX-$ArchitecturePublicName$ $version$ Microsoft Microsoft, NugetWPF © Microsoft Corporation. All rights reserved true https://github.com/Microsoft/WPFDXInterop/blob/master/LICENSE Microsoft.Wpf.Interop.DirectX provides a new implementation of D3DImage that enables you to seamlessly interop with DirectX 10 or 11 content in your WPF application. https://github.com/Microsoft/WPFDXInterop http://go.microsoft.com/fwlink/?LinkID=532657 WPF DirectX D3DImage D3D11Image DirectX11 DirectX10 Microsoft.Wpf.Interop.DirectX.D3D11Image is a version of D3DImage that supports DirectX 11 or DirectX 10. For more information, check out the project here: https://github.com/Microsoft/WPFDXInterop ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/AssemblyInfo.cpp ================================================ // Copyright (c) Microsoft Corporation. All rights reserved. #include "stdafx.h" using namespace System; using namespace System::Reflection; using namespace System::Runtime::CompilerServices; using namespace System::Runtime::InteropServices; using namespace System::Security::Permissions; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/D3D11Image.cpp ================================================ #include "D3D11Image.h" namespace Microsoft { namespace Wpf { namespace Interop { namespace DirectX { static D3D11Image::D3D11Image() { OnRenderProperty = DependencyProperty::Register("OnRender", Action::typeid, D3D11Image::typeid, gcnew UIPropertyMetadata(nullptr, gcnew PropertyChangedCallback(&RenderChanged))); WindowOwnerProperty = DependencyProperty::Register("WindowOwner", IntPtr::typeid, D3D11Image::typeid, gcnew UIPropertyMetadata(IntPtr::Zero, gcnew PropertyChangedCallback(&HWNDOwnerChanged))); } D3D11Image::D3D11Image() { } D3D11Image::~D3D11Image() { if (this->Helper != nullptr) { this->Helper->~SurfaceQueueInteropHelper(); this->Helper = nullptr; } } Freezable^ D3D11Image::CreateInstanceCore() { return gcnew D3D11Image(); } void D3D11Image::HWNDOwnerChanged(DependencyObject^ sender, DependencyPropertyChangedEventArgs args) { D3D11Image^ image = dynamic_cast(sender); if (image != nullptr) { if (image->Helper != nullptr) { image->Helper->HWND = static_cast(args.NewValue); } } } void D3D11Image::RenderChanged(DependencyObject^ sender, DependencyPropertyChangedEventArgs args) { D3D11Image^ image = dynamic_cast(sender); if (image != nullptr) { if (image->Helper != nullptr) { image->Helper->RenderD2D = static_cast^>(args.NewValue); } } } void D3D11Image::EnsureHelper() { if (this->Helper == nullptr) { this->Helper = gcnew SurfaceQueueInteropHelper(); this->Helper->HWND = this->WindowOwner; this->Helper->D3DImage = this; this->Helper->RenderD2D = this->OnRender; } } void D3D11Image::RequestRender() { this->EnsureHelper(); // Don't bother with a call if there's no callback registered. if (nullptr != this->OnRender) { this->Helper->RequestRenderD2D(); } } void D3D11Image::SetPixelSize(int pixelWidth, int pixelHeight) { this->EnsureHelper(); this->Helper->SetPixelSize(static_cast(pixelWidth), static_cast(pixelHeight)); } } } } } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/D3D11Image.h ================================================ // SurfaceQueueInteropHelper.h #pragma once #include "SurfaceQueueInteropHelper.h" using namespace System; using namespace System::Windows; using namespace System::Windows::Interop; using namespace Microsoft::Windows::Media; namespace Microsoft { namespace Wpf { namespace Interop { namespace DirectX { /// A System.Windows.Media.ImageSource which displays a user provided DirectX 10 or 11 surface. public ref class D3D11Image : public D3DImage { private: static void RenderChanged(DependencyObject^ sender, DependencyPropertyChangedEventArgs args); static void HWNDOwnerChanged(DependencyObject^ sender, DependencyPropertyChangedEventArgs args); void EnsureHelper(); static D3D11Image(); internal: SurfaceQueueInteropHelper^ Helper; protected: Freezable^ CreateInstanceCore() override; public: D3D11Image(); ~D3D11Image(); static DependencyProperty^ OnRenderProperty; static DependencyProperty^ WindowOwnerProperty; /// The OnRender action delegate will fire and pass the surface to the application that the DirectX rendering component should /// render into. property Action^ OnRender { Action^ get() { return static_cast^>(GetValue(OnRenderProperty)); } void set(Action^ value) { SetValue(OnRenderProperty, value); } } /// The window handle (HWND) of the Window which hosts the D3D11Image (used during DirectX surface creation). property IntPtr WindowOwner { IntPtr get() { return static_cast(GetValue(WindowOwnerProperty)); } void set(IntPtr value) { SetValue(WindowOwnerProperty, value); } } /// The RequestRender method signals that the D3D11Image should get the DirectX rendering code to render a new frame to the provided surface. /// Typically the user of the D3D11Image calls this every time the CompositionTarget.Rendering event fires. void RequestRender(); /// The application hosting the D3D11Image should ensure that the PixelSize is the number of pixels that the D3D11Image is /// being displayed in. void SetPixelSize(int pixelWidth, int pixelHeight); }; } } } } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/Microsoft.Wpf.Interop.DirectX_dxsdk.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 Create Create Create Create {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2} Win32Proj Microsoft.Wpf.Interop.DirectX Microsoft.Wpf.Interop.DirectX v4.5 DynamicLibrary true Unicode true v120 DynamicLibrary true Unicode true v120 DynamicLibrary false true Unicode true v120 DynamicLibrary false true Unicode true v120 true $(LibraryPath);$(DXSDK_DIR)Lib\x86 $(IncludePath);$(DXSDK_DIR)Include false $(LibraryPath);$(DXSDK_DIR)Lib\x86 $(IncludePath);$(DXSDK_DIR)Include true $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 false $(IncludePath);$(DXSDK_DIR)Include $(LibraryPath);$(DXSDK_DIR)Lib\x64 NotUsing Level3 Disabled DIRECTX_SDK;WIN32;_DEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) MultiThreadedDLL true dxgi.lib;d3d9.lib;d3dx9d.lib;d3d10_1.lib;d3dx10d.lib;%(AdditionalDependencies) $(DXSDK_DIR)Lib\x86;..\Debug;%(AdditionalLibraryDirectories) NotUsing Level3 Disabled DIRECTX_SDK;_DEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) MultiThreadedDLL true dxgi.lib;d3d9.lib;d3dx9d.lib;d3d10_1.lib;d3dx10d.lib;%(AdditionalDependencies) $(DXSDK_DIR)Lib\x64;..\x64\Debug;%(AdditionalLibraryDirectories) Level3 NotUsing MaxSpeed true DIRECTX_SDK;WIN32;NDEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) MultiThreadedDLL %(AdditionalIncludeDirectories) Async true dxgi.lib;d3d9.lib;d3dx9d.lib;d3d10_1.lib;d3dx10d.lib;%(AdditionalDependencies) $(DXSDK_DIR)Lib\x86;..\Release;%(AdditionalLibraryDirectories) false Level3 NotUsing MaxSpeed true DIRECTX_SDK;NDEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) MultiThreadedDLL %(AdditionalIncludeDirectories) Async true dxgi.lib;d3d9.lib;d3dx9d.lib;d3d10_1.lib;d3dx10d.lib;%(AdditionalDependencies) $(DXSDK_DIR)Lib\x64;..\x64\Release;%(AdditionalLibraryDirectories) false ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/Microsoft.Wpf.Interop.DirectX_winsdk.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 Create Create Create Create {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2} Win32Proj Microsoft.Wpf.Interop.DirectX Microsoft.Wpf.Interop.DirectX v4.5 8.1 Microsoft.Wpf.Interop.DirectX_winsdk DynamicLibrary true Unicode true v140 DynamicLibrary true Unicode true v140 DynamicLibrary false true Unicode true v140 DynamicLibrary false true Unicode true v140 true $(LibraryPath) $(IncludePath) false $(LibraryPath) $(IncludePath) true $(IncludePath) $(LibraryPath) false $(IncludePath) $(LibraryPath) NotUsing Level3 Disabled WIN32;_DEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) MultiThreadedDLL true dxgi.lib;d3d9.lib;d3d10_1.lib;%(AdditionalDependencies) ..\Debug;%(AdditionalLibraryDirectories) NotUsing Level3 Disabled _DEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) MultiThreadedDLL true true dxgi.lib;d3d9.lib;d3d10_1.lib;%(AdditionalDependencies) ..\x64\Debug;%(AdditionalLibraryDirectories) Level3 NotUsing MaxSpeed true WIN32;NDEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) MultiThreadedDLL %(AdditionalIncludeDirectories) Async true dxgi.lib;d3d9.lib;d3d10_1.lib;%(AdditionalDependencies) ..\Release;%(AdditionalLibraryDirectories) false Level3 NotUsing MaxSpeed true NDEBUG;QUEUE_USE_CONFORMANT_NEW;%(PreprocessorDefinitions) MultiThreadedDLL %(AdditionalIncludeDirectories) Async true dxgi.lib;d3d9.lib;d3d10_1.lib;%(AdditionalDependencies) ..\x64\Release;%(AdditionalLibraryDirectories) false ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/Stdafx.cpp ================================================ // stdafx.cpp : source file that includes just the standard includes // SurfaceQueueInteropHelper.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/Stdafx.h ================================================ // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once // Windows Header Files: #include // C RunTime Header Files #include #include #include "SurfaceQueue.h" #if DIRECTX_SDK #include #else #include "d3d9.h" #endif #include //#include #define IFC(x) { hr = (x); if (FAILED(hr)) { goto Cleanup; }} #define ReleaseInterface(x) { if (NULL != x) { x->Release(); x = NULL; }} ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceDevice10.cpp ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "SurfaceQueueImpl.h" //----------------------------------------------------------------------------- // Implementation of D3D10 Device Wrapper. This is a simple wrapper around the // public D3D10 APIs that are necessary for the shared surface queue. See // the comments in SharedSurfaceQueue.h to descriptions of these functions. //----------------------------------------------------------------------------- CSurfaceQueueDeviceD3D10::CSurfaceQueueDeviceD3D10(ID3D10Device* pD3D10Device) : m_pDevice(pD3D10Device) { ASSERT(m_pDevice); if (NULL != m_pDevice) { m_pDevice->AddRef(); } } CSurfaceQueueDeviceD3D10::~CSurfaceQueueDeviceD3D10() { m_pDevice->Release(); } HRESULT CSurfaceQueueDeviceD3D10::CreateSharedSurface( UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppUnknown, HANDLE* pHandle) { ASSERT(m_pDevice); ASSERT(ppUnknown); ASSERT(pHandle); if (NULL == m_pDevice || NULL == ppUnknown || NULL == pHandle) { return E_FAIL; } HRESULT hr; ID3D10Texture2D** ppTexture = (ID3D10Texture2D**)ppUnknown; D3D10_TEXTURE2D_DESC Desc; Desc.Width = Width; Desc.Height = Height; Desc.MipLevels = 1; Desc.ArraySize = 1; Desc.Format = format; Desc.SampleDesc.Count = 1; Desc.SampleDesc.Quality = 0; Desc.Usage = D3D10_USAGE_DEFAULT; Desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; Desc.CPUAccessFlags = 0; Desc.MiscFlags = D3D10_RESOURCE_MISC_SHARED; hr = m_pDevice->CreateTexture2D(&Desc, NULL, ppTexture); if (SUCCEEDED(hr)) { if (FAILED( GetSharedHandle(*ppUnknown, pHandle))) { (*ppTexture)->Release(); (*ppTexture) = NULL; } } return hr; } HRESULT CSurfaceQueueDeviceD3D10::OpenSurface( HANDLE hSharedHandle, void** ppSurface, UINT, UINT, DXGI_FORMAT) { return m_pDevice->OpenSharedResource(hSharedHandle, __uuidof(ID3D10Texture2D), ppSurface); } HRESULT CSurfaceQueueDeviceD3D10::GetSharedHandle(IUnknown* pUnknown, HANDLE* pHandle) { ASSERT(pUnknown); ASSERT(pHandle); if (NULL == pUnknown || NULL == pHandle) { return E_FAIL; } HRESULT hr = S_OK; *pHandle = NULL; IDXGIResource* pSurface; if (FAILED(hr = pUnknown->QueryInterface(__uuidof(IDXGIResource), (void**)&pSurface))) { return hr; } hr = pSurface->GetSharedHandle(pHandle); pSurface->Release(); return hr; } HRESULT CSurfaceQueueDeviceD3D10::CreateCopyResource(DXGI_FORMAT format, UINT width, UINT height, IUnknown** ppRes) { ASSERT(ppRes); ASSERT(m_pDevice); if (NULL == ppRes || NULL == m_pDevice) { return E_FAIL; } D3D10_TEXTURE2D_DESC Desc; Desc.Width = width; Desc.Height = height; Desc.MipLevels = 1; Desc.ArraySize = 1; Desc.Format = format; Desc.SampleDesc.Count = 1; Desc.SampleDesc.Quality = 0; Desc.Usage = D3D10_USAGE_STAGING; Desc.BindFlags = 0; Desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; Desc.MiscFlags = 0; return m_pDevice->CreateTexture2D(&Desc, NULL, reinterpret_cast(ppRes)); } HRESULT CSurfaceQueueDeviceD3D10::CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height) { HRESULT hr; D3D10_BOX UnitBox = {0, 0, 0, width, height, 1}; ID3D10Resource* pSrcRes = NULL; ID3D10Resource* pDstRes = NULL; if (FAILED(hr = pDst->QueryInterface(__uuidof(ID3D10Resource), (void**)&pDstRes))) { goto end; } if (FAILED(hr = pSrc->QueryInterface(__uuidof(ID3D10Resource), (void**)&pSrcRes))) { goto end; } m_pDevice->CopySubresourceRegion( pDstRes, 0, 0, 0, 0, //(x, y, z) pSrcRes, 0, &UnitBox); end: if (pSrcRes) { pSrcRes->Release(); } if (pDstRes) { pDstRes->Release(); } return hr; } HRESULT CSurfaceQueueDeviceD3D10::LockSurface(IUnknown* pSurface, DWORD flags) { ASSERT(pSurface); if (NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; ID3D10Texture2D* pTex2D = NULL; DWORD d3d10flags = 0; D3D10_MAPPED_TEXTURE2D region; if (flags & SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { flags |= D3D10_MAP_FLAG_DO_NOT_WAIT; } if (FAILED(hr = pSurface->QueryInterface(__uuidof(ID3D10Texture2D), (void**)&pTex2D))) { goto end; } hr = pTex2D->Map(0, D3D10_MAP_READ, d3d10flags, ®ion); end: if (pTex2D) { pTex2D->Release(); } return hr; } HRESULT CSurfaceQueueDeviceD3D10::UnlockSurface(IUnknown* pSurface) { ASSERT(pSurface); if (NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; ID3D10Texture2D* pTex2D = NULL; if (FAILED(hr = pSurface->QueryInterface(__uuidof(ID3D10Texture2D), (void**)&pTex2D))) { return hr; } pTex2D->Unmap(0); pTex2D->Release(); return hr; } BOOL CSurfaceQueueDeviceD3D10::ValidateREFIID(REFIID id) { return (id == __uuidof(ID3D10Texture2D)) || (id == __uuidof(IDXGISurface)); } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceDevice11.cpp ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "SurfaceQueueImpl.h" //----------------------------------------------------------------------------- // Implementation of D3D11 Device Wrapper. This is a simple wrapper around the // public D3D11 APIs that are necessary for the shared surface queue. See // the comments in SharedSurfaceQueue.h to descriptions of these functions. //----------------------------------------------------------------------------- CSurfaceQueueDeviceD3D11::CSurfaceQueueDeviceD3D11(ID3D11Device* pD3D11Device) : m_pDevice(pD3D11Device) { ASSERT(m_pDevice); if (NULL != m_pDevice) { m_pDevice->AddRef(); } } CSurfaceQueueDeviceD3D11::~CSurfaceQueueDeviceD3D11() { m_pDevice->Release(); } HRESULT CSurfaceQueueDeviceD3D11::CreateSharedSurface( UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppUnknown, HANDLE* pHandle) { ASSERT(m_pDevice); ASSERT(ppUnknown); ASSERT(pHandle); if(NULL == m_pDevice || NULL == ppUnknown || NULL == pHandle) { return E_FAIL; } HRESULT hr; ID3D11Texture2D** ppTexture = (ID3D11Texture2D**)ppUnknown; D3D11_TEXTURE2D_DESC Desc; Desc.Width = Width; Desc.Height = Height; Desc.MipLevels = 1; Desc.ArraySize = 1; Desc.Format = format; Desc.SampleDesc.Count = 1; Desc.SampleDesc.Quality = 0; Desc.Usage = D3D11_USAGE_DEFAULT; Desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; Desc.CPUAccessFlags = 0; Desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; hr = m_pDevice->CreateTexture2D(&Desc, NULL, ppTexture); if (SUCCEEDED(hr)) { if (FAILED( GetSharedHandle(*ppUnknown, pHandle))) { (*ppTexture)->Release(); (*ppTexture) = NULL; } } return hr; } HRESULT CSurfaceQueueDeviceD3D11::OpenSurface( HANDLE hSharedHandle, void** ppSurface, UINT, UINT, DXGI_FORMAT) { return m_pDevice->OpenSharedResource(hSharedHandle, __uuidof(ID3D11Texture2D), ppSurface); } HRESULT CSurfaceQueueDeviceD3D11::GetSharedHandle(IUnknown* pUnknown, HANDLE* pHandle) { ASSERT(pUnknown); ASSERT(pHandle); if(NULL == pUnknown || NULL == pHandle) { return E_FAIL; } HRESULT hr = S_OK; *pHandle = NULL; IDXGIResource* pSurface; if (FAILED(hr = pUnknown->QueryInterface(__uuidof(IDXGIResource), (void**)&pSurface))) { return hr; } hr = pSurface->GetSharedHandle(pHandle); pSurface->Release(); return hr; } HRESULT CSurfaceQueueDeviceD3D11::CreateCopyResource(DXGI_FORMAT format, UINT width, UINT height, IUnknown** ppRes) { ASSERT(ppRes); ASSERT(m_pDevice); if(NULL == ppRes || NULL == m_pDevice) { return E_FAIL; } D3D11_TEXTURE2D_DESC Desc; Desc.Width = width; Desc.Height = height; Desc.MipLevels = 1; Desc.ArraySize = 1; Desc.Format = format; Desc.SampleDesc.Count = 1; Desc.SampleDesc.Quality = 0; Desc.Usage = D3D11_USAGE_STAGING; Desc.BindFlags = 0; Desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; Desc.MiscFlags = 0; return m_pDevice->CreateTexture2D(&Desc, NULL, reinterpret_cast(ppRes)); } HRESULT CSurfaceQueueDeviceD3D11::CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height) { HRESULT hr; D3D11_BOX UnitBox = {0, 0, 0, width, height, 1}; ID3D11DeviceContext* pContext = NULL; ID3D11Resource* pSrcRes = NULL; ID3D11Resource* pDstRes = NULL; m_pDevice->GetImmediateContext(&pContext); ASSERT(pContext); if (FAILED(hr = pDst->QueryInterface(__uuidof(ID3D11Resource), (void**)&pDstRes))) { goto end; } if (FAILED(hr = pSrc->QueryInterface(__uuidof(ID3D11Resource), (void**)&pSrcRes))) { goto end; } pContext->CopySubresourceRegion( pDstRes, 0, 0, 0, 0, //(x, y, z) pSrcRes, 0, &UnitBox); end: if (pSrcRes) { pSrcRes->Release(); } if (pDstRes) { pDstRes->Release(); } if (pContext) { pContext->Release(); } return hr; } HRESULT CSurfaceQueueDeviceD3D11::LockSurface(IUnknown* pSurface, DWORD flags) { ASSERT(pSurface); if(NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; D3D11_MAPPED_SUBRESOURCE region; ID3D11Resource* pResource = NULL; ID3D11DeviceContext* pContext = NULL; DWORD d3d11flags = 0; m_pDevice->GetImmediateContext(&pContext); ASSERT(pContext); if (flags & SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { d3d11flags |= D3D11_MAP_FLAG_DO_NOT_WAIT; } if (FAILED(hr = pSurface->QueryInterface(__uuidof(ID3D11Resource), (void**)&pResource))) { goto end; } hr = pContext->Map(pResource, 0, D3D11_MAP_READ, d3d11flags, ®ion); end: if (pResource) { pResource->Release(); } if (pContext) { pContext->Release(); } return hr; } HRESULT CSurfaceQueueDeviceD3D11::UnlockSurface(IUnknown* pSurface) { ASSERT(pSurface); if(NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; ID3D11DeviceContext* pContext = NULL; ID3D11Resource* pResource = NULL; m_pDevice->GetImmediateContext(&pContext); ASSERT(pContext); if (FAILED(hr = pSurface->QueryInterface(__uuidof(ID3D11Resource), (void**)&pResource))) { goto end; } pContext->Unmap(pResource, 0); end: if (pResource) { pResource->Release(); } if (pContext) { pContext->Release(); } return hr; } BOOL CSurfaceQueueDeviceD3D11::ValidateREFIID(REFIID id) { return (id == __uuidof(ID3D11Texture2D)) || (id == __uuidof(IDXGISurface)); } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceDevice9.cpp ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "SurfaceQueueImpl.h" //----------------------------------------------------------------------------- // Implementation of D3D9 Device Wrapper. This is a simple wrapper around the // public D3D9Ex APIs that are necessary for the shared surface queue. See // the comments in SharedSurfaceQueue.h to descriptions of these functions. //----------------------------------------------------------------------------- // // D3D9Ex does not have an API to get shared handles. We replicate that functionality // using setprivatedata. // static GUID SharedHandleGuid = {0x91facf2d, 0xe464, 0x4495, 0x84, 0xa6, 0x37, 0xbe, 0xd3, 0x56, 0x8d, 0xa3}; // // This function will convert from DXGI formats (d3d10/d3d11) to D3D9 formats. // Most formtas are not cross api shareable and for those the function will // return D3DFMT_UNKNOWN. // D3DFORMAT DXGIToCrossAPID3D9Format(DXGI_FORMAT Format) { switch (Format) { case DXGI_FORMAT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8; case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return D3DFMT_A8R8G8B8; case DXGI_FORMAT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8; case DXGI_FORMAT_R8G8B8A8_UNORM: return D3DFMT_A8B8G8R8; case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return D3DFMT_A8B8G8R8; case DXGI_FORMAT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10; case DXGI_FORMAT_R16G16B16A16_FLOAT: return D3DFMT_A16B16G16R16F; default: return D3DFMT_UNKNOWN; }; } CSurfaceQueueDeviceD3D9::CSurfaceQueueDeviceD3D9(IDirect3DDevice9Ex* pD3D9Device) : m_pDevice(pD3D9Device) { ASSERT(m_pDevice); if(NULL != m_pDevice) { m_pDevice->AddRef(); } } CSurfaceQueueDeviceD3D9::~CSurfaceQueueDeviceD3D9() { m_pDevice->Release(); } HRESULT CSurfaceQueueDeviceD3D9::CreateSharedSurface( UINT Width, UINT Height, DXGI_FORMAT Format, IUnknown** ppTexture, HANDLE* pHandle) { ASSERT(m_pDevice); if(NULL == m_pDevice) { return E_FAIL; } D3DFORMAT D3D9Format; if ((D3D9Format = DXGIToCrossAPID3D9Format(Format)) == D3DFMT_UNKNOWN) { return E_INVALIDARG; } HRESULT hr; *pHandle = NULL; hr = m_pDevice->CreateTexture(Width, Height, 1, D3DUSAGE_RENDERTARGET, D3D9Format, D3DPOOL_DEFAULT, (IDirect3DTexture9**)ppTexture, pHandle); return hr; } HRESULT CSurfaceQueueDeviceD3D9::OpenSurface( HANDLE hSharedHandle, void** ppUnknown, UINT Width, UINT Height, DXGI_FORMAT Format) { D3DFORMAT D3D9Format; // If the format is not cross api shareable the utility function will return // D3DFMT_UNKNOWN if ((D3D9Format = DXGIToCrossAPID3D9Format(Format)) == D3DFMT_UNKNOWN) { return E_INVALIDARG; } HRESULT hr = S_OK; IDirect3DTexture9** ppTexture = (IDirect3DTexture9**)ppUnknown; hr = m_pDevice->CreateTexture(Width, Height, 1, D3DUSAGE_RENDERTARGET, D3D9Format, D3DPOOL_DEFAULT, ppTexture, &hSharedHandle); if (SUCCEEDED(hr)) { // Store the shared handle hr = (*ppTexture)->SetPrivateData(SharedHandleGuid, &hSharedHandle, sizeof(HANDLE), 0); if (FAILED(hr)) { (*ppTexture)->Release(); *ppTexture = NULL; } } return hr; } HRESULT CSurfaceQueueDeviceD3D9::GetSharedHandle(IUnknown* pUnknown, HANDLE* pHandle) { ASSERT(pUnknown); ASSERT(pHandle); if(NULL == pUnknown || NULL == pHandle) { return E_FAIL; } HRESULT hr = S_OK; *pHandle = NULL; IDirect3DTexture9* pTexture; if (FAILED(hr = pUnknown->QueryInterface(__uuidof(IDirect3DTexture9), (void**)&pTexture))) { return hr; } DWORD size = sizeof(HANDLE); hr = pTexture->GetPrivateData(SharedHandleGuid, pHandle, &size); pTexture->Release(); return hr; } HRESULT CSurfaceQueueDeviceD3D9::CreateCopyResource(DXGI_FORMAT Format, UINT width, UINT height, IUnknown** ppRes) { D3DFORMAT D3D9Format; if ((D3D9Format = DXGIToCrossAPID3D9Format(Format)) == D3DFMT_UNKNOWN) { return E_INVALIDARG; } return m_pDevice->CreateRenderTarget( width, height, D3D9Format, D3DMULTISAMPLE_NONE, 0, TRUE, (IDirect3DSurface9**)ppRes, NULL ); } HRESULT CSurfaceQueueDeviceD3D9::CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height) { ASSERT(pDst); ASSERT(pSrc); ASSERT(m_pDevice); if(NULL == pDst || NULL == pSrc || NULL == m_pDevice) { return E_FAIL; } HRESULT hr = S_OK; IDirect3DSurface9* pSrcSurf = NULL; IDirect3DSurface9* pDstSurf = NULL; IDirect3DTexture9* pSrcTex = NULL; RECT rect = {(long)0, (long)0, (long)width, (long)height }; // The source should be a IDirect3DTexture9. We need to QI for it and then get the // top most surface from it. if (FAILED(hr = pSrc->QueryInterface(__uuidof(IDirect3DTexture9), (void**)&pSrcTex))) { goto end; } if (FAILED(hr = pSrcTex->GetSurfaceLevel(0, &pSrcSurf))) { goto end; } // The dst is a IDirect3DSurface9 so we can simply QI for it. if (FAILED(hr = pDst->QueryInterface(__uuidof(IDirect3DSurface9), (void**)&pDstSurf))) { goto end; } hr = m_pDevice->StretchRect(pSrcSurf, &rect, pDstSurf, &rect, D3DTEXF_NONE); end: if (pSrcTex) { pSrcTex->Release(); } if (pSrcSurf) { pSrcSurf->Release(); } if (pDstSurf) { pDstSurf->Release(); } return hr; } HRESULT CSurfaceQueueDeviceD3D9::LockSurface(IUnknown* pSurface, DWORD flags) { ASSERT(pSurface); if(NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; IDirect3DSurface9* pSurf = NULL; DWORD d3d9flags = D3DLOCK_READONLY; D3DLOCKED_RECT region; if (flags & SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { d3d9flags |= D3DLOCK_DONOTWAIT; } if (FAILED(hr = pSurface->QueryInterface(__uuidof(IDirect3DSurface9), (void**)&pSurf))) { goto end; } hr = pSurf->LockRect(®ion, NULL, d3d9flags); end: if (pSurf) { pSurf->Release(); } if (hr == D3DERR_WASSTILLDRAWING) { hr = DXGI_ERROR_WAS_STILL_DRAWING; } return hr; } HRESULT CSurfaceQueueDeviceD3D9::UnlockSurface(IUnknown* pSurface) { ASSERT(pSurface); if(NULL == pSurface) { return E_FAIL; } HRESULT hr = S_OK; IDirect3DSurface9* pSurf = NULL; if (FAILED(hr = pSurface->QueryInterface(__uuidof(IDirect3DSurface9), (void**)&pSurf))) { goto end; } hr = pSurf->UnlockRect(); end: if (pSurf) { pSurf->Release(); } return hr; } BOOL CSurfaceQueueDeviceD3D9::ValidateREFIID(REFIID id) { return id == __uuidof(IDirect3DTexture9); } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueue.cpp ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include #include "SurfaceQueue.inl" // // Notes about the synchronization: It's important for this library // to be reasonably parallel; it should be possible to have simultaneously // enqueues/dequeues. It is undesirable for a thread to grab the queue // lock while it calls into a blocking or very time consuming DirectX API. // // The single threaded flag will disable the synchronization constructs. // // There are 4 synchronization primitives used in this library. // 1) Critical Section in CSurfaceProducer/CSurfaceConsumer that protects // simultaneous access to their apis (Enqueue&Flush/Dequeue). The public // functions from those objects are not designed to be multithreaded. It // is not designed to support, for example, simultaneous Enqueues to the same // queue. This lock guarantees that the Queue can not have simultaneous Enqueues // and Flushes. There are a few CSurfaceQueue member variables that are shared // ONLY between Enqueue and Flush and do not need to be protected in CSurfaceQueue. // 2) A Semaphore to control waiting when the Queue is empty. The semaphore is // released on Enqueue/Flush and is waited on in Dequeue. // 3) A SlimReaderWriter lock protecting the CSurfaceQueue object. All of the // high frequency calls grab shared locks (Enqueue/Flush/Dequeue) to allow // parallel access to the queue. The low frequency state changes // (i.e. OpenProducer) will grab an exclusive lock. // 4) A critical section protecting the underlying circular queue. Both Enqueue // and dequeue will contend for this lock but the duration the lock is held // is kept to a minimum. // //----------------------------------------------------------------------------- // Helper Functions //----------------------------------------------------------------------------- HRESULT CreateDeviceWrapper(IUnknown* pUnknown, ISurfaceQueueDevice** ppDevice) { IDirect3DDevice9Ex* pD3D9Device; ID3D10Device* pD3D10Device; ID3D11Device* pD3D11Device; HRESULT hr = S_OK; *ppDevice = NULL; if (SUCCEEDED(pUnknown->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&pD3D9Device))) { pD3D9Device->Release(); *ppDevice = new QUEUE_NOTHROW_SPECIFIER CSurfaceQueueDeviceD3D9(pD3D9Device); } else if (SUCCEEDED(pUnknown->QueryInterface(__uuidof(ID3D10Device), (void**)&pD3D10Device))) { pD3D10Device->Release(); *ppDevice = new QUEUE_NOTHROW_SPECIFIER CSurfaceQueueDeviceD3D10(pD3D10Device); } else if (SUCCEEDED(pUnknown->QueryInterface(__uuidof(ID3D11Device), (void**)&pD3D11Device))) { pD3D11Device->Release(); *ppDevice = new QUEUE_NOTHROW_SPECIFIER CSurfaceQueueDeviceD3D11(pD3D11Device); } else { hr = E_INVALIDARG; } if (SUCCEEDED(hr) && *ppDevice == NULL) { hr = E_OUTOFMEMORY; } return hr; }; //----------------------------------------------------------------------------- // SharedSurfaceObject Implementation //----------------------------------------------------------------------------- SharedSurfaceObject::SharedSurfaceObject(UINT Width, UINT Height, DXGI_FORMAT Format) { hSharedHandle = NULL; state = SHARED_SURFACE_STATE_UNINITIALIZED; queue = NULL; width = Width; height = Height; format = Format; pSurface = NULL; } SharedSurfaceObject::~SharedSurfaceObject() { // Release the reference to the created surface if (pSurface) { pSurface->Release(); } } //----------------------------------------------------------------------------- // CreateSurfaceQueue //----------------------------------------------------------------------------- HRESULT WINAPI CreateSurfaceQueue( SURFACE_QUEUE_DESC* pDesc, IUnknown* pDevice, ISurfaceQueue** ppQueue) { HRESULT hr = E_FAIL; if (ppQueue == NULL) { return E_INVALIDARG; } *ppQueue = NULL; if (pDesc == NULL) { return E_INVALIDARG; } if (pDevice == NULL) { return E_INVALIDARG; } if (pDesc->NumSurfaces == 0) { return E_INVALIDARG; } if (pDesc->Width == 0 || pDesc->Height == 0) { return E_INVALIDARG; } if (pDesc->Flags != 0 && pDesc->Flags != SURFACE_QUEUE_FLAG_SINGLE_THREADED) { return E_INVALIDARG; } CSurfaceQueue* pSurfaceQueue = new QUEUE_NOTHROW_SPECIFIER CSurfaceQueue(); if (!pSurfaceQueue) { hr = E_OUTOFMEMORY; goto end; } hr = pSurfaceQueue->Initialize(pDesc, pDevice, pSurfaceQueue); if (FAILED(hr)) { goto end; } hr = pSurfaceQueue->QueryInterface(__uuidof(ISurfaceQueue), (void**)ppQueue); end: if (FAILED(hr)) { if (pSurfaceQueue) { delete pSurfaceQueue; } *ppQueue = NULL; } return hr; } //----------------------------------------------------------------------------- // CSurfaceConsumer implementation //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CSurfaceConsumer:: CSurfaceConsumer(BOOL IsMultithreaded) : m_RefCount(0), m_IsMultithreaded(IsMultithreaded), m_pQueue(NULL), m_pDevice(NULL) { if (m_IsMultithreaded) { InitializeCriticalSection(&m_lock); } } //----------------------------------------------------------------------------- CSurfaceConsumer::~CSurfaceConsumer() { if (m_pQueue) { m_pQueue->RemoveConsumer(); m_pQueue->Release(); } if (m_pDevice) { delete m_pDevice; } if (m_IsMultithreaded) { DeleteCriticalSection(&m_lock); } } //----------------------------------------------------------------------------- HRESULT CSurfaceConsumer::Initialize(IUnknown* pDevice) { ASSERT(pDevice); ASSERT(m_pDevice == NULL); HRESULT hr; hr = CreateDeviceWrapper(pDevice, &m_pDevice); if (FAILED(hr)) { if (m_pDevice) { delete m_pDevice; m_pDevice = NULL; } } return hr; } //----------------------------------------------------------------------------- void CSurfaceConsumer::SetQueue(CSurfaceQueue* queue) { ASSERT(!m_pQueue && queue); if (NULL != m_pQueue || NULL == queue) { return; } m_pQueue = queue; m_pQueue->AddRef(); } //----------------------------------------------------------------------------- HRESULT CSurfaceConsumer::Dequeue( REFIID id, IUnknown** ppSurface, void* pBuffer, UINT* BufferSize, DWORD dwTimeout) { ASSERT(m_pQueue); if (NULL == m_pQueue) { return E_FAIL; } HRESULT hr = S_OK; if (m_IsMultithreaded) { EnterCriticalSection(&m_lock); } // Validate that REFIID is correct for a surface from this device if (!m_pDevice->ValidateREFIID(id)) { hr = E_INVALIDARG; goto end; } if (ppSurface == NULL) { hr = E_INVALIDARG; goto end; } *ppSurface = NULL; // Forward to queue hr = m_pQueue->Dequeue(ppSurface, pBuffer, BufferSize, dwTimeout); end: if (m_IsMultithreaded) { LeaveCriticalSection(&m_lock); } return hr; } //----------------------------------------------------------------------------- // CSurfaceProducer implementation //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CSurfaceProducer:: CSurfaceProducer(BOOL IsMultithreaded) : m_RefCount(0), m_IsMultithreaded(IsMultithreaded), m_pQueue(NULL), m_pDevice(NULL), m_nStagingResources(0), m_pStagingResources(NULL), m_uiStagingResourceHeight(0), m_uiStagingResourceWidth(0), m_iCurrentResource(0) { if (m_IsMultithreaded) { InitializeCriticalSection(&m_lock); } } //----------------------------------------------------------------------------- CSurfaceProducer::~CSurfaceProducer() { if (m_pQueue) { m_pQueue->RemoveProducer(); m_pQueue->Release(); } if (m_pStagingResources) { for (UINT i = 0; i < m_nStagingResources; i++) { if (m_pStagingResources[i]) { m_pStagingResources[i]->Release(); } } delete[] m_pStagingResources; } if (m_pDevice) { delete m_pDevice; } if (m_IsMultithreaded) { DeleteCriticalSection(&m_lock); } } //----------------------------------------------------------------------------- void CSurfaceProducer::SetQueue(CSurfaceQueue* queue) { ASSERT(!m_pQueue && queue); if (NULL != m_pQueue || NULL == queue) { return; } m_pQueue = queue; m_pQueue->AddRef(); } //----------------------------------------------------------------------------- HRESULT CSurfaceProducer::Initialize(IUnknown* pDevice, UINT uNumSurfaces, SURFACE_QUEUE_DESC* queueDesc) { ASSERT(pDevice); ASSERT(!m_pStagingResources && m_nStagingResources == 0) HRESULT hr = S_OK; hr = CreateDeviceWrapper(pDevice, &m_pDevice); if (FAILED(hr)) { goto end; } m_pStagingResources = new QUEUE_NOTHROW_SPECIFIER IUnknown*[uNumSurfaces]; if (!m_pStagingResources) { hr = E_OUTOFMEMORY; goto end; } ZeroMemory(m_pStagingResources, sizeof(IUnknown*) * uNumSurfaces); m_nStagingResources = uNumSurfaces; // Determine the size of the staging resource in case the queue surface is less than SHARED_SURFACE_COPY_SIZE m_uiStagingResourceWidth = min(queueDesc->Width, SHARED_SURFACE_COPY_SIZE); m_uiStagingResourceHeight = min(queueDesc->Height, SHARED_SURFACE_COPY_SIZE); // Create the staging resources for (UINT i = 0; i < m_nStagingResources; i++) { if (FAILED(hr = m_pDevice->CreateCopyResource(queueDesc->Format, m_uiStagingResourceWidth, m_uiStagingResourceHeight, &(m_pStagingResources[i])))) { goto end; } } end: if (FAILED(hr)) { if (m_pStagingResources) { for (UINT i = 0; i < m_nStagingResources; i++) { if (m_pStagingResources[i]) { m_pStagingResources[i]->Release(); } } delete[] m_pStagingResources; m_pStagingResources = NULL; m_nStagingResources = 0; } if (m_pDevice) { delete m_pDevice; m_pDevice = NULL; } } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceProducer::Enqueue( IUnknown* pSurface, void* pBuffer, UINT BufferSize, DWORD Flags ) { // // This function essentially does simple error checking and then // forwards the call to the queue object. The SurfaceProducer // maintains a circular buffer of staging resources to use and will // pass the next availible one to the queue. // ASSERT(m_pQueue); if (NULL == m_pQueue) { return E_FAIL; } if (m_IsMultithreaded) { EnterCriticalSection(&m_lock); } HRESULT hr; if (m_pDevice == NULL) { hr = E_INVALIDARG; goto end; } if (!pSurface) { hr = E_INVALIDARG; goto end; } if (Flags && Flags != SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { hr = E_INVALIDARG; goto end; } // Forward call to queue hr = m_pQueue->Enqueue( pSurface, pBuffer, BufferSize, Flags, m_pStagingResources[m_iCurrentResource], m_uiStagingResourceWidth, m_uiStagingResourceHeight ); if (hr == DXGI_ERROR_WAS_STILL_DRAWING) { // // Increment the staging resource only if the current one is still // being used. This only happens if the function returns with // DXGI_ERROR_WAS_STILL_DRAWING indicating that a future flush // will still need the resource // // We do not need to worry about wrapping around and reusing staging // surfaces that are currently in use. The design of the queue makes // it invalid to enqueue when the queue is already full. If the user // does that, the queue will fail the call with E_INVALIDARG. m_iCurrentResource = (m_iCurrentResource + 1) % m_nStagingResources; } end: if (m_IsMultithreaded) { LeaveCriticalSection(&m_lock); } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceProducer::Flush( DWORD Flags, UINT* NumSurfaces ) { ASSERT(m_pQueue); if (NULL == m_pQueue) { return E_FAIL; } if (m_IsMultithreaded) { EnterCriticalSection(&m_lock); } HRESULT hr; if (m_pDevice == NULL) { hr = E_INVALIDARG; goto end; } if (Flags && Flags != SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { hr = E_INVALIDARG; goto end; } // Forward call to queue hr = m_pQueue->Flush(Flags, NumSurfaces); end: if (m_IsMultithreaded) { LeaveCriticalSection(&m_lock); } return hr; } //----------------------------------------------------------------------------- // CSurfaceQueue implementation //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CSurfaceQueue:: CSurfaceQueue() : m_RefCount(0), m_IsMultithreaded(TRUE), m_hSemaphore(NULL), m_pRootQueue(NULL), m_NumQueuesInNetwork(0), m_pConsumer(NULL), m_pProducer(NULL), m_pCreator(NULL), m_SurfaceQueue(NULL), m_QueueHead(0), m_QueueSize(0), m_ConsumerSurfaces(NULL), m_CreatedSurfaces(NULL), m_iEnqueuedHead(0), m_nEnqueuedSurfaces(0) { } //----------------------------------------------------------------------------- CSurfaceQueue::~CSurfaceQueue() { Destroy(); } //----------------------------------------------------------------------------- void CSurfaceQueue::Destroy() { RemoveQueueFromNetwork(); // The ref counting should guarantee that the root queue object // is the last to be deleted if (m_pRootQueue != this) { m_pRootQueue->Release(); } else { ASSERT(m_NumQueuesInNetwork == 0); } // The root queue will destroy the creating device if (m_pCreator) { delete m_pCreator; m_pCreator = NULL; } // Release all opened surfaces if (m_ConsumerSurfaces) { for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_ConsumerSurfaces[i].pSurface) { m_ConsumerSurfaces[i].pSurface->Release(); } } delete[] m_ConsumerSurfaces; m_ConsumerSurfaces = NULL; } // Clean up the allocated meta data buffers if (m_SurfaceQueue) { for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_SurfaceQueue[i].pMetaData) { delete[] m_SurfaceQueue[i].pMetaData; } } delete[] m_SurfaceQueue; m_SurfaceQueue = NULL; } // The root queue object created the surfaces. All other queue // objects only have a reference. if (m_CreatedSurfaces) { for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_pRootQueue == this && m_CreatedSurfaces[i]) { delete m_CreatedSurfaces[i]; } m_CreatedSurfaces[i] = NULL; } delete[] m_CreatedSurfaces; m_CreatedSurfaces = NULL; } m_pConsumer = NULL; m_pProducer = NULL; if (m_IsMultithreaded) { if (m_hSemaphore) { CloseHandle(m_hSemaphore); m_hSemaphore = NULL; } DeleteCriticalSection(&m_QueueLock); } else { m_nFlushedSurfaces = 0; } } //----------------------------------------------------------------------------- ISurfaceQueueDevice* CSurfaceQueue::GetCreatorDevice() { return m_pRootQueue->m_pCreator; } //----------------------------------------------------------------------------- UINT CSurfaceQueue::GetNumQueuesInNetwork() { return m_pRootQueue->m_NumQueuesInNetwork; } //----------------------------------------------------------------------------- UINT CSurfaceQueue::AddQueueToNetwork() { if (m_pRootQueue == this) { return InterlockedIncrement(&m_NumQueuesInNetwork); } else { return m_pRootQueue->AddQueueToNetwork(); } } //----------------------------------------------------------------------------- UINT CSurfaceQueue::RemoveQueueFromNetwork() { ASSERT(GetNumQueuesInNetwork() > 0); if (m_pRootQueue == this) { return InterlockedDecrement(&m_NumQueuesInNetwork); } else { return m_pRootQueue->RemoveQueueFromNetwork(); } } //----------------------------------------------------------------------------- SharedSurfaceObject* CSurfaceQueue::GetSurfaceObjectFromHandle(HANDLE handle) { // // This does a linear search through the created surfaces for the specific // handle. When the user enqueues, we get the shared handle from surface // and then use the handle to get to the SharedSurfaceObject. This essentially // converts from a "generic d3d surface" to a "surface queue surface". // // This search is linear with the number of surfaces created. We expect that // number to be small. // ASSERT(handle); ASSERT(m_CreatedSurfaces); if (NULL == handle || NULL == m_CreatedSurfaces) { return NULL; } for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_CreatedSurfaces[i]->hSharedHandle == handle) { return m_CreatedSurfaces[i]; } } // The user tried to enqueue an shared surface that was not part of the queue. return NULL; } //----------------------------------------------------------------------------- IUnknown* CSurfaceQueue::GetOpenedSurface(const SharedSurfaceObject* pObject) const { // // On OpenConsumer, all of the shared surfaces will be opened by the consuming // device and cached. On dequeue, we simply look in the cache and return the // appropriate surface, getting a significant perf bonus over opening/closing // the surface on every dequeue/enqueue. // // This method is also linear with respect to the number of surfaces and a more // scalable data structure can be used if the number of surfaces is used. // ASSERT(pObject); ASSERT(m_ConsumerSurfaces); if (NULL == pObject || NULL == m_ConsumerSurfaces) { return NULL; } for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_ConsumerSurfaces[i].pObject == pObject) { return m_ConsumerSurfaces[i].pSurface; } } return NULL; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::AllocateMetaDataBuffers() { // This function allocates the meta data buffers during creation time. if (m_Desc.MetaDataSize != 0) { for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { m_SurfaceQueue[i].pMetaData = new QUEUE_NOTHROW_SPECIFIER BYTE[m_Desc.MetaDataSize]; if (m_SurfaceQueue[i].pMetaData == NULL) { return E_OUTOFMEMORY; } } } return S_OK; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::CreateSurfaces() { // // This function is only called by the root queue to create the surfaces. // The queue has the property that the root queue starts off full (all the // surfaces on it are ready for dequeue. This function will use the creating // device to create the shared surfaces and initialize them for dequeue. // HRESULT hr = S_OK; ASSERT(m_pRootQueue == this); for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { SharedSurfaceObject* pSurfaceObject = new QUEUE_NOTHROW_SPECIFIER SharedSurfaceObject(m_Desc.Width, m_Desc.Height, m_Desc.Format); if (!pSurfaceObject) { return E_OUTOFMEMORY; } m_CreatedSurfaces[i] = pSurfaceObject; if (FAILED(hr = m_pCreator->CreateSharedSurface( m_Desc.Width, m_Desc.Height, m_Desc.Format, &(pSurfaceObject->pSurface), &(pSurfaceObject->hSharedHandle) ))) { return hr; } // Important to note that created surfaces start in the flushed state. This // lets the system start in a state that makes it ready to go. m_SurfaceQueue[i].surface = m_CreatedSurfaces[i]; m_SurfaceQueue[i].surface->state = SHARED_SURFACE_STATE_FLUSHED; m_SurfaceQueue[i].surface->queue = this; } return S_OK; } //----------------------------------------------------------------------------- void CSurfaceQueue::CopySurfaceReferences(CSurfaceQueue* pRootQueue) { // This is called by cloned devices. They simply take a reference // to the shared created surfaces. ASSERT(m_pRootQueue != this); for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { m_CreatedSurfaces[i] = pRootQueue->m_CreatedSurfaces[i]; } } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::Initialize(SURFACE_QUEUE_DESC* pDesc, IUnknown* pDevice, CSurfaceQueue* pRootQueue) { ASSERT(pDesc); ASSERT(pRootQueue); if (NULL == pDesc || NULL == pRootQueue) { return E_FAIL; } HRESULT hr = S_OK; m_Desc = *pDesc; m_pRootQueue = pRootQueue; m_IsMultithreaded = !(m_Desc.Flags & SURFACE_QUEUE_FLAG_SINGLE_THREADED); AddQueueToNetwork(); if (m_IsMultithreaded) { InitializeCriticalSection(&m_QueueLock); } // Allocate Queue ASSERT(!m_SurfaceQueue); m_SurfaceQueue = new QUEUE_NOTHROW_SPECIFIER SharedSurfaceQueueEntry[pDesc->NumSurfaces]; if (!m_SurfaceQueue) { hr = E_OUTOFMEMORY; goto cleanup; } ZeroMemory(m_SurfaceQueue, sizeof(SharedSurfaceQueueEntry) * pDesc->NumSurfaces); // Allocate array to keep track of opened surfaces ASSERT(!m_ConsumerSurfaces); m_ConsumerSurfaces = new QUEUE_NOTHROW_SPECIFIER SharedSurfaceOpenedMapping[pDesc->NumSurfaces]; if (!m_ConsumerSurfaces) { hr = E_OUTOFMEMORY; goto cleanup; } ZeroMemory(m_ConsumerSurfaces, sizeof(SharedSurfaceOpenedMapping) * pDesc->NumSurfaces); // Allocate created surface tracking list ASSERT(!m_CreatedSurfaces); m_CreatedSurfaces = new QUEUE_NOTHROW_SPECIFIER SharedSurfaceObject*[pDesc->NumSurfaces]; if (!m_CreatedSurfaces) { hr = E_OUTOFMEMORY; goto cleanup; } ZeroMemory(m_CreatedSurfaces, sizeof(SharedSurfaceObject*) * pDesc->NumSurfaces); // If this is the root queue, create the surfaces if (m_pRootQueue == this) { ASSERT(pDevice); hr = CreateDeviceWrapper(pDevice, &m_pCreator); if (FAILED(hr)) { ASSERT(m_pCreator == NULL); goto cleanup; } hr = CreateSurfaces(); if (FAILED(hr)) { goto cleanup; } m_QueueSize = pDesc->NumSurfaces; } else { // Increment the reference count on the src queue m_pRootQueue->AddRef(); CopySurfaceReferences(pRootQueue); m_QueueSize = 0; } if (m_Desc.MetaDataSize) { if (FAILED(hr = AllocateMetaDataBuffers())) { goto cleanup; } } ASSERT(m_pRootQueue); if (m_IsMultithreaded) { // Create Semaphore for queue synchronization m_hSemaphore = CreateSemaphore(NULL, m_pRootQueue == this ? pDesc->NumSurfaces : 0, pDesc->NumSurfaces, NULL); if (m_hSemaphore == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } // Initialize the slim reader/writer lock InitializeSRWLock(&m_lock); } else { m_nFlushedSurfaces = m_pRootQueue == this ? pDesc->NumSurfaces : 0; } cleanup: // The object will get destroyed if initialize fails. Cleanup // will happen then. return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::OpenConsumer( IUnknown* pDevice, ISurfaceConsumer** ppConsumer) { if (pDevice == NULL) { return E_INVALIDARG; } if (ppConsumer == NULL) { return E_INVALIDARG; } *ppConsumer = NULL; HRESULT hr = E_FAIL; if (m_IsMultithreaded) { AcquireSRWLockExclusive(&m_lock); } // // If a consumer exists, we need to bail early. The normal error // path will deallocate the current consumer. Instead this will // be a no-op for the queue and E_INVALIDARG will be returned. // if (m_pConsumer) { if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } return E_INVALIDARG; } m_pConsumer = new QUEUE_NOTHROW_SPECIFIER CSurfaceConsumer(m_IsMultithreaded); if (m_pConsumer == NULL) { hr = E_OUTOFMEMORY; goto end; } hr = m_pConsumer->Initialize(pDevice); if (FAILED(hr)) { goto end; } // // For all the surfaces in the queue, we want to open it with the producing device. // This guarantees that surfaces are only open at creation time. // for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { ASSERT(m_CreatedSurfaces[i]); ASSERT(m_ConsumerSurfaces); if (NULL == m_CreatedSurfaces[i] || NULL == m_ConsumerSurfaces) { return E_FAIL; } IUnknown* pSurface = NULL; hr = m_pConsumer->GetDevice()->OpenSurface( m_CreatedSurfaces[i]->hSharedHandle, (void**)&pSurface, m_Desc.Width, m_Desc.Height, m_Desc.Format); if (FAILED(hr)) { goto end; } ASSERT(pSurface); m_ConsumerSurfaces[i].pObject = m_CreatedSurfaces[i]; m_ConsumerSurfaces[i].pSurface = pSurface; } hr = m_pConsumer->QueryInterface(__uuidof(ISurfaceConsumer), (void**) ppConsumer); if (FAILED(hr)) { goto end; } m_pConsumer->SetQueue(this); end: if (FAILED(hr)) { *ppConsumer = NULL; if (m_pConsumer) { if (m_pConsumer->GetDevice()) { for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_ConsumerSurfaces[i].pSurface) { m_ConsumerSurfaces[i].pSurface->Release(); } } } ZeroMemory(m_ConsumerSurfaces, sizeof(SharedSurfaceOpenedMapping) * m_Desc.NumSurfaces); delete m_pConsumer; m_pConsumer = NULL; } } if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::OpenProducer( IUnknown* pDevice, ISurfaceProducer** ppProducer) { if (pDevice == NULL) { return E_INVALIDARG; } if (ppProducer == NULL) { return E_INVALIDARG; } *ppProducer = NULL; HRESULT hr = E_FAIL; if (m_IsMultithreaded) { AcquireSRWLockExclusive(&m_lock); } if (m_pProducer) { if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } return E_INVALIDARG; } m_pProducer = new QUEUE_NOTHROW_SPECIFIER CSurfaceProducer(m_IsMultithreaded); if (m_pProducer == NULL) { hr = E_OUTOFMEMORY; goto end; } hr = m_pProducer->Initialize(pDevice, m_Desc.NumSurfaces, &m_Desc); if (FAILED(hr)) { goto end; } hr = m_pProducer->QueryInterface(__uuidof(ISurfaceProducer), (void**)ppProducer); if (FAILED (hr)) { goto end; } m_pProducer->SetQueue(this); end: if (FAILED(hr)) { *ppProducer = NULL; if (m_pProducer) { delete m_pProducer; m_pProducer = NULL; *ppProducer = NULL; } } if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } return hr; } //----------------------------------------------------------------------------- void CSurfaceQueue::RemoveProducer() { if (m_IsMultithreaded) { AcquireSRWLockExclusive(&m_lock); } ASSERT(m_pProducer); m_pProducer = NULL; if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } } //----------------------------------------------------------------------------- void CSurfaceQueue::RemoveConsumer() { if (m_IsMultithreaded) { AcquireSRWLockExclusive(&m_lock); } ASSERT(m_pConsumer && m_pConsumer->GetDevice()); for (UINT i = 0; i < m_Desc.NumSurfaces; i++) { if (m_ConsumerSurfaces[i].pSurface) { m_ConsumerSurfaces[i].pSurface->Release(); } } ZeroMemory(m_ConsumerSurfaces, sizeof(SharedSurfaceOpenedMapping) * m_Desc.NumSurfaces); m_pConsumer = NULL; if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::Clone( SURFACE_QUEUE_CLONE_DESC* pDesc, ISurfaceQueue** ppQueue) { // Have all the clones originate from the root queue. This makes tracking // referenes easier. if (m_pRootQueue != this) { return m_pRootQueue->Clone(pDesc, ppQueue); } if (!pDesc) { return E_INVALIDARG; } if (!ppQueue) { return E_INVALIDARG; } if (pDesc->Flags != 0 && pDesc->Flags != SURFACE_QUEUE_FLAG_SINGLE_THREADED) { return E_INVALIDARG; } *ppQueue = NULL; HRESULT hr = E_FAIL; if (m_IsMultithreaded) { AcquireSRWLockExclusive(&m_lock); } SURFACE_QUEUE_DESC createDesc = m_Desc; createDesc.MetaDataSize = pDesc->MetaDataSize; createDesc.Flags = pDesc->Flags; CSurfaceQueue* pQueue = new QUEUE_NOTHROW_SPECIFIER CSurfaceQueue(); if (!pQueue) { hr = E_OUTOFMEMORY; goto end; } hr = pQueue->Initialize(&createDesc, NULL, this); if (FAILED(hr)) { goto end; } hr = pQueue->QueryInterface(__uuidof(ISurfaceQueue), (void**)ppQueue); end: if (FAILED(hr)) { if (pQueue) { delete pQueue; } *ppQueue = NULL; } if (m_IsMultithreaded) { ReleaseSRWLockExclusive(&m_lock); } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::Enqueue( IUnknown* pSurface, void* pBuffer, UINT BufferSize, DWORD Flags, IUnknown* pStagingResource, UINT width, UINT height ) { ASSERT( pSurface ); if (pBuffer && !BufferSize) { return E_INVALIDARG; } if (!pBuffer && BufferSize) { return E_INVALIDARG; } if (BufferSize > m_Desc.MetaDataSize) { return E_INVALIDARG; } HRESULT hr = E_FAIL; if (m_IsMultithreaded) { AcquireSRWLockShared(&m_lock); } ASSERT( m_pProducer ); SharedSurfaceQueueEntry QueueEntry; HANDLE hSharedHandle; SharedSurfaceObject* pSurfaceObject; // Require both the producer and consumer to be initialized. // This avoids a potential race condition if (!m_pProducer || !m_pConsumer) { hr = E_INVALIDARG; goto end; } // Check that the queue is not full. Enqueuing onto a full queue is // not a scenario that makes sense if (m_QueueSize == m_Desc.NumSurfaces) { hr = E_INVALIDARG; goto end; } // Get the SharedSurfaceObject from the surface hr = m_pProducer->GetDevice()->GetSharedHandle(pSurface, &hSharedHandle); if (FAILED(hr)) { goto end; } pSurfaceObject = GetSurfaceObjectFromHandle(hSharedHandle); // Validate that this surface is one that can be part of this queue if (pSurfaceObject == NULL) { hr = E_INVALIDARG; goto end; } if (pSurfaceObject->state != SHARED_SURFACE_STATE_DEQUEUED) { hr = E_INVALIDARG; goto end; } QueueEntry.surface = pSurfaceObject; QueueEntry.pMetaData = (BYTE*)pBuffer; QueueEntry.bMetaDataSize = BufferSize; QueueEntry.pStagingResource = NULL; // Copy a small portion of the surface onto the staging surface hr = m_pProducer->GetDevice()->CopySurface(pStagingResource, pSurface, width, height); if (FAILED(hr)) { goto end; } pSurfaceObject->state = SHARED_SURFACE_STATE_ENQUEUED; pSurfaceObject->queue = this; // // At this point we have succesfully issued the copy to the staging resource. // The surface will now must be added to the fifo queue either in the ENQUEUED // or FLUSHED state. // // // Do not attempt to flush the surfaces if the DO_NOT_WAIT flag was used. // In these cases, simply add the surface to the FIFO queue as an ENQUEUED surface. // // // Note: m_nEnqueuedSurfaces and m_iEnqueuedHead are protected by the lock in the // SurfaceProducer. This value is not shared between the Consumer and Producer and // therefore does not need any sychronization in the queue object. // if (Flags & SURFACE_QUEUE_FLAG_DO_NOT_WAIT) { // // The surface should go into the ENQUEUED but not FLUSHED state. // // // Queue the entry into the fifo queue along with the staging resource for it // QueueEntry.pStagingResource = pStagingResource; Enqueue(QueueEntry); m_nEnqueuedSurfaces++; // // Since the surface did not flush, set the return to DXGI_ERROR_WAS_STILL_DRAWING // and return. // hr = DXGI_ERROR_WAS_STILL_DRAWING; goto end; } else if (m_nEnqueuedSurfaces) { // // Enqueued was called without the DO_NOT_WAIT flag but there are enqueued surfaces // currently not flushed. First flush the existing surfaces and then perform the // current Enqueue. // hr = Flush(0, NULL); ASSERT(SUCCEEDED(hr)); } // // Force rendering to complete by locking the staging resource. // if (FAILED(hr = m_pProducer->GetDevice()->LockSurface(pStagingResource, Flags))) { goto end; } if (FAILED(hr = m_pProducer->GetDevice()->UnlockSurface(pStagingResource))) { goto end; } ASSERT(QueueEntry.pStagingResource == NULL); // // The call to lock the surface completed succesfully meaning the surface if flushed // and ready for dequeue. Mark the surface as such and add it to the fifo queue. // pSurfaceObject->state = SHARED_SURFACE_STATE_FLUSHED; m_iEnqueuedHead = (m_iEnqueuedHead + 1) % m_Desc.NumSurfaces; Enqueue(QueueEntry); if (m_IsMultithreaded) { // Increment the semaphore ReleaseSemaphore(m_hSemaphore, 1, NULL); } else { m_nFlushedSurfaces++; } end: if (m_IsMultithreaded) { ReleaseSRWLockShared(&m_lock); } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::Dequeue( IUnknown** ppSurface, void* pBuffer, UINT* BufferSize, DWORD dwTimeout ) { if (!pBuffer && BufferSize) { return E_INVALIDARG; } if (pBuffer) { if (!BufferSize || *BufferSize == 0) { return E_INVALIDARG; } if (*BufferSize > m_Desc.MetaDataSize) { return E_INVALIDARG; } } if (m_IsMultithreaded) { AcquireSRWLockShared(&m_lock); } SharedSurfaceQueueEntry QueueElement; IUnknown* pSurface = NULL; HRESULT hr = E_FAIL; // Require both the producer and consumer to be initialized. // This avoids a potential race condition if (!m_pProducer || !m_pConsumer) { hr = E_INVALIDARG; goto end; } if (m_IsMultithreaded) { // Wait on the semaphore until the queue is not empty DWORD dwWait = WaitForSingleObject(m_hSemaphore, dwTimeout); switch (dwWait) { case WAIT_ABANDONED: hr = E_FAIL; break; case WAIT_OBJECT_0: hr = S_OK; break; case WAIT_TIMEOUT: hr = HRESULT_FROM_WIN32(WAIT_TIMEOUT); break; case WAIT_FAILED: hr = HRESULT_FROM_WIN32(GetLastError()); break; default: hr = E_FAIL; break; } } else { // In the single threaded case, dequeuing on an empty // will return immediately. The error returned is not // *exactly* right but it parallels the multithreaded // case. if (m_nFlushedSurfaces == 0) { hr = HRESULT_FROM_WIN32(WAIT_TIMEOUT); } else { m_nFlushedSurfaces--; hr = S_OK; } } // Early return because of timeout or wait error if (FAILED(hr)) { goto end; } // // At this point, there must be a surface in the queue ready to be // dequeued. Get a reference to the first surface make sure // it is valid. We don't want the situation where the surface is // removed but then fails. // // At this point there must be an surface in the queue ready to go // Dequeue it Front(QueueElement); ASSERT (QueueElement.surface->state == SHARED_SURFACE_STATE_FLUSHED); ASSERT (QueueElement.surface->queue == this); // // Update the state of the surface to dequeued // QueueElement.surface->state = SHARED_SURFACE_STATE_DEQUEUED; QueueElement.surface->device = m_pConsumer->GetDevice(); // // Get the surface for the consuming device from the surface object // pSurface = GetOpenedSurface(QueueElement.surface); ASSERT(pSurface); pSurface->AddRef(); *ppSurface = pSurface; // // There should be no more failures after here // if (pBuffer && QueueElement.bMetaDataSize) { memcpy(pBuffer, QueueElement.pMetaData, sizeof(BYTE) * QueueElement.bMetaDataSize); } // // Store the actual number of bytes copied as meta data. // if (BufferSize) { *BufferSize = QueueElement.bMetaDataSize; } // // Remove the element from the queue. We do it at the very end in case there are // errors. // Dequeue(QueueElement); end: if (m_IsMultithreaded) { ReleaseSRWLockShared(&m_lock); } return hr; } //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::Flush( DWORD Flags, UINT* pRemainingSurfaces ) { if (m_IsMultithreaded) { AcquireSRWLockShared(&m_lock); } HRESULT hr = S_OK; UINT uiFlushedSurfaces = 0; UINT index, i; // Store this locally for the loop counter. The loop will change the // value of m_nEnqueuedSurfaces. UINT uiEnqueuedSize = m_nEnqueuedSurfaces; // Require both the producer and consumer to be initialized. // This avoids a potential race condition if (!m_pProducer || !m_pConsumer) { hr = E_INVALIDARG; goto end; } // Iterate over all queue entries starting at the head. for (index = m_iEnqueuedHead, i = 0; i < uiEnqueuedSize; i++, index++) { index = index % m_Desc.NumSurfaces; SharedSurfaceQueueEntry& queueEntry = m_SurfaceQueue[index]; ASSERT(queueEntry.surface->state == SHARED_SURFACE_STATE_ENQUEUED); ASSERT(queueEntry.surface->queue == this); ASSERT(queueEntry.pStagingResource); IUnknown* pStagingResource = queueEntry.pStagingResource; // // Attempt to lock the staging surface to see if the rendering // is complete. // hr = m_pProducer->GetDevice()->LockSurface(pStagingResource, Flags); if (FAILED(hr)) { // // As soon as the first surface is not flushed, skip the remaining // goto end; } hr = m_pProducer->GetDevice()->UnlockSurface(pStagingResource); ASSERT(SUCCEEDED(hr)); // When the lock is complete, rendering is complete and the the surface is // ready for dequeue queueEntry.surface->state = SHARED_SURFACE_STATE_FLUSHED; queueEntry.pStagingResource = NULL; uiFlushedSurfaces++; // This is protected by the SurfaceProducer lock. m_nEnqueuedSurfaces--; m_iEnqueuedHead = (m_iEnqueuedHead + 1) % m_Desc.NumSurfaces; if (m_IsMultithreaded) { // Increment the semaphore count ReleaseSemaphore(m_hSemaphore, 1, NULL); } else { m_nFlushedSurfaces++; } } end: if (pRemainingSurfaces) { *pRemainingSurfaces = m_nEnqueuedSurfaces; } if (m_IsMultithreaded) { ReleaseSRWLockShared(&m_lock); } return hr; } //----------------------------------------------------------------------------- void CSurfaceQueue::Front(SharedSurfaceQueueEntry& entry) { entry = m_SurfaceQueue[m_QueueHead]; } //----------------------------------------------------------------------------- void CSurfaceQueue::Dequeue(SharedSurfaceQueueEntry& entry) { // The semaphore protecting access to the queue guarantees that the queue // can not be empty. if (m_IsMultithreaded) { EnterCriticalSection(&m_QueueLock); } entry = m_SurfaceQueue[m_QueueHead]; m_QueueHead = (m_QueueHead + 1) % m_Desc.NumSurfaces; m_QueueSize--; if (m_IsMultithreaded) { LeaveCriticalSection(&m_QueueLock); } } //----------------------------------------------------------------------------- void CSurfaceQueue::Enqueue(SharedSurfaceQueueEntry& entry) { // // The validation in the queue should guarantee that the queue is not full // if (m_IsMultithreaded) { EnterCriticalSection(&m_QueueLock); } UINT end = (m_QueueHead + m_QueueSize) % m_Desc.NumSurfaces; m_QueueSize++; if (m_IsMultithreaded) { LeaveCriticalSection(&m_QueueLock); } m_SurfaceQueue[end].surface = entry.surface; m_SurfaceQueue[end].bMetaDataSize = entry.bMetaDataSize; m_SurfaceQueue[end].pStagingResource = entry.pStagingResource; if (entry.bMetaDataSize) { memcpy(m_SurfaceQueue[end].pMetaData, entry.pMetaData, sizeof(BYTE) * entry.bMetaDataSize); } } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueue.h ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved /* this ALWAYS GENERATED file contains the definitions for the interfaces */ /* File created by MIDL compiler version 7.00.0555 */ /* Compiler settings for surfacequeue.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ #pragma warning( disable: 4049 ) /* more than 64k source lines */ /* verify that the version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ #define __REQUIRED_RPCNDR_H_VERSION__ 500 #endif /* verify that the version is high enough to compile this file*/ #ifndef __REQUIRED_RPCSAL_H_VERSION__ #define __REQUIRED_RPCSAL_H_VERSION__ 100 #endif #include "rpc.h" #include "rpcndr.h" #ifndef __RPCNDR_H_VERSION__ #error this stub requires an updated version of #endif // __RPCNDR_H_VERSION__ #ifndef COM_NO_WINDOWS_H #include "windows.h" #include "ole2.h" #endif /*COM_NO_WINDOWS_H*/ #ifndef __surfacequeue_h__ #define __surfacequeue_h__ #if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once #endif /* Forward Declarations */ #ifndef __ISurfaceProducer_FWD_DEFINED__ #define __ISurfaceProducer_FWD_DEFINED__ typedef interface ISurfaceProducer ISurfaceProducer; #endif /* __ISurfaceProducer_FWD_DEFINED__ */ #ifndef __ISurfaceConsumer_FWD_DEFINED__ #define __ISurfaceConsumer_FWD_DEFINED__ typedef interface ISurfaceConsumer ISurfaceConsumer; #endif /* __ISurfaceConsumer_FWD_DEFINED__ */ #ifndef __ISurfaceQueue_FWD_DEFINED__ #define __ISurfaceQueue_FWD_DEFINED__ typedef interface ISurfaceQueue ISurfaceQueue; #endif /* __ISurfaceQueue_FWD_DEFINED__ */ /* header files for imported files */ #include "oaidl.h" #include "ocidl.h" #include "dxgitype.h" #ifdef __cplusplus extern "C"{ #endif /* interface __MIDL_itf_surfacequeue_0000_0000 */ /* [local] */ typedef struct SURFACE_QUEUE_DESC { UINT Width; UINT Height; DXGI_FORMAT Format; UINT NumSurfaces; UINT MetaDataSize; DWORD Flags; } SURFACE_QUEUE_DESC; typedef struct SURFACE_QUEUE_CLONE_DESC { UINT MetaDataSize; DWORD Flags; } SURFACE_QUEUE_CLONE_DESC; typedef enum SURFACE_QUEUE_FLAG { SURFACE_QUEUE_FLAG_DO_NOT_WAIT = 0x1L, SURFACE_QUEUE_FLAG_SINGLE_THREADED = 0x2L } SURFACE_QUEUE_FLAG; extern RPC_IF_HANDLE __MIDL_itf_surfacequeue_0000_0000_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_surfacequeue_0000_0000_v0_0_s_ifspec; #ifndef __ISurfaceProducer_INTERFACE_DEFINED__ #define __ISurfaceProducer_INTERFACE_DEFINED__ /* interface ISurfaceProducer */ /* [unique][local][uuid][object] */ EXTERN_C const IID IID_ISurfaceProducer; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B8B0B73B-79C1-4446-BB8A-19595018B0B7") ISurfaceProducer : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Enqueue( /* [in] */ IUnknown *pSurface, /* [in] */ void *pBuffer, /* [in] */ UINT BufferSize, /* [in] */ DWORD Flags) = 0; virtual HRESULT STDMETHODCALLTYPE Flush( /* [in] */ DWORD Flags, /* [out] */ UINT *NumSurfaces) = 0; }; #else /* C style interface */ typedef struct ISurfaceProducerVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISurfaceProducer * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISurfaceProducer * This); ULONG ( STDMETHODCALLTYPE *Release )( ISurfaceProducer * This); HRESULT ( STDMETHODCALLTYPE *Enqueue )( ISurfaceProducer * This, /* [in] */ IUnknown *pSurface, /* [in] */ void *pBuffer, /* [in] */ UINT BufferSize, /* [in] */ DWORD Flags); HRESULT ( STDMETHODCALLTYPE *Flush )( ISurfaceProducer * This, /* [in] */ DWORD Flags, /* [out] */ UINT *NumSurfaces); END_INTERFACE } ISurfaceProducerVtbl; interface ISurfaceProducer { CONST_VTBL struct ISurfaceProducerVtbl *lpVtbl; }; #ifdef COBJMACROS #define ISurfaceProducer_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define ISurfaceProducer_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define ISurfaceProducer_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define ISurfaceProducer_Enqueue(This,pSurface,pBuffer,BufferSize,Flags) \ ( (This)->lpVtbl -> Enqueue(This,pSurface,pBuffer,BufferSize,Flags) ) #define ISurfaceProducer_Flush(This,Flags,NumSurfaces) \ ( (This)->lpVtbl -> Flush(This,Flags,NumSurfaces) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __ISurfaceProducer_INTERFACE_DEFINED__ */ #ifndef __ISurfaceConsumer_INTERFACE_DEFINED__ #define __ISurfaceConsumer_INTERFACE_DEFINED__ /* interface ISurfaceConsumer */ /* [unique][local][uuid][object] */ EXTERN_C const IID IID_ISurfaceConsumer; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("97E305E1-1EC7-41a6-972C-99092DE6A31E") ISurfaceConsumer : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Dequeue( /* [in] */ REFIID id, /* [out] */ IUnknown **ppSurface, /* [out] */ void *pBuffer, /* [out][in] */ UINT *pBufferSize, /* [in] */ DWORD dwTimeout) = 0; }; #else /* C style interface */ typedef struct ISurfaceConsumerVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISurfaceConsumer * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISurfaceConsumer * This); ULONG ( STDMETHODCALLTYPE *Release )( ISurfaceConsumer * This); HRESULT ( STDMETHODCALLTYPE *Dequeue )( ISurfaceConsumer * This, /* [in] */ REFIID id, /* [out] */ IUnknown **ppSurface, /* [out] */ void *pBuffer, /* [out][in] */ UINT *pBufferSize, /* [in] */ DWORD dwTimeout); END_INTERFACE } ISurfaceConsumerVtbl; interface ISurfaceConsumer { CONST_VTBL struct ISurfaceConsumerVtbl *lpVtbl; }; #ifdef COBJMACROS #define ISurfaceConsumer_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define ISurfaceConsumer_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define ISurfaceConsumer_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define ISurfaceConsumer_Dequeue(This,id,ppSurface,pBuffer,pBufferSize,dwTimeout) \ ( (This)->lpVtbl -> Dequeue(This,id,ppSurface,pBuffer,pBufferSize,dwTimeout) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __ISurfaceConsumer_INTERFACE_DEFINED__ */ #ifndef __ISurfaceQueue_INTERFACE_DEFINED__ #define __ISurfaceQueue_INTERFACE_DEFINED__ /* interface ISurfaceQueue */ /* [unique][local][uuid][object] */ EXTERN_C const IID IID_ISurfaceQueue; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("1C08437F-48DF-467e-8D55-CA9268C73779") ISurfaceQueue : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE OpenProducer( /* [in] */ IUnknown *pDevice, /* [out] */ ISurfaceProducer **ppProducer) = 0; virtual HRESULT STDMETHODCALLTYPE OpenConsumer( /* [in] */ IUnknown *pDevice, /* [out] */ ISurfaceConsumer **ppConsumer) = 0; virtual HRESULT STDMETHODCALLTYPE Clone( /* [in] */ SURFACE_QUEUE_CLONE_DESC *pDesc, /* [out] */ ISurfaceQueue **ppQueue) = 0; }; #else /* C style interface */ typedef struct ISurfaceQueueVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISurfaceQueue * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISurfaceQueue * This); ULONG ( STDMETHODCALLTYPE *Release )( ISurfaceQueue * This); HRESULT ( STDMETHODCALLTYPE *OpenProducer )( ISurfaceQueue * This, /* [in] */ IUnknown *pDevice, /* [out] */ ISurfaceProducer **ppProducer); HRESULT ( STDMETHODCALLTYPE *OpenConsumer )( ISurfaceQueue * This, /* [in] */ IUnknown *pDevice, /* [out] */ ISurfaceConsumer **ppConsumer); HRESULT ( STDMETHODCALLTYPE *Clone )( ISurfaceQueue * This, /* [in] */ SURFACE_QUEUE_CLONE_DESC *pDesc, /* [out] */ ISurfaceQueue **ppQueue); END_INTERFACE } ISurfaceQueueVtbl; interface ISurfaceQueue { CONST_VTBL struct ISurfaceQueueVtbl *lpVtbl; }; #ifdef COBJMACROS #define ISurfaceQueue_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define ISurfaceQueue_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define ISurfaceQueue_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define ISurfaceQueue_OpenProducer(This,pDevice,ppProducer) \ ( (This)->lpVtbl -> OpenProducer(This,pDevice,ppProducer) ) #define ISurfaceQueue_OpenConsumer(This,pDevice,ppConsumer) \ ( (This)->lpVtbl -> OpenConsumer(This,pDevice,ppConsumer) ) #define ISurfaceQueue_Clone(This,pDesc,ppQueue) \ ( (This)->lpVtbl -> Clone(This,pDesc,ppQueue) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __ISurfaceQueue_INTERFACE_DEFINED__ */ /* interface __MIDL_itf_surfacequeue_0000_0003 */ /* [local] */ HRESULT WINAPI CreateSurfaceQueue( SURFACE_QUEUE_DESC* pDesc, IUnknown* pDevice, ISurfaceQueue** ppQueue); extern RPC_IF_HANDLE __MIDL_itf_surfacequeue_0000_0003_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_surfacequeue_0000_0003_v0_0_s_ifspec; /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ #ifdef __cplusplus } #endif #endif ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueue.inl ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "SurfaceQueueImpl.h" //----------------------------------------------------------------------------- // CSurfaceConsumer IUnknown implementation //----------------------------------------------------------------------------- HRESULT CSurfaceConsumer::QueryInterface(REFIID id, void** ppInterface) { *ppInterface = NULL; if (id == __uuidof(ISurfaceConsumer)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } else if (id == __uuidof(IUnknown)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG CSurfaceConsumer::AddRef() { InterlockedIncrement(&m_RefCount); return m_RefCount; } ULONG CSurfaceConsumer::Release() { InterlockedDecrement(&m_RefCount); ULONG RefCount = m_RefCount; if (m_RefCount == 0) { delete this; }; return RefCount; } //----------------------------------------------------------------------------- // CSurfaceProducer IUnknown implementation //----------------------------------------------------------------------------- HRESULT CSurfaceProducer::QueryInterface(REFIID id, void** ppInterface) { *ppInterface = NULL; if (id == __uuidof(ISurfaceProducer)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } else if (id == __uuidof(IUnknown)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG CSurfaceProducer::AddRef() { InterlockedIncrement(&m_RefCount); return m_RefCount; } ULONG CSurfaceProducer::Release() { InterlockedDecrement(&m_RefCount); ULONG RefCount = m_RefCount; if (m_RefCount == 0) { delete this; }; return RefCount; } //----------------------------------------------------------------------------- // CSurfaceQueue IUnknown implementation //----------------------------------------------------------------------------- HRESULT CSurfaceQueue::QueryInterface(REFIID id, void** ppInterface) { *ppInterface = NULL; if (id == __uuidof(ISurfaceQueue)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } else if (id == __uuidof(IUnknown)) { *reinterpret_cast(ppInterface) = this; AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG CSurfaceQueue::AddRef() { InterlockedIncrement(&m_RefCount); return m_RefCount; } ULONG CSurfaceQueue::Release() { InterlockedDecrement(&m_RefCount); ULONG RefCount = m_RefCount; if (m_RefCount == 0) { delete this; }; return RefCount; } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueueImpl.h ================================================ // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #pragma once #include #include #include #include "surfacequeue.h" #include #define ASSERT(x) assert(x); // // This library doesnt use exceptions, and can be used in C++ environments with or without exception support. // It uses a non-throwing new that returns null on out-of-memory. The user of the library MUST provide a define // to tell it whether the C++ environment provides a standard throwing new. In standard-compliant environments // define QUEUE_USE_CONFORMANT_NEW (the library will specify std::nothrow to opt for a non-throwing new.) In // environments where new doesnt throw by default define QUEUE_USE_OLD_NEW. // // WARNING: If you define QUEUE_USE_OLD_NEW and use the library with a throwing new the library will have undefined behavior. // // For the default Visual Studio solution, QUEUE_USE_CONFORMANT_NEW has been defined. // #if defined(QUEUE_USE_OLD_NEW) #define QUEUE_NOTHROW_SPECIFIER #elif defined (QUEUE_USE_CONFORMANT_NEW) #define QUEUE_NOTHROW_SPECIFIER (std::nothrow) #else #error "Please select operator new for out-of-memory exception behavior." #endif // // This defines the size of staging resource. The purpose of the staging resource is // so we can copy & lock as a way to wait for rendering to complete. We ideally, want // to copy to a 1x1 staging texture but because of various driver bugs, it is more reliable // to use a slightly bigger texture (16x16). // #define SHARED_SURFACE_COPY_SIZE (16) /****************************************************************************************\ * * Implementation * \****************************************************************************************/ class CSurfaceConsumer; class CSurfaceProducer; class CSurfaceQueue; // Interface to abstract away different runtime devices. Each of the runtimes will // have a wrapper that implements this interface. This interface contains a small // subset of the public APIs that the queue needs. class ISurfaceQueueDevice { public: virtual HRESULT CreateSharedSurface(UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppSurface, HANDLE* handle) = 0; // The surface queue is designed to only share 2D textures. // D3D9 will be expecting IDirect3DTexture9 // D3D10 will be expecting ID3D10Texture2D // D3D11 will be expecting ID3D11Texture2D virtual BOOL ValidateREFIID(REFIID) = 0; // Opens a shared surface with the given handle. virtual HRESULT OpenSurface(HANDLE, void**, UINT w, UINT h, DXGI_FORMAT) = 0; // Returns the shared handle for a queue surface. This lets the queue // validate that the surface the user provided is one owned by the queue. virtual HRESULT GetSharedHandle(IUnknown*, HANDLE*) = 0; // Creates a staging resource that will be used for the synchronization. virtual HRESULT CreateCopyResource(DXGI_FORMAT, UINT width, UINT height, IUnknown** pRes) = 0; // Copy from the queue surface to the staging resource. virtual HRESULT CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height) = 0; // Locks the (staging) surface. When this call completes, the surface // has been flushed and is ready to be used by another device virtual HRESULT LockSurface(IUnknown* pSurface, DWORD flags) = 0; // Unlocks the (staging) surface. virtual HRESULT UnlockSurface(IUnknown* pSurface) = 0; // The wrapper maintins a refence to the underlying I*Device. virtual ~ISurfaceQueueDevice() {}; }; // Implementation of SurfaceQueueDevice for D3D9Ex class CSurfaceQueueDeviceD3D9 : public ISurfaceQueueDevice { public: HRESULT CreateSharedSurface(UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppSurface, HANDLE* handle); BOOL ValidateREFIID(REFIID); HRESULT OpenSurface(HANDLE, void**, UINT Width, UINT Height, DXGI_FORMAT format); HRESULT GetSharedHandle(IUnknown*, HANDLE*); HRESULT CreateCopyResource(DXGI_FORMAT, UINT width, UINT height, IUnknown** pRes); HRESULT CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height); HRESULT LockSurface(IUnknown* pSurface, DWORD flags); HRESULT UnlockSurface(IUnknown* pSurface); CSurfaceQueueDeviceD3D9(IDirect3DDevice9Ex* pD3D9Device); ~CSurfaceQueueDeviceD3D9(); private: IDirect3DDevice9Ex* m_pDevice; }; // Implementation of SurfaceQueueDevice for D3D10 class CSurfaceQueueDeviceD3D10 : public ISurfaceQueueDevice { public: HRESULT CreateSharedSurface(UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppSurface, HANDLE* handle); BOOL ValidateREFIID(REFIID); HRESULT OpenSurface(HANDLE, void**, UINT w, UINT h, DXGI_FORMAT); HRESULT GetSharedHandle(IUnknown*, HANDLE*); HRESULT CreateCopyResource(DXGI_FORMAT, UINT width, UINT height, IUnknown** pRes); HRESULT CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height); HRESULT LockSurface(IUnknown* pSurface, DWORD flags); HRESULT UnlockSurface(IUnknown* pSurface); CSurfaceQueueDeviceD3D10(ID3D10Device* pD3D10Device); ~CSurfaceQueueDeviceD3D10(); private: ID3D10Device* m_pDevice; }; // Implementation of SurfaceQueueDevice for D3D11 class CSurfaceQueueDeviceD3D11 : public ISurfaceQueueDevice { public: HRESULT CreateSharedSurface(UINT Width, UINT Height, DXGI_FORMAT format, IUnknown** ppSurface, HANDLE* handle); BOOL ValidateREFIID(REFIID); HRESULT OpenSurface(HANDLE, void**, UINT w, UINT h, DXGI_FORMAT); HRESULT GetSharedHandle(IUnknown*, HANDLE*); HRESULT CreateCopyResource(DXGI_FORMAT, UINT width, UINT height, IUnknown** pRes); HRESULT CopySurface(IUnknown* pDst, IUnknown* pSrc, UINT width, UINT height); HRESULT LockSurface(IUnknown* pSurface, DWORD flags); HRESULT UnlockSurface(IUnknown* pSurface); CSurfaceQueueDeviceD3D11(ID3D11Device* pD3D11Device); ~CSurfaceQueueDeviceD3D11(); private: ID3D11Device* m_pDevice; }; enum SharedSurfaceState { SHARED_SURFACE_STATE_UNINITIALIZED = 0, SHARED_SURFACE_STATE_DEQUEUED, SHARED_SURFACE_STATE_ENQUEUED, SHARED_SURFACE_STATE_FLUSHED, }; // This object is shared between all queues in a network and maintains state // about the surface. struct SharedSurfaceObject { HANDLE hSharedHandle; SharedSurfaceState state; UINT width; UINT height; DXGI_FORMAT format; // Tracks which queue or device currently is using the surface union { ISurfaceQueue* queue; ISurfaceQueueDevice* device; }; IUnknown* pSurface; SharedSurfaceObject(UINT Width, UINT Height, DXGI_FORMAT format); ~SharedSurfaceObject(); }; class CSurfaceConsumer : public ISurfaceConsumer { // Com Interfaces public: STDMETHOD( QueryInterface) (REFIID ID, void** ppInterface); STDMETHOD_( ULONG, AddRef)(); STDMETHOD_( ULONG, Release)(); // Public Interfaces public: STDMETHOD (Dequeue) ( REFIID id, IUnknown** ppSurface, void* pBuffer, UINT* BufferSize, DWORD dwTimeout ); // Implementation public: CSurfaceConsumer(BOOL IsMultithreaded); ~CSurfaceConsumer(); HRESULT Initialize(IUnknown* pDevice); void SetQueue(CSurfaceQueue*); ISurfaceQueueDevice* GetDevice() { return m_pDevice; } private: LONG m_RefCount; BOOL m_IsMultithreaded; // Weak reference to the queue this is part of CSurfaceQueue* m_pQueue; // The device this was opened with ISurfaceQueueDevice* m_pDevice; // Critical Section for the consumer CRITICAL_SECTION m_lock; }; class CSurfaceProducer : public ISurfaceProducer { // Com Interfaces public: STDMETHOD( QueryInterface) (REFIID ID, void** ppInterface); STDMETHOD_( ULONG, AddRef)(); STDMETHOD_( ULONG, Release)(); // Public Interfaces public: STDMETHOD (Enqueue) ( IUnknown* pSurface, void* pBuffer, UINT BufferSize, DWORD Flags ); STDMETHOD (Flush) ( DWORD Flags, UINT* NumSurfaces ); // Implementation public: CSurfaceProducer(BOOL IsMultithreaded); ~CSurfaceProducer(); HRESULT Initialize(IUnknown* pDevice, UINT uNumSurfaces, SURFACE_QUEUE_DESC* queueDesc); void SetQueue(CSurfaceQueue*); ISurfaceQueueDevice* GetDevice() { return m_pDevice; } private: LONG m_RefCount; BOOL m_IsMultithreaded; // Reference to the queue this is part of CSurfaceQueue* m_pQueue; // The producer device ISurfaceQueueDevice* m_pDevice; // Critical Section for the producer CRITICAL_SECTION m_lock; // Circular buffer of staging resources UINT m_nStagingResources; IUnknown** m_pStagingResources; // Size of staging resource UINT m_uiStagingResourceWidth; UINT m_uiStagingResourceHeight; // Index of current staging resource to use UINT m_iCurrentResource; }; class CSurfaceQueue : public ISurfaceQueue { // Com Functions public: STDMETHOD( QueryInterface) (REFIID ID, void** ppInterface); STDMETHOD_( ULONG, AddRef)(); STDMETHOD_( ULONG, Release)(); // ISurfaceQueue functions public: STDMETHOD (OpenProducer) ( IUnknown* pDevice, ISurfaceProducer** ppProducer ); STDMETHOD (OpenConsumer) ( IUnknown* pDevice, ISurfaceConsumer** ppConsumer ); STDMETHOD (Clone) ( SURFACE_QUEUE_CLONE_DESC* pDesc, ISurfaceQueue** ppQueue ); // Implementation Functions public: CSurfaceQueue(); ~CSurfaceQueue(); // Initializes the queue. Creates the surfaces, initializes the synchronization code HRESULT Initialize(SURFACE_QUEUE_DESC*, IUnknown*, CSurfaceQueue*); // Removes the producer device void RemoveProducer(); // Removes the consumer device. void RemoveConsumer(); HRESULT Enqueue( IUnknown* pSurface, void* pBuffer, UINT BufferSize, DWORD Flags, IUnknown* pStagingResource, UINT width, UINT height ); HRESULT Dequeue( IUnknown** ppSurface, void* pBuffer, UINT* BufferSize, DWORD dwTimeout ); HRESULT Flush( DWORD Flags, UINT* NumSurfaces ); private: struct SharedSurfaceQueueEntry { SharedSurfaceObject* surface; BYTE* pMetaData; UINT bMetaDataSize; IUnknown* pStagingResource; SharedSurfaceQueueEntry() { surface = NULL; pMetaData = NULL; bMetaDataSize = 0; pStagingResource = NULL; } }; struct SharedSurfaceOpenedMapping { SharedSurfaceObject* pObject; IUnknown* pSurface; }; private: void Destroy(); HRESULT CreateSurfaces(); void CopySurfaceReferences(CSurfaceQueue*); HRESULT AllocateMetaDataBuffers(); ISurfaceQueueDevice* GetCreatorDevice(); UINT GetNumQueuesInNetwork(); UINT AddQueueToNetwork(); UINT RemoveQueueFromNetwork(); void Dequeue(SharedSurfaceQueueEntry& entry); void Enqueue(SharedSurfaceQueueEntry& entry); void Front(SharedSurfaceQueueEntry& entry); SharedSurfaceObject* GetSurfaceObjectFromHandle(HANDLE h); IUnknown* GetOpenedSurface(const SharedSurfaceObject*) const; private: LONG m_RefCount; BOOL m_IsMultithreaded; // Synchronization object to handle concurrent dequeues and enqueues // For the single threaded case, we can keep track of the number of // availible surfaces to help the user prevent hanging on an empty // queue. union { HANDLE m_hSemaphore; UINT m_nFlushedSurfaces; }; // Refernce to the source queue object CSurfaceQueue* m_pRootQueue; // Number of Queue objects in the network - only stored in root queue volatile LONG m_NumQueuesInNetwork; // References to producer and consumer objects CSurfaceConsumer* m_pConsumer; CSurfaceProducer* m_pProducer; // Reference to the creating device ISurfaceQueueDevice* m_pCreator; // FIFO Surface Queue SharedSurfaceQueueEntry* m_SurfaceQueue; UINT m_QueueHead; UINT m_QueueSize; SharedSurfaceOpenedMapping* m_ConsumerSurfaces; SharedSurfaceObject** m_CreatedSurfaces; UINT m_iEnqueuedHead; UINT m_nEnqueuedSurfaces; SURFACE_QUEUE_DESC m_Desc; // Lock around all of the public queue functions. This should have very little contention // and is used to synchronize rare queue state changes (i.e. the consumer device changes). SRWLOCK m_lock; // Lock for access to the underlying queue CRITICAL_SECTION m_QueueLock; }; ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueueInteropHelper.cpp ================================================ #include "SurfaceQueueInteropHelper.h" #pragma once using namespace System; using namespace System::Windows; using namespace System::Windows::Interop; #define WIDTH 640 #define HEIGHT 480 REFIID surfaceIDDXGI = __uuidof(IDXGISurface); REFIID surfaceID9 = __uuidof(IDirect3DTexture9); namespace Microsoft { namespace Windows { namespace Media { HRESULT SurfaceQueueInteropHelper::InitD3D10() { HRESULT hr; UINT DeviceFlags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; //DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #ifdef _DEBUG // To debug DirectX, uncomment the following lines: //DeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; //dwShaderFlags |= D3D10_SHADER_DEBUG; #endif { pin_ptr pinD3D10Device = &m_D3D10Device; ID3D10Device1** ppD3D10Device = pinD3D10Device; if (FAILED(hr = D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, DeviceFlags, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, ppD3D10Device))) { return hr; } } D3D10_VIEWPORT vp; vp.Width = WIDTH; vp.Height = HEIGHT; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; m_D3D10Device->RSSetViewports(1, &vp); return S_OK; } void SurfaceQueueInteropHelper::RenderToDXGI(IntPtr pdxgiSurface, bool isNewSurface) { if (nullptr != m_renderD2D) { m_renderD2D(pdxgiSurface, isNewSurface); } } void SurfaceQueueInteropHelper::CleanupD3D10() { ReleaseInterface(m_D3D10Device); } HRESULT SurfaceQueueInteropHelper::InitD3D9() { HRESULT hr; { pin_ptr pinD3D9 = &m_pD3D9; IDirect3D9Ex** ppD3D9 = pinD3D9; Direct3DCreate9Ex(D3D_SDK_VERSION, ppD3D9); } if (!m_pD3D9) { return E_FAIL; } D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = NULL; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; { pin_ptr pinD3D9Device = &m_pD3D9Device; IDirect3DDevice9Ex** ppD3D9Device = pinD3D9Device; hr = m_pD3D9->CreateDeviceEx( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, &d3dpp, NULL, ppD3D9Device); } return hr; } void SurfaceQueueInteropHelper::CleanupD3D9() { ReleaseInterface(m_pD3D9Device); ReleaseInterface(m_pD3D9); } void SurfaceQueueInteropHelper::CleanupSurfaces() { m_areSurfacesInitialized = false; ReleaseInterface(m_BAProducer); ReleaseInterface(m_ABProducer); ReleaseInterface(m_BAConsumer); ReleaseInterface(m_ABConsumer); ReleaseInterface(m_ABQueue); ReleaseInterface(m_BAQueue); } void SurfaceQueueInteropHelper::CleanupD3D() { if (m_areSurfacesInitialized) { CleanupSurfaces(); } m_isD3DInitialized = false; CleanupD3D10(); CleanupD3D9(); } HRESULT SurfaceQueueInteropHelper::InitD3D() { HRESULT hr = S_OK; if (!m_isD3DInitialized) { IFC(InitD3D9()); IFC(InitD3D10()); m_isD3DInitialized = true; } Cleanup: if (FAILED(hr)) { CleanupD3D(); } return hr; } HRESULT SurfaceQueueInteropHelper::InitSurfaces() { HRESULT hr = S_OK; SURFACE_QUEUE_DESC desc; ZeroMemory(&desc, sizeof(desc)); desc.Width = m_pixelWidth; desc.Height = m_pixelHeight; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.NumSurfaces = 1; desc.MetaDataSize = sizeof(int); desc.Flags = SURFACE_QUEUE_FLAG_SINGLE_THREADED; SURFACE_QUEUE_CLONE_DESC CloneDesc = { 0 }; CloneDesc.MetaDataSize = 0; CloneDesc.Flags = SURFACE_QUEUE_FLAG_SINGLE_THREADED; if (!m_isD3DInitialized || (desc.Width <= 0) || (desc.Height <= 0)) { hr = S_FALSE; goto Cleanup; } if (!m_areSurfacesInitialized) { // // Initialize the surface queues // { pin_ptr pinABQueue = &m_ABQueue; ISurfaceQueue** ppABQueue = pinABQueue; IFC(CreateSurfaceQueue(&desc, m_pD3D9Device, ppABQueue)); } // Clone the queue { pin_ptr pinBAQueue = &m_BAQueue; ISurfaceQueue** ppBAQueue = pinBAQueue; IFC(m_ABQueue->Clone(&CloneDesc, ppBAQueue)); } // Setup queue management { pin_ptr pinm_BAProducer = &m_BAProducer; ISurfaceProducer** ppm_BAProducer = pinm_BAProducer; IFC(m_BAQueue->OpenProducer(m_D3D10Device, ppm_BAProducer)); } { pin_ptr pinm_ABConsumer = &m_ABConsumer; ISurfaceConsumer** ppm_ABConsumer = pinm_ABConsumer; IFC(m_ABQueue->OpenConsumer(m_D3D10Device, ppm_ABConsumer)); } { pin_ptr pinm_ABProducer = &m_ABProducer; ISurfaceProducer** ppm_ABProducer = pinm_ABProducer; IFC(m_ABQueue->OpenProducer(m_pD3D9Device, ppm_ABProducer)); } { pin_ptr pinm_BAConsumer = &m_BAConsumer; ISurfaceConsumer** ppm_BAConsumer = pinm_BAConsumer; IFC(m_BAQueue->OpenConsumer(m_pD3D9Device, ppm_BAConsumer)); } m_areSurfacesInitialized = true; } Cleanup: return hr; } // Returns true if this instance is now initialized. bool SurfaceQueueInteropHelper::Initialize() { HRESULT hr = S_OK; if (m_isD3DInitialized) { hr = m_pD3D9Device->CheckDeviceState(NULL); if (D3D_OK != hr) { CleanupD3D(); } } if (!m_isD3DInitialized) { IFC(InitD3D()); } if (!m_areSurfacesInitialized) { // Can be S_FALSE if there's nothing to do. IFC(InitSurfaces()); } Cleanup: // Clean up, but don't throw, as this can be a transient failure. // TODO: Consider if/how to differentiate between fatal failure and transient failure. if (FAILED(hr)) { CleanupD3D(); } return m_areSurfacesInitialized; } // If fShouldRenderD3D10 is true, this method performs the callout to RenderD3D10. // In any case, this method always initializes m_d3dImage which incurrs no cost if this results in no change. void SurfaceQueueInteropHelper::QueueHelper(QueueRenderMode renderMode) { HRESULT hr = S_OK; IDXGISurface* pDXGISurface = NULL; IUnknown* pUnkDXGISurface = NULL; IDirect3DTexture9* pTexture9 = NULL; IUnknown* pUnkTexture9 = NULL; IDirect3DSurface9* pSurface9 = NULL; DXGI_SURFACE_DESC desc; // D3D10 portion int count = 0; UINT size = sizeof(int); bool fNeedUnlock = false; bool isNewSurface = !m_areSurfacesInitialized; if (m_shouldSkipRender || (nullptr == m_d3dImage) || !Initialize()) { goto Cleanup; } m_d3dImage->Lock(); fNeedUnlock = true; // Flush the AB queue m_ABProducer->Flush(0 /* wait */, NULL); // Dequeue from AB queue IFC(m_ABConsumer->Dequeue(surfaceIDDXGI, &pUnkDXGISurface, &count, &size, INFINITE)); IFC(pUnkDXGISurface->QueryInterface(surfaceIDDXGI, (void**)&pDXGISurface)); IFC(pDXGISurface->GetDesc(&desc)); if (renderMode == QueueRenderMode::RenderDXGI) { // Render D3D10 content try { RenderToDXGI((IntPtr)(void*)pDXGISurface, isNewSurface); } catch (Exception^) { IFC(E_FAIL); } } // Produce the surface m_BAProducer->Enqueue(pDXGISurface, NULL, NULL, SURFACE_QUEUE_FLAG_DO_NOT_WAIT); // Flush the BA queue m_BAProducer->Flush(0 /* wait, *not* SURFACE_QUEUE_FLAG_DO_NOT_WAIT*/, NULL); // Dequeue from BA queue IFC(m_BAConsumer->Dequeue(surfaceID9, &pUnkTexture9, NULL, NULL, INFINITE)); IFC(pUnkTexture9->QueryInterface(surfaceID9, (void**)&pTexture9)); // Get the top level surface from the texture IFC(pTexture9->GetSurfaceLevel(0, &pSurface9)); m_d3dImage->SetBackBuffer(System::Windows::Interop::D3DResourceType::IDirect3DSurface9, (IntPtr)(void*)pSurface9, true // enableSoftwareFallback // Supports fallback to software rendering for Remote Desktop, etc... // Was added in WPF 4.5 ); // Produce Surface m_ABProducer->Enqueue(pTexture9, &count, sizeof(int), SURFACE_QUEUE_FLAG_DO_NOT_WAIT); // Flush the AB queue - use "do not wait" here, we'll block at the top of the *next* call if we need to m_ABProducer->Flush(SURFACE_QUEUE_FLAG_DO_NOT_WAIT, NULL); Cleanup: if (fNeedUnlock) { m_d3dImage->AddDirtyRect(Int32Rect(0, 0, m_d3dImage->PixelWidth, m_d3dImage->PixelHeight)); m_d3dImage->Unlock(); } ReleaseInterface(pSurface9); ReleaseInterface(pTexture9); ReleaseInterface(pUnkTexture9); ReleaseInterface(pDXGISurface); ReleaseInterface(pUnkDXGISurface); } void SurfaceQueueInteropHelper::SetPixelSize(unsigned int pixelWidth, unsigned int pixelHeight) { if ((m_pixelWidth != pixelWidth) || (m_pixelHeight != pixelHeight)) { m_pixelWidth = pixelWidth; m_pixelHeight = pixelHeight; CleanupSurfaces(); QueueHelper(QueueRenderMode::RenderDXGI); } } void SurfaceQueueInteropHelper::RequestRenderD2D() { QueueHelper(QueueRenderMode::RenderDXGI); } SurfaceQueueInteropHelper::!SurfaceQueueInteropHelper() { CleanupD3D(); } SurfaceQueueInteropHelper::~SurfaceQueueInteropHelper() { CleanupD3D(); } } } } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/SurfaceQueueInteropHelper.h ================================================ // SurfaceQueueInteropHelper.h #include "stdafx.h" #pragma once using namespace System; using namespace System::Windows; using namespace System::Windows::Interop; namespace Microsoft { namespace Windows { namespace Media { /// A helper class which enables several versions of DirectX to share the same rendering surface. public ref class SurfaceQueueInteropHelper : IDisposable { private: Action^ m_renderD2D; D3DImage^ m_d3dImage; DependencyPropertyChangedEventHandler^ m_frontBufferAvailableChanged; UINT m_pixelWidth, m_pixelHeight; HWND m_hwnd; IDirect3D9Ex* m_pD3D9; IDirect3DDevice9Ex* m_pD3D9Device; ID3D10Device1* m_D3D10Device; ISurfaceQueue* m_ABQueue; ISurfaceQueue* m_BAQueue; ISurfaceConsumer* m_ABConsumer; ISurfaceProducer* m_BAProducer; ISurfaceConsumer* m_BAConsumer; ISurfaceProducer* m_ABProducer; bool m_isD3DInitialized; bool m_areSurfacesInitialized; bool m_shouldSkipRender; // Could hypothetically add additional types enum struct QueueRenderMode { None = 0, RenderDXGI = 1 }; HRESULT InitD3D10(); void RenderToDXGI(IntPtr pdxgiSurface, bool isNewSurface); void CleanupD3D10(); HRESULT InitD3D9(); void CleanupD3D9(); void CleanupSurfaces(); void CleanupD3D(); HRESULT InitD3D(); HRESULT InitSurfaces(); bool Initialize(); // If fShouldRenderD3D10 is true, this method performs the callout to RenderD3D10. // In any case, this method always initializes m_d3dImage which incurrs no cost if this results in no change. void QueueHelper(QueueRenderMode renderMode); public: /// The action delegate called when a render is required. property Action^ SurfaceQueueInteropHelper::RenderD2D { void set(Action^ value) { m_renderD2D = value; } } /// Gets or sets the associated D3DImage object that is working in conjunction with this helper. property D3DImage^ SurfaceQueueInteropHelper::D3DImage { System::Windows::Interop::D3DImage^ get() { return m_d3dImage; } void set(System::Windows::Interop::D3DImage^ d3dImage) { if (d3dImage != m_d3dImage) { if (nullptr != m_d3dImage) { m_d3dImage->SetBackBuffer(System::Windows::Interop::D3DResourceType::IDirect3DSurface9, (IntPtr)nullptr); } m_d3dImage = d3dImage; // TODO: Force a rerender...? } } } /// Gets the desired pixel width for the surface. property unsigned int SurfaceQueueInteropHelper::PixelWidth { unsigned int get() { return m_pixelWidth; } } /// Gets the desired pixel height for the surface. property unsigned int SurfaceQueueInteropHelper::PixelHeight { unsigned int get() { return m_pixelHeight; } } /// Enables user of this component to set the desired pixel size for the surface. void SetPixelSize(unsigned int pixelWidth, unsigned int pixelHeight); /// Gets or sets the HWND used by the helper while creating DirectX devices. property IntPtr SurfaceQueueInteropHelper::HWND { IntPtr get() { return (IntPtr)(void*)m_hwnd; } void set(IntPtr hwnd) { m_hwnd = (::HWND)(void*)hwnd; } } /// Requests render to happen. void RequestRenderD2D(); !SurfaceQueueInteropHelper(); ~SurfaceQueueInteropHelper(); }; } } } ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX/version.rc ================================================ ///////////////////////////////////////////////////////////////////////////// // // Version // #include #include ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX_dxsdk.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Wpf.Interop.DirectX_dxsdk", "Microsoft.Wpf.Interop.DirectX\Microsoft.Wpf.Interop.DirectX.csproj", "{51880B2F-A2DD-4669-B7F2-D5315B03C06D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x64.ActiveCfg = Debug|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x64.Build.0 = Debug|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x86.ActiveCfg = Debug|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x86.Build.0 = Debug|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x64.ActiveCfg = Release|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x64.Build.0 = Release|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x86.ActiveCfg = Release|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x86.Build.0 = Release|Win32 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Debug|x64.ActiveCfg = Debug|x64 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Debug|x64.Build.0 = Debug|x64 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Debug|x86.ActiveCfg = Debug|Win32 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Debug|x86.Build.0 = Debug|Win32 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Release|x64.ActiveCfg = Release|x64 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Release|x64.Build.0 = Release|x64 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Release|x86.ActiveCfg = Release|Win32 {51880B2F-A2DD-4669-B7F2-D5315B03C06D}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: src/Microsoft.Wpf.Interop.DirectX_winsdk.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Wpf.Interop.DirectX_winsdk", "Microsoft.Wpf.Interop.DirectX\Microsoft.Wpf.Interop.DirectX_winsdk.vcxproj", "{157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x64.ActiveCfg = Debug|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x64.Build.0 = Debug|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x86.ActiveCfg = Debug|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Debug|x86.Build.0 = Debug|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x64.ActiveCfg = Release|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x64.Build.0 = Release|x64 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x86.ActiveCfg = Release|Win32 {157A478D-FE02-4EB2-BD7C-8CF3BF1CB9A2}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal