Add wgc demo

This commit is contained in:
dijunkun
2023-08-28 00:53:55 +08:00
parent 69ee2ed5d5
commit 8f803cbd4c
37 changed files with 2561 additions and 6 deletions

View File

@@ -0,0 +1,85 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE SOFTWARE IS PROVIDED <20>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.
//
//*********************************************************
#include "pch.h"
#include "App.h"
#include "SimpleCapture.h"
using namespace winrt;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::Graphics::Capture;
void App::Initialize(ContainerVisual const &root) {
auto queue = DispatcherQueue::GetForCurrentThread();
m_compositor = root.Compositor();
m_root = m_compositor.CreateContainerVisual();
m_content = m_compositor.CreateSpriteVisual();
m_brush = m_compositor.CreateSurfaceBrush();
m_root.RelativeSizeAdjustment({1, 1});
root.Children().InsertAtTop(m_root);
m_content.AnchorPoint({0.5f, 0.5f});
m_content.RelativeOffsetAdjustment({0.5f, 0.5f, 0});
m_content.RelativeSizeAdjustment({1, 1});
m_content.Size({-80, -80});
m_content.Brush(m_brush);
m_brush.HorizontalAlignmentRatio(0.5f);
m_brush.VerticalAlignmentRatio(0.5f);
m_brush.Stretch(CompositionStretch::Uniform);
auto shadow = m_compositor.CreateDropShadow();
shadow.Mask(m_brush);
m_content.Shadow(shadow);
m_root.Children().InsertAtTop(m_content);
auto d3dDevice = CreateD3DDevice();
auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
m_device = CreateDirect3DDevice(dxgiDevice.get());
}
void App::StartCapture(HWND hwnd) {
if (m_capture) {
m_capture->Close();
m_capture = nullptr;
}
auto item = CreateCaptureItemForWindow(hwnd);
m_capture = std::make_unique<SimpleCapture>(m_device, item);
auto surface = m_capture->CreateSurface(m_compositor);
m_brush.Surface(surface);
m_capture->StartCapture();
}
void App::StartCapture(HMONITOR hmonitor) {
if (m_capture) {
m_capture->Close();
m_capture = nullptr;
}
auto item = CreateCaptureItemForMonitor(hmonitor);
m_capture = std::make_unique<SimpleCapture>(m_device, item);
auto surface = m_capture->CreateSurface(m_compositor);
m_brush.Surface(surface);
m_capture->StartCapture();
}

View File

@@ -0,0 +1,24 @@
#pragma once
class SimpleCapture;
class App {
public:
App() {}
~App() {}
void Initialize(winrt::Windows::UI::Composition::ContainerVisual const &root);
void StartCapture(HWND hwnd);
void StartCapture(HMONITOR hmonitor);
private:
winrt::Windows::UI::Composition::Compositor m_compositor{nullptr};
winrt::Windows::UI::Composition::ContainerVisual m_root{nullptr};
winrt::Windows::UI::Composition::SpriteVisual m_content{nullptr};
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{
nullptr};
std::unique_ptr<SimpleCapture> m_capture{nullptr};
};

View File

@@ -0,0 +1,219 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE SOFTWARE IS PROVIDED <20>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.
//
//*********************************************************
#include "pch.h"
#include "SimpleCapture.h"
using namespace winrt;
using namespace Windows;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::Graphics;
using namespace Windows::Graphics::Capture;
using namespace Windows::Graphics::DirectX;
using namespace Windows::Graphics::DirectX::Direct3D11;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
SimpleCapture::SimpleCapture(IDirect3DDevice const &device,
GraphicsCaptureItem const &item) {
m_item = item;
m_device = device;
// Set up
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
d3dDevice->GetImmediateContext(m_d3dContext.put());
auto size = m_item.Size();
m_swapChain = CreateDXGISwapChain(
d3dDevice, static_cast<uint32_t>(size.Width),
static_cast<uint32_t>(size.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized), 2);
// Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and
// frame size.
m_framePool = Direct3D11CaptureFramePool::Create(
m_device, DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, size);
m_session = m_framePool.CreateCaptureSession(m_item);
m_lastSize = size;
m_frameArrived = m_framePool.FrameArrived(
auto_revoke, {this, &SimpleCapture::OnFrameArrived});
}
// Start sending capture frames
void SimpleCapture::StartCapture() {
CheckClosed();
m_session.StartCapture();
}
ICompositionSurface SimpleCapture::CreateSurface(Compositor const &compositor) {
CheckClosed();
return CreateCompositionSurfaceForSwapChain(compositor, m_swapChain.get());
}
// Process captured frames
void SimpleCapture::Close() {
auto expected = false;
if (m_closed.compare_exchange_strong(expected, true)) {
m_frameArrived.revoke();
m_framePool.Close();
m_session.Close();
m_swapChain = nullptr;
m_framePool = nullptr;
m_session = nullptr;
m_item = nullptr;
}
}
void SimpleCapture::OnFrameArrived(
Direct3D11CaptureFramePool const &sender,
winrt::Windows::Foundation::IInspectable const &) {
auto newSize = false;
{
auto frame = sender.TryGetNextFrame();
auto frameContentSize = frame.ContentSize();
if (frameContentSize.Width != m_lastSize.Width ||
frameContentSize.Height != m_lastSize.Height) {
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
newSize = true;
m_lastSize = frameContentSize;
m_swapChain->ResizeBuffers(
2, static_cast<uint32_t>(m_lastSize.Width),
static_cast<uint32_t>(m_lastSize.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
0);
}
// copy to swapChain
{
auto frameSurface =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
com_ptr<ID3D11Texture2D> backBuffer;
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(),
backBuffer.put_void()));
m_d3dContext->CopyResource(backBuffer.get(), frameSurface.get());
DXGI_PRESENT_PARAMETERS presentParameters = {0};
m_swapChain->Present1(1, 0, &presentParameters);
}
// copy to mapped texture
{
auto frameSurface =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
if (!m_mappedTexture || newSize)
CreateMappedTexture(frameSurface);
m_d3dContext->CopyResource(m_mappedTexture.get(), frameSurface.get());
D3D11_MAPPED_SUBRESOURCE mapInfo;
m_d3dContext->Map(m_mappedTexture.get(), 0, D3D11_MAP_READ,
D3D11_MAP_FLAG_DO_NOT_WAIT, &mapInfo);
// copy data from mapInfo.pData
#if 1
if (mapInfo.pData) {
static unsigned char *buffer = nullptr;
if (buffer && newSize)
delete[] buffer;
if (!buffer)
buffer = new unsigned char[frameContentSize.Width *
frameContentSize.Height * 4];
int dstRowPitch = frameContentSize.Width * 4;
for (int h = 0; h < frameContentSize.Height; h++) {
memcpy_s(buffer + h * dstRowPitch, dstRowPitch,
(BYTE *)mapInfo.pData + h * mapInfo.RowPitch,
min(mapInfo.RowPitch, dstRowPitch));
}
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = frameContentSize.Width;
bi.biHeight = frameContentSize.Height * (-1);
bi.biPlanes = 1;
bi.biBitCount = 32; // should get from system color bits
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
BITMAPFILEHEADER bf;
bf.bfType = 0x4d42;
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bf.bfSize =
bf.bfOffBits + frameContentSize.Width * frameContentSize.Height * 4;
FILE *fp = nullptr;
fopen_s(&fp, ".\\save.bmp", "wb+");
fwrite(&bf, 1, sizeof(bf), fp);
fwrite(&bi, 1, sizeof(bi), fp);
fwrite(buffer, 1, frameContentSize.Width * frameContentSize.Height * 4,
fp);
fflush(fp);
fclose(fp);
}
#endif
m_d3dContext->Unmap(m_mappedTexture.get(), 0);
}
}
if (newSize) {
m_framePool.Recreate(m_device, DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, m_lastSize);
}
}
HRESULT
SimpleCapture::CreateMappedTexture(winrt::com_ptr<ID3D11Texture2D> src_texture,
UINT width, UINT height) {
D3D11_TEXTURE2D_DESC src_desc;
src_texture->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC map_desc;
map_desc.Width = width == 0 ? src_desc.Width : width;
map_desc.Height = height == 0 ? src_desc.Height : height;
map_desc.MipLevels = src_desc.MipLevels;
map_desc.ArraySize = src_desc.ArraySize;
map_desc.Format = src_desc.Format;
map_desc.SampleDesc = src_desc.SampleDesc;
map_desc.Usage = D3D11_USAGE_STAGING;
map_desc.BindFlags = 0;
map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
map_desc.MiscFlags = 0;
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
return d3dDevice->CreateTexture2D(&map_desc, nullptr, m_mappedTexture.put());
}

View File

@@ -0,0 +1,49 @@
#pragma once
class SimpleCapture {
public:
SimpleCapture(
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const
&device,
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &item);
~SimpleCapture() { Close(); }
void StartCapture();
winrt::Windows::UI::Composition::ICompositionSurface
CreateSurface(winrt::Windows::UI::Composition::Compositor const &compositor);
void Close();
private:
void OnFrameArrived(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
&sender,
winrt::Windows::Foundation::IInspectable const &args);
void CheckClosed() {
if (m_closed.load() == true) {
throw winrt::hresult_error(RO_E_CLOSED);
}
}
HRESULT
CreateMappedTexture(winrt::com_ptr<ID3D11Texture2D> src_texture,
UINT width = 0, UINT height = 0);
private:
winrt::Windows::Graphics::Capture::GraphicsCaptureItem m_item{nullptr};
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_framePool{
nullptr};
winrt::Windows::Graphics::Capture::GraphicsCaptureSession m_session{nullptr};
winrt::Windows::Graphics::SizeInt32 m_lastSize;
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{
nullptr};
winrt::com_ptr<IDXGISwapChain1> m_swapChain{nullptr};
winrt::com_ptr<ID3D11DeviceContext> m_d3dContext{nullptr};
winrt::com_ptr<ID3D11Texture2D> m_mappedTexture{nullptr};
std::atomic<bool> m_closed = false;
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
FrameArrived_revoker m_frameArrived;
};

View File

@@ -0,0 +1,50 @@
#pragma once
#include <dwmapi.h>
struct Monitor {
public:
Monitor(nullptr_t) {}
Monitor(HMONITOR hmonitor, std::wstring &className, bool isPrimary) {
m_hmonitor = hmonitor;
m_className = className;
m_bIsPrimary = isPrimary;
}
HMONITOR Hmonitor() const noexcept { return m_hmonitor; }
std::wstring ClassName() const noexcept { return m_className; }
bool IsPrimary() const noexcept { return m_bIsPrimary; }
private:
HMONITOR m_hmonitor;
std::wstring m_className;
bool m_bIsPrimary;
};
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc,
LPARAM data) {
MONITORINFOEX info_ex;
info_ex.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hmonitor, &info_ex);
if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER)
return true;
auto monitors = ((std::vector<Monitor> *)data);
std::wstring name = info_ex.szDevice;
auto monitor =
Monitor(hmonitor, name, info_ex.dwFlags & MONITORINFOF_PRIMARY);
monitors->emplace_back(monitor);
return true;
}
std::vector<Monitor> EnumerateMonitors() {
std::vector<Monitor> monitors;
::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&monitors);
return monitors;
}

View File

@@ -0,0 +1,101 @@
#pragma once
#include <dwmapi.h>
struct Window {
public:
Window(nullptr_t) {}
Window(HWND hwnd, std::wstring const &title, std::wstring &className) {
m_hwnd = hwnd;
m_title = title;
m_className = className;
}
HWND Hwnd() const noexcept { return m_hwnd; }
std::wstring Title() const noexcept { return m_title; }
std::wstring ClassName() const noexcept { return m_className; }
private:
HWND m_hwnd;
std::wstring m_title;
std::wstring m_className;
};
std::wstring GetClassName(HWND hwnd) {
std::array<WCHAR, 1024> className;
::GetClassName(hwnd, className.data(), (int)className.size());
std::wstring title(className.data());
return title;
}
std::wstring GetWindowText(HWND hwnd) {
std::array<WCHAR, 1024> windowText;
::GetWindowText(hwnd, windowText.data(), (int)windowText.size());
std::wstring title(windowText.data());
return title;
}
bool IsAltTabWindow(Window const &window) {
HWND hwnd = window.Hwnd();
HWND shellWindow = GetShellWindow();
auto title = window.Title();
auto className = window.ClassName();
if (hwnd == shellWindow) {
return false;
}
if (title.length() == 0) {
return false;
}
if (!IsWindowVisible(hwnd)) {
return false;
}
if (GetAncestor(hwnd, GA_ROOT) != hwnd) {
return false;
}
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (!((style & WS_DISABLED) != WS_DISABLED)) {
return false;
}
DWORD cloaked = FALSE;
HRESULT hrTemp =
DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked));
if (SUCCEEDED(hrTemp) && cloaked == DWM_CLOAKED_SHELL) {
return false;
}
return true;
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
auto class_name = GetClassName(hwnd);
auto title = GetWindowText(hwnd);
auto window = Window(hwnd, title, class_name);
if (!IsAltTabWindow(window)) {
return TRUE;
}
std::vector<Window> &windows =
*reinterpret_cast<std::vector<Window> *>(lParam);
windows.push_back(window);
return TRUE;
}
const std::vector<Window> EnumerateWindows() {
std::vector<Window> windows;
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&windows));
return windows;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <windows.graphics.capture.h>
#include <windows.graphics.capture.interop.h>
#include <winrt/Windows.Graphics.Capture.h>
inline auto CreateCaptureItemForWindow(HWND hwnd) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForWindow(
hwnd,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void **>(winrt::put_abi(item)));
return item;
}
inline auto CreateCaptureItemForMonitor(HMONITOR hmonitor) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForMonitor(
hmonitor,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void **>(winrt::put_abi(item)));
return item;
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include <d2d1_1.h>
#include <windows.ui.composition.interop.h>
#include <winrt/Windows.UI.Composition.h>
inline auto CreateCompositionGraphicsDevice(
winrt::Windows::UI::Composition::Compositor const &compositor,
::IUnknown *device) {
winrt::Windows::UI::Composition::CompositionGraphicsDevice graphicsDevice{
nullptr};
auto compositorInterop =
compositor.as<ABI::Windows::UI::Composition::ICompositorInterop>();
winrt::com_ptr<ABI::Windows::UI::Composition::ICompositionGraphicsDevice>
graphicsInterop;
winrt::check_hresult(
compositorInterop->CreateGraphicsDevice(device, graphicsInterop.put()));
winrt::check_hresult(graphicsInterop->QueryInterface(
winrt::guid_of<
winrt::Windows::UI::Composition::CompositionGraphicsDevice>(),
reinterpret_cast<void **>(winrt::put_abi(graphicsDevice))));
return graphicsDevice;
}
inline void ResizeSurface(
winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface,
winrt::Windows::Foundation::Size const &size) {
auto surfaceInterop = surface.as<
ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>();
SIZE newSize = {};
newSize.cx = static_cast<LONG>(std::round(size.Width));
newSize.cy = static_cast<LONG>(std::round(size.Height));
winrt::check_hresult(surfaceInterop->Resize(newSize));
}
inline auto SurfaceBeginDraw(
winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface) {
auto surfaceInterop = surface.as<
ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>();
winrt::com_ptr<ID2D1DeviceContext> context;
POINT offset = {};
winrt::check_hresult(surfaceInterop->BeginDraw(
nullptr, __uuidof(ID2D1DeviceContext), context.put_void(), &offset));
context->SetTransform(
D2D1::Matrix3x2F::Translation((FLOAT)offset.x, (FLOAT)offset.y));
return context;
}
inline void SurfaceEndDraw(
winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface) {
auto surfaceInterop = surface.as<
ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>();
winrt::check_hresult(surfaceInterop->EndDraw());
}
inline auto CreateCompositionSurfaceForSwapChain(
winrt::Windows::UI::Composition::Compositor const &compositor,
::IUnknown *swapChain) {
winrt::Windows::UI::Composition::ICompositionSurface surface{nullptr};
auto compositorInterop =
compositor.as<ABI::Windows::UI::Composition::ICompositorInterop>();
winrt::com_ptr<ABI::Windows::UI::Composition::ICompositionSurface>
surfaceInterop;
winrt::check_hresult(compositorInterop->CreateCompositionSurfaceForSwapChain(
swapChain, surfaceInterop.put()));
winrt::check_hresult(surfaceInterop->QueryInterface(
winrt::guid_of<winrt::Windows::UI::Composition::ICompositionSurface>(),
reinterpret_cast<void **>(winrt::put_abi(surface))));
return surface;
}

View File

@@ -0,0 +1,132 @@
#pragma once
#include "composition.interop.h"
struct SurfaceContext {
public:
SurfaceContext(std::nullptr_t) {}
SurfaceContext(
winrt::Windows::UI::Composition::CompositionDrawingSurface surface) {
m_surface = surface;
m_d2dContext = SurfaceBeginDraw(m_surface);
}
~SurfaceContext() {
SurfaceEndDraw(m_surface);
m_d2dContext = nullptr;
m_surface = nullptr;
}
winrt::com_ptr<ID2D1DeviceContext> GetDeviceContext() { return m_d2dContext; }
private:
winrt::com_ptr<ID2D1DeviceContext> m_d2dContext;
winrt::Windows::UI::Composition::CompositionDrawingSurface m_surface{nullptr};
};
struct D3D11DeviceLock {
public:
D3D11DeviceLock(std::nullopt_t) {}
D3D11DeviceLock(ID3D11Multithread *pMultithread) {
m_multithread.copy_from(pMultithread);
m_multithread->Enter();
}
~D3D11DeviceLock() {
m_multithread->Leave();
m_multithread = nullptr;
}
private:
winrt::com_ptr<ID3D11Multithread> m_multithread;
};
inline auto CreateWICFactory() {
winrt::com_ptr<IWICImagingFactory2> wicFactory;
winrt::check_hresult(::CoCreateInstance(
CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
winrt::guid_of<IWICImagingFactory>(), wicFactory.put_void()));
return wicFactory;
}
inline auto CreateD2DDevice(winrt::com_ptr<ID2D1Factory1> const &factory,
winrt::com_ptr<ID3D11Device> const &device) {
winrt::com_ptr<ID2D1Device> result;
winrt::check_hresult(
factory->CreateDevice(device.as<IDXGIDevice>().get(), result.put()));
return result;
}
inline auto CreateD3DDevice(D3D_DRIVER_TYPE const type,
winrt::com_ptr<ID3D11Device> &device) {
WINRT_ASSERT(!device);
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
//#ifdef _DEBUG
// flags |= D3D11_CREATE_DEVICE_DEBUG;
//#endif
return D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, device.put(), nullptr, nullptr);
}
inline auto CreateD3DDevice() {
winrt::com_ptr<ID3D11Device> device;
HRESULT hr = CreateD3DDevice(D3D_DRIVER_TYPE_HARDWARE, device);
if (DXGI_ERROR_UNSUPPORTED == hr) {
hr = CreateD3DDevice(D3D_DRIVER_TYPE_WARP, device);
}
winrt::check_hresult(hr);
return device;
}
inline auto CreateD2DFactory() {
D2D1_FACTORY_OPTIONS options{};
//#ifdef _DEBUG
// options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
//#endif
winrt::com_ptr<ID2D1Factory1> factory;
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
options, factory.put()));
return factory;
}
inline auto CreateDXGISwapChain(winrt::com_ptr<ID3D11Device> const &device,
const DXGI_SWAP_CHAIN_DESC1 *desc) {
auto dxgiDevice = device.as<IDXGIDevice2>();
winrt::com_ptr<IDXGIAdapter> adapter;
winrt::check_hresult(dxgiDevice->GetParent(winrt::guid_of<IDXGIAdapter>(),
adapter.put_void()));
winrt::com_ptr<IDXGIFactory2> factory;
winrt::check_hresult(
adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), factory.put_void()));
winrt::com_ptr<IDXGISwapChain1> swapchain;
winrt::check_hresult(factory->CreateSwapChainForComposition(
device.get(), desc, nullptr, swapchain.put()));
return swapchain;
}
inline auto CreateDXGISwapChain(winrt::com_ptr<ID3D11Device> const &device,
uint32_t width, uint32_t height,
DXGI_FORMAT format, uint32_t bufferCount) {
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Width = width;
desc.Height = height;
desc.Format = format;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferCount = bufferCount;
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
return CreateDXGISwapChain(device, &desc);
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <winrt/windows.graphics.directx.direct3d11.h>
extern "C" {
HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
HRESULT __stdcall CreateDirect3D11SurfaceFromDXGISurface(
::IDXGISurface *dgxiSurface, ::IInspectable **graphicsSurface);
}
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
IDirect3DDxgiInterfaceAccess : ::IUnknown {
virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0;
};
inline auto CreateDirect3DDevice(IDXGIDevice *dxgi_device) {
winrt::com_ptr<::IInspectable> d3d_device;
winrt::check_hresult(
CreateDirect3D11DeviceFromDXGIDevice(dxgi_device, d3d_device.put()));
return d3d_device
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
}
inline auto CreateDirect3DSurface(IDXGISurface *dxgi_surface) {
winrt::com_ptr<::IInspectable> d3d_surface;
winrt::check_hresult(
CreateDirect3D11SurfaceFromDXGISurface(dxgi_surface, d3d_surface.put()));
return d3d_surface
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface>();
}
template <typename T>
auto GetDXGIInterfaceFromObject(
winrt::Windows::Foundation::IInspectable const &object) {
auto access = object.as<IDirect3DDxgiInterfaceAccess>();
winrt::com_ptr<T> result;
winrt::check_hresult(
access->GetInterface(winrt::guid_of<T>(), result.put_void()));
return result;
}

View File

@@ -0,0 +1,159 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE SOFTWARE IS PROVIDED <20>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.
//
//*********************************************************
#include "pch.h"
#include "App.h"
#include "SimpleCapture.h"
#include "Win32MonitorEnumeration.h"
#include "Win32WindowEnumeration.h"
#include <ShObjIdl.h>
using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Composition::Desktop;
// Direct3D11CaptureFramePool requires a DispatcherQueue
auto CreateDispatcherQueueController() {
namespace abi = ABI::Windows::System;
DispatcherQueueOptions options{sizeof(DispatcherQueueOptions),
DQTYPE_THREAD_CURRENT, DQTAT_COM_STA};
Windows::System::DispatcherQueueController controller{nullptr};
check_hresult(CreateDispatcherQueueController(
options, reinterpret_cast<abi::IDispatcherQueueController **>(
put_abi(controller))));
return controller;
}
DesktopWindowTarget CreateDesktopWindowTarget(Compositor const &compositor,
HWND window) {
namespace abi = ABI::Windows::UI::Composition::Desktop;
auto interop = compositor.as<abi::ICompositorDesktopInterop>();
DesktopWindowTarget target{nullptr};
check_hresult(interop->CreateDesktopWindowTarget(
window, true,
reinterpret_cast<abi::IDesktopWindowTarget **>(put_abi(target))));
return target;
}
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance,
LPSTR cmdLine, int cmdShow);
auto g_app = std::make_shared<App>();
auto g_windows = EnumerateWindows();
auto g_monitors = EnumerateMonitors();
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance,
LPSTR cmdLine, int cmdShow) {
// Init COM
init_apartment(apartment_type::single_threaded);
// Create the window
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = instance;
wcex.hIcon = LoadIcon(instance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"ScreenCaptureforHWND";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
WINRT_VERIFY(RegisterClassEx(&wcex));
HWND hwnd = CreateWindow(L"ScreenCaptureforHWND", L"ScreenCaptureforHWND",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
800, 600, NULL, NULL, instance, NULL);
WINRT_VERIFY(hwnd);
ShowWindow(hwnd, cmdShow);
UpdateWindow(hwnd);
// Create combo box
HWND comboBoxHwnd =
CreateWindow(WC_COMBOBOX, L"",
CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_CHILD |
WS_OVERLAPPED | WS_VISIBLE,
10, 10, 200, 200, hwnd, NULL, instance, NULL);
WINRT_VERIFY(comboBoxHwnd);
// Populate combo box
for (auto &window : g_windows) {
SendMessage(comboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)window.Title().c_str());
}
for (auto &monitor : g_monitors) {
SendMessage(comboBoxHwnd, CB_ADDSTRING, 0,
(LPARAM)monitor.ClassName().c_str());
}
// SendMessage(comboBoxHwnd, CB_SETCURSEL, 0, 0);
// Create a DispatcherQueue for our thread
auto controller = CreateDispatcherQueueController();
// Initialize Composition
auto compositor = Compositor();
auto target = CreateDesktopWindowTarget(compositor, hwnd);
auto root = compositor.CreateContainerVisual();
root.RelativeSizeAdjustment({1.0f, 1.0f});
target.Root(root);
// Enqueue our capture work on the dispatcher
auto queue = controller.DispatcherQueue();
auto success = queue.TryEnqueue([=]() -> void { g_app->Initialize(root); });
WINRT_VERIFY(success);
// Message pump
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
if (HIWORD(wParam) == CBN_SELCHANGE) {
auto index = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
if (index < g_windows.size() - 1) {
auto window = g_windows[index];
g_app->StartCapture(window.Hwnd());
} else {
auto monitor = g_monitors[index - g_windows.size()];
g_app->StartCapture(monitor.Hmonitor());
}
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return 0;
}

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,34 @@
#pragma once
#include <Unknwn.h>
#include <inspectable.h>
// WinRT
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.UI.h>
#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Composition.Desktop.h>
#include <winrt/Windows.UI.Popups.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <winrt/Windows.Graphics.DirectX.h>
#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
#include <windows.ui.composition.interop.h>
#include <DispatcherQueue.h>
// STL
#include <atomic>
#include <memory>
// D3D
#include <d3d11_4.h>
#include <dxgi1_6.h>
#include <d2d1_3.h>
#include <wincodec.h>
// Helpers
#include "composition.interop.h"
#include "d3dHelpers.h"
#include "direct3d11.interop.h"
#include "capture.interop.h"