Skip to content

Commit

Permalink
Merge branch 'master' into arm64
Browse files Browse the repository at this point in the history
  • Loading branch information
robmikh committed Oct 2, 2019
2 parents efe6a6f + 2f34e9e commit e9cdb79
Show file tree
Hide file tree
Showing 16 changed files with 312 additions and 64 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,4 @@ __pycache__/
*.pyc

Win32CaptureSample/output.png
/Win32CaptureSample/output.jxr
95 changes: 50 additions & 45 deletions Win32CaptureSample/App.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "pch.h"
#include "App.h"
#include "SimpleCapture.h"
#include "CaptureSnapshot.h"

using namespace winrt;
Expand All @@ -10,7 +9,9 @@ using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Popups;
using namespace Windows::Graphics::Capture;
using namespace Windows::Graphics::DirectX;

App::App(ContainerVisual root, GraphicsCapturePicker capturePicker, FileSavePicker savePicker)
{
Expand Down Expand Up @@ -44,9 +45,7 @@ App::App(ContainerVisual root, GraphicsCapturePicker capturePicker, FileSavePick
auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
m_device = CreateDirect3DDevice(dxgiDevice.get());

m_d2dFactory = CreateD2DFactory();
m_d2dDevice = CreateD2DDevice(m_d2dFactory, d3dDevice);
check_hresult(m_d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, m_d2dContext.put()));
m_encoder = std::make_unique<SimpleImageEncoder>(m_device);
}

GraphicsCaptureItem App::StartCaptureFromWindowHandle(HWND hwnd)
Expand Down Expand Up @@ -100,55 +99,50 @@ IAsyncOperation<StorageFile> App::TakeSnapshotAsync()
m_savePicker.DefaultFileExtension(L".png");
m_savePicker.FileTypeChoices().Clear();
m_savePicker.FileTypeChoices().Insert(L"PNG image", single_threaded_vector<hstring>({ L".png" }));
m_savePicker.FileTypeChoices().Insert(L"JPG image", single_threaded_vector<hstring>({ L".jpg" }));
m_savePicker.FileTypeChoices().Insert(L"JXR image", single_threaded_vector<hstring>({ L".jxr" }));
auto file = co_await m_savePicker.PickSaveFileAsync();
if (file == nullptr)
{
co_return nullptr;
}

// Decide on the pixel format depending on the image type
auto fileExtension = file.FileType();
SimpleImageEncoder::SupportedFormats fileFormat;
DirectXPixelFormat pixelFormat;
if (fileExtension == L".png")
{
fileFormat = SimpleImageEncoder::SupportedFormats::Png;
pixelFormat = DirectXPixelFormat::B8G8R8A8UIntNormalized;
}
else if (fileExtension == L".jpg" || fileExtension == L".jpeg")
{
fileFormat = SimpleImageEncoder::SupportedFormats::Jpg;
pixelFormat = DirectXPixelFormat::B8G8R8A8UIntNormalized;
}
else if (fileExtension == L".jxr")
{
fileFormat = SimpleImageEncoder::SupportedFormats::Jxr;
pixelFormat = DirectXPixelFormat::R16G16B16A16Float;
}
else
{
// Unsupported
auto dialog = MessageDialog(L"Unsupported file format!");

co_await dialog.ShowAsync();
co_return nullptr;
}

// Get the file stream
auto randomAccessStream = co_await file.OpenAsync(FileAccessMode::ReadWrite);
auto stream = CreateStreamFromRandomAccessStream(randomAccessStream);
auto stream = co_await file.OpenAsync(FileAccessMode::ReadWrite);

// Take the snapshot
auto frame = co_await CaptureSnapshot::TakeAsync(m_device, item);
auto frameTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame);
D3D11_TEXTURE2D_DESC textureDesc = {};
frameTexture->GetDesc(&textureDesc);
auto dxgiFrameTexture = frameTexture.as<IDXGISurface>();

// Get a D2D bitmap for our snapshot
// TODO: Since this sample doesn't use D2D any other way, it may be better to map
// the pixels manually and hand them to WIC. However, using d2d is easier for now.
com_ptr<ID2D1Bitmap1> d2dBitmap;
check_hresult(m_d2dContext->CreateBitmapFromDxgiSurface(dxgiFrameTexture.get(), nullptr, d2dBitmap.put()));

// Encode the snapshot
// TODO: dpi?
auto dpi = 96.0f;
WICImageParameters params = {};
params.PixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
params.PixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
params.DpiX = dpi;
params.DpiY = dpi;
params.PixelWidth = textureDesc.Width;
params.PixelHeight = textureDesc.Height;

auto wicFactory = CreateWICFactory();
com_ptr<IWICBitmapEncoder> encoder;
check_hresult(wicFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, encoder.put()));
check_hresult(encoder->Initialize(stream.get(), WICBitmapEncoderNoCache));

com_ptr<IWICBitmapFrameEncode> wicFrame;
com_ptr<IPropertyBag2> frameProperties;
check_hresult(encoder->CreateNewFrame(wicFrame.put(), frameProperties.put()));
check_hresult(wicFrame->Initialize(frameProperties.get()));

com_ptr<IWICImageEncoder> imageEncoder;
check_hresult(wicFactory->CreateImageEncoder(m_d2dDevice.get(), imageEncoder.put()));
check_hresult(imageEncoder->WriteFrame(d2dBitmap.get(), wicFrame.get(), &params));
check_hresult(wicFrame->Commit());
check_hresult(encoder->Commit());
auto frame = co_await CaptureSnapshot::TakeAsync(m_device, item, pixelFormat);

// Encode the image
m_encoder->EncodeImage(frame, stream, fileFormat);

co_return file;
}
Expand All @@ -163,7 +157,7 @@ void App::SnapshotCurrentCapture()

void App::StartCaptureFromItem(GraphicsCaptureItem item)
{
m_capture = std::make_unique<SimpleCapture>(m_device, item);
m_capture = std::make_unique<SimpleCapture>(m_device, item, m_pixelFormat);

auto surface = m_capture->CreateSurface(m_compositor);
m_brush.Surface(surface);
Expand All @@ -179,4 +173,15 @@ void App::StopCapture()
m_capture = nullptr;
m_brush.Surface(nullptr);
}
}

void App::PixelFormat(DirectXPixelFormat pixelFormat)
{
m_pixelFormat = pixelFormat;
if (m_capture)
{
auto item = m_capture->CaptureItem();
StopCapture();
StartCaptureFromItem(item);
}
}
8 changes: 5 additions & 3 deletions Win32CaptureSample/App.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "SimpleCapture.h"
#include "SimpleImageEncoder.h"

class App
{
Expand All @@ -14,6 +15,8 @@ class App
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Graphics::Capture::GraphicsCaptureItem> StartCaptureWithPickerAsync();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> TakeSnapshotAsync();
void SnapshotCurrentCapture();
winrt::Windows::Graphics::DirectX::DirectXPixelFormat PixelFormat() { return m_pixelFormat; }
void PixelFormat(winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat);

void StopCapture();

Expand All @@ -32,8 +35,7 @@ class App

winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ nullptr };
std::unique_ptr<SimpleCapture> m_capture{ nullptr };
winrt::Windows::Graphics::DirectX::DirectXPixelFormat m_pixelFormat = winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized;

winrt::com_ptr<ID2D1Factory1> m_d2dFactory;
winrt::com_ptr<ID2D1Device> m_d2dDevice;
winrt::com_ptr<ID2D1DeviceContext> m_d2dContext;
std::unique_ptr<SimpleImageEncoder> m_encoder{ nullptr };
};
4 changes: 2 additions & 2 deletions Win32CaptureSample/CaptureSnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using namespace Windows::UI;
using namespace Windows::UI::Composition;

IAsyncOperation<IDirect3DSurface>
CaptureSnapshot::TakeAsync(IDirect3DDevice const& device, GraphicsCaptureItem const& item)
CaptureSnapshot::TakeAsync(IDirect3DDevice const& device, GraphicsCaptureItem const& item, DirectXPixelFormat const& pixelFormat)
{
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(device);
com_ptr<ID3D11DeviceContext> d3dContext;
Expand All @@ -27,7 +27,7 @@ CaptureSnapshot::TakeAsync(IDirect3DDevice const& device, GraphicsCaptureItem co
// DispatcherQueue requirement.
auto framePool = Direct3D11CaptureFramePool::CreateFreeThreaded(
device,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
pixelFormat,
1,
item.Size());
auto session = framePool.CreateCaptureSession(item);
Expand Down
3 changes: 2 additions & 1 deletion Win32CaptureSample/CaptureSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ class CaptureSnapshot
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface>
TakeAsync(
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item);
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item,
winrt::Windows::Graphics::DirectX::DirectXPixelFormat const& format = winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized);

private:
CaptureSnapshot() = delete;
Expand Down
27 changes: 27 additions & 0 deletions Win32CaptureSample/SampleWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ using namespace Windows::System;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Composition::Desktop;
using namespace Windows::Graphics::DirectX;

const std::wstring SampleWindow::ClassName = L"Win32CaptureSample";

Expand Down Expand Up @@ -42,6 +43,11 @@ SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr<App>
m_app = app;
m_windows = std::make_unique<WindowList>();
m_monitors = std::make_unique<MonitorList>();
m_pixelFormats =
{
{ L"B8G8R8A8UIntNormalized", DirectXPixelFormat::B8G8R8A8UIntNormalized },
{ L"R16G16B16A16Float", DirectXPixelFormat::R16G16B16A16Float }
};

CreateControls(instance);
}
Expand Down Expand Up @@ -84,6 +90,11 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP
SetSubTitle(std::wstring(item.DisplayName()));
SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0);
}
else if (hwnd == m_pixelFormatComboBoxHwnd)
{
auto pixelFormatData = m_pixelFormats[index];
m_app->PixelFormat(pixelFormatData.PixelFormat);
}
}
break;
case BN_CLICKED:
Expand Down Expand Up @@ -193,12 +204,28 @@ void SampleWindow::CreateControls(HINSTANCE instance)
10, 200, 200, 30, m_window, nullptr, instance, nullptr);
WINRT_VERIFY(snapshotButtonHwnd);

// Create pixel format combo box
HWND pixelFormatComboBox = CreateWindowW(WC_COMBOBOX, L"",
CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
10, 240, 200, 200, m_window, nullptr, instance, nullptr);
WINRT_VERIFY(pixelFormatComboBox);

// Populate pixel format combo box
for (auto& pixelFormat : m_pixelFormats)
{
SendMessageW(pixelFormatComboBox, CB_ADDSTRING, 0, (LPARAM)pixelFormat.Name.c_str());
}

// The default pixel format is BGRA8
SendMessageW(pixelFormatComboBox, CB_SETCURSEL, 0, 0);

m_windowComboBoxHwnd = windowComboBoxHwnd;
m_monitorComboBoxHwnd = monitorComboBoxHwnd;
m_pickerButtonHwnd = pickerButtonHwnd;
m_stopButtonHwnd = stopButtonHwnd;
m_currentSnapshotHwnd = currentSnapshotButtonHwnd;
m_snapshotButtonHwnd = snapshotButtonHwnd;
m_pixelFormatComboBoxHwnd = pixelFormatComboBox;
}

void SampleWindow::SetSubTitle(std::wstring const& text)
Expand Down
8 changes: 8 additions & 0 deletions Win32CaptureSample/SampleWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,23 @@ struct SampleWindow : DesktopWindow<SampleWindow>
void StopCapture();
void OnCaptureItemClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&, winrt::Windows::Foundation::IInspectable const&);

struct PixelFormatData
{
std::wstring Name;
winrt::Windows::Graphics::DirectX::DirectXPixelFormat PixelFormat;
};

private:
HWND m_windowComboBoxHwnd = nullptr;
HWND m_monitorComboBoxHwnd = nullptr;
HWND m_pickerButtonHwnd = nullptr;
HWND m_stopButtonHwnd = nullptr;
HWND m_currentSnapshotHwnd = nullptr;
HWND m_snapshotButtonHwnd = nullptr;
HWND m_pixelFormatComboBoxHwnd = nullptr;
std::unique_ptr<WindowList> m_windows;
std::unique_ptr<MonitorList> m_monitors;
std::vector<PixelFormatData> m_pixelFormats;
std::shared_ptr<App> m_app;
winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker m_itemClosedRevoker;
};
25 changes: 17 additions & 8 deletions Win32CaptureSample/SimpleCapture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@ namespace winrt
using namespace Windows::UI::Composition;
}

SimpleCapture::SimpleCapture(winrt::IDirect3DDevice const& device, winrt::GraphicsCaptureItem const& item)
SimpleCapture::SimpleCapture(winrt::IDirect3DDevice const& device, winrt::GraphicsCaptureItem const& item, winrt::DirectXPixelFormat pixelFormat)
{
m_item = item;
m_device = device;
m_pixelFormat = pixelFormat;

auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
d3dDevice->GetImmediateContext(m_d3dContext.put());

m_swapChain = CreateDXGISwapChain(d3dDevice, static_cast<uint32_t>(m_item.Size().Width), static_cast<uint32_t>(m_item.Size().Height),
DXGI_FORMAT_B8G8R8A8_UNORM, 2);
static_cast<DXGI_FORMAT>(m_pixelFormat), 2);

// Creating our frame pool with 'Create' instead of 'CreateFreeThreaded'
// means that the frame pool's FrameArrived event is called on the thread
// the frame pool was created on. This also means that the creating thread
// must have a DispatcherQueue. If you use this method, it's best not to do
// it on the UI thread.
m_framePool = winrt::Direct3D11CaptureFramePool::Create(m_device, winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, m_item.Size());
m_framePool = winrt::Direct3D11CaptureFramePool::Create(m_device, m_pixelFormat, 2, m_item.Size());
m_session = m_framePool.CreateCaptureSession(m_item);
m_lastSize = m_item.Size();
m_framePool.FrameArrived({ this, &SimpleCapture::OnFrameArrived });
Expand Down Expand Up @@ -74,8 +75,8 @@ bool SimpleCapture::TryResizeSwapChain(winrt::Direct3D11CaptureFrame const& fram
{
// The thing we have been capturing has changed size, resize the swap chain to match.
m_lastSize = contentSize;
m_swapChain->ResizeBuffers(2, static_cast<uint32_t>(m_lastSize.Width), static_cast<uint32_t>(m_lastSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM, 0);
winrt::check_hresult(m_swapChain->ResizeBuffers(2, static_cast<uint32_t>(m_lastSize.Width), static_cast<uint32_t>(m_lastSize.Height),
static_cast<DXGI_FORMAT>(m_pixelFormat), 0));
return true;
}
return false;
Expand Down Expand Up @@ -107,7 +108,7 @@ void SimpleCapture::OnFrameArrived(winrt::Direct3D11CaptureFramePool const& send

if (swapChainResizedToFrame)
{
m_framePool.Recreate(m_device, winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, m_lastSize);
m_framePool.Recreate(m_device, m_pixelFormat, 2, m_lastSize);
}
}

Expand All @@ -117,6 +118,14 @@ void SimpleCapture::TakeSnapshot(winrt::com_ptr<ID3D11Texture2D> const& frame)
winrt::check_hresult(DirectX::CaptureTexture(GetDXGIInterfaceFromObject<ID3D11Device>(m_device).get(),
m_d3dContext.get(), frame.get(), im));
const auto& realImage = *im.GetImage(0, 0, 0);
winrt::check_hresult(DirectX::SaveToWICFile(realImage, DirectX::WIC_FLAGS_NONE,
GUID_ContainerFormatPng, L"output.png"));
if (m_pixelFormat == winrt::DirectXPixelFormat::R16G16B16A16Float)
{
winrt::check_hresult(DirectX::SaveToWICFile(realImage, DirectX::WIC_FLAGS_NONE,
GUID_ContainerFormatWmp, L"output.jxr"));
}
else // BGRA8
{
winrt::check_hresult(DirectX::SaveToWICFile(realImage, DirectX::WIC_FLAGS_NONE,
GUID_ContainerFormatPng, L"output.png"));
}
}
5 changes: 4 additions & 1 deletion Win32CaptureSample/SimpleCapture.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ class SimpleCapture
public:
SimpleCapture(
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item);
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item,
winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat);
~SimpleCapture() { Close(); }

void StartCapture();
winrt::Windows::UI::Composition::ICompositionSurface CreateSurface(
winrt::Windows::UI::Composition::Compositor const& compositor);

void SaveNextFrame() { m_captureNextImage = true; }
winrt::Windows::Graphics::Capture::GraphicsCaptureItem CaptureItem() { return m_item; }

void Close();

Expand Down Expand Up @@ -41,6 +43,7 @@ class SimpleCapture
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ nullptr };
winrt::com_ptr<IDXGISwapChain1> m_swapChain{ nullptr };
winrt::com_ptr<ID3D11DeviceContext> m_d3dContext{ nullptr };
winrt::Windows::Graphics::DirectX::DirectXPixelFormat m_pixelFormat;

std::atomic<bool> m_closed = false;
std::atomic<bool> m_captureNextImage = false;
Expand Down
Loading

0 comments on commit e9cdb79

Please sign in to comment.