doubango/plugins/pluginWinDD/internals/ThreadManager.cxx

235 lines
7.2 KiB
C++
Executable File

// 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 "ThreadManager.h"
DWORD WINAPI DDProc(_In_ void* Param);
THREADMANAGER::THREADMANAGER() : m_ThreadCount(0),
m_ThreadHandles(nullptr),
m_ThreadData(nullptr)
{
RtlZeroMemory(&m_PtrInfo, sizeof(m_PtrInfo));
}
THREADMANAGER::~THREADMANAGER()
{
Clean();
}
//
// Clean up resources
//
void THREADMANAGER::Clean()
{
if (m_PtrInfo.PtrShapeBuffer) {
delete [] m_PtrInfo.PtrShapeBuffer;
m_PtrInfo.PtrShapeBuffer = nullptr;
}
RtlZeroMemory(&m_PtrInfo, sizeof(m_PtrInfo));
if (m_ThreadHandles) {
for (UINT i = 0; i < m_ThreadCount; ++i) {
if (m_ThreadHandles[i]) {
CloseHandle(m_ThreadHandles[i]);
}
}
delete [] m_ThreadHandles;
m_ThreadHandles = nullptr;
}
if (m_ThreadData) {
for (UINT i = 0; i < m_ThreadCount; ++i) {
CleanDx(&m_ThreadData[i].DxRes);
}
delete [] m_ThreadData;
m_ThreadData = nullptr;
}
m_ThreadCount = 0;
}
//
// Clean up DX_RESOURCES
//
void THREADMANAGER::CleanDx(_Inout_ DX_RESOURCES* Data)
{
if (Data->Device) {
Data->Device->Release();
Data->Device = nullptr;
}
if (Data->Context) {
Data->Context->Release();
Data->Context = nullptr;
}
if (Data->VertexShader) {
Data->VertexShader->Release();
Data->VertexShader = nullptr;
}
if (Data->PixelShader) {
Data->PixelShader->Release();
Data->PixelShader = nullptr;
}
if (Data->InputLayout) {
Data->InputLayout->Release();
Data->InputLayout = nullptr;
}
if (Data->SamplerLinear) {
Data->SamplerLinear->Release();
Data->SamplerLinear = nullptr;
}
}
//
// Start up threads for DDA
//
DUPL_RETURN THREADMANAGER::Initialize(INT SingleOutput, UINT OutputCount, HANDLE UnexpectedErrorEvent, HANDLE ExpectedErrorEvent, HANDLE TerminateThreadsEvent, HANDLE SharedHandle, _In_ const struct tmedia_producer_s* Producer, _In_ RECT* DesktopDim)
{
m_ThreadCount = OutputCount;
m_ThreadHandles = new (std::nothrow) HANDLE[m_ThreadCount];
m_ThreadData = new (std::nothrow) THREAD_DATA[m_ThreadCount];
if (!m_ThreadHandles || !m_ThreadData) {
return ProcessFailure(nullptr, L"Failed to allocate array for threads", L"Error", E_OUTOFMEMORY);
}
// Create appropriate # of threads for duplication
DUPL_RETURN Ret = DUPL_RETURN_SUCCESS;
for (UINT i = 0; i < m_ThreadCount; ++i) {
m_ThreadData[i].UnexpectedErrorEvent = UnexpectedErrorEvent;
m_ThreadData[i].ExpectedErrorEvent = ExpectedErrorEvent;
m_ThreadData[i].TerminateThreadsEvent = TerminateThreadsEvent;
m_ThreadData[i].Output = (SingleOutput < 0) ? i : SingleOutput;
m_ThreadData[i].TexSharedHandle = SharedHandle;
m_ThreadData[i].OffsetX = DesktopDim->left;
m_ThreadData[i].OffsetY = DesktopDim->top;
m_ThreadData[i].PtrInfo = &m_PtrInfo;
m_ThreadData[i].Producer = Producer;
RtlZeroMemory(&m_ThreadData[i].DxRes, sizeof(DX_RESOURCES));
Ret = InitializeDx(&m_ThreadData[i].DxRes);
if (Ret != DUPL_RETURN_SUCCESS) {
return Ret;
}
DWORD ThreadId;
m_ThreadHandles[i] = CreateThread(nullptr, 0, DDProc, &m_ThreadData[i], 0, &ThreadId);
if (m_ThreadHandles[i] == nullptr) {
return ProcessFailure(nullptr, L"Failed to create thread", L"Error", E_FAIL);
}
}
return Ret;
}
//
// Get DX_RESOURCES
//
DUPL_RETURN THREADMANAGER::InitializeDx(_Out_ DX_RESOURCES* Data)
{
HRESULT hr = S_OK;
// Driver types supported
D3D_DRIVER_TYPE DriverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
// Feature levels supported
D3D_FEATURE_LEVEL FeatureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1
};
UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
D3D_FEATURE_LEVEL FeatureLevel;
// Create device
for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex) {
hr = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels, NumFeatureLevels,
D3D11_SDK_VERSION, &Data->Device, &FeatureLevel, &Data->Context);
if (SUCCEEDED(hr)) {
// Device creation success, no need to loop anymore
break;
}
}
if (FAILED(hr)) {
return ProcessFailure(nullptr, L"Failed to create device in InitializeDx", L"Error", hr);
}
// VERTEX shader
UINT Size = ARRAYSIZE(g_VS);
hr = Data->Device->CreateVertexShader(g_VS, Size, nullptr, &Data->VertexShader);
if (FAILED(hr)) {
return ProcessFailure(Data->Device, L"Failed to create vertex shader in InitializeDx", L"Error", hr, SystemTransitionsExpectedErrors);
}
// Input layout
D3D11_INPUT_ELEMENT_DESC Layout[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
UINT NumElements = ARRAYSIZE(Layout);
hr = Data->Device->CreateInputLayout(Layout, NumElements, g_VS, Size, &Data->InputLayout);
if (FAILED(hr)) {
return ProcessFailure(Data->Device, L"Failed to create input layout in InitializeDx", L"Error", hr, SystemTransitionsExpectedErrors);
}
Data->Context->IASetInputLayout(Data->InputLayout);
// Pixel shader
Size = ARRAYSIZE(g_PS);
hr = Data->Device->CreatePixelShader(g_PS, Size, nullptr, &Data->PixelShader);
if (FAILED(hr)) {
return ProcessFailure(Data->Device, L"Failed to create pixel shader in InitializeDx", L"Error", hr, SystemTransitionsExpectedErrors);
}
// Set up sampler
D3D11_SAMPLER_DESC SampDesc;
RtlZeroMemory(&SampDesc, sizeof(SampDesc));
SampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
SampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
SampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
SampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
SampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
SampDesc.MinLOD = 0;
SampDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = Data->Device->CreateSamplerState(&SampDesc, &Data->SamplerLinear);
if (FAILED(hr)) {
return ProcessFailure(Data->Device, L"Failed to create sampler state in InitializeDx", L"Error", hr, SystemTransitionsExpectedErrors);
}
return DUPL_RETURN_SUCCESS;
}
//
// Getter for the PTR_INFO structure
//
PTR_INFO* THREADMANAGER::GetPointerInfo()
{
return &m_PtrInfo;
}
//
// Waits infinitely for all spawned threads to terminate
//
bool THREADMANAGER::WaitForThreadTermination(DWORD timeout /*= INFINITE*/)
{
bool bRet = true;
if (m_ThreadCount != 0) {
bRet = (WaitForMultipleObjectsEx(m_ThreadCount, m_ThreadHandles, TRUE, timeout, FALSE) != WAIT_TIMEOUT);
}
return bRet;
}