call AcquireNextFrame on isolated thread
This commit is contained in:
@@ -45,6 +45,10 @@ public class DisplacementMapping : MonoBehaviour
|
|||||||
case TargetMonitor.Next: ++id; break;
|
case TargetMonitor.Next: ++id; break;
|
||||||
case TargetMonitor.Prev: --id; break;
|
case TargetMonitor.Prev: --id; break;
|
||||||
}
|
}
|
||||||
|
if (uDesktopDuplication.Manager.monitorCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
id = Mathf.Clamp(id, 0, uDesktopDuplication.Manager.monitorCount - 1);
|
id = Mathf.Clamp(id, 0, uDesktopDuplication.Manager.monitorCount - 1);
|
||||||
var monitor = uDesktopDuplication.Manager.GetMonitor(id);
|
var monitor = uDesktopDuplication.Manager.GetMonitor(id);
|
||||||
monitor.shouldBeUpdated = true;
|
monitor.shouldBeUpdated = true;
|
||||||
|
|||||||
Binary file not shown.
@@ -86,7 +86,7 @@ public static class Lib
|
|||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern void Finalize();
|
public static extern void Finalize();
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern void Reinitialize();
|
public static extern void Reinitialize(bool useThread);
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern void Update();
|
public static extern void Update();
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ public class Manager : MonoBehaviour
|
|||||||
|
|
||||||
[SerializeField] int desktopDuplicationApiTimeout = 0;
|
[SerializeField] int desktopDuplicationApiTimeout = 0;
|
||||||
[SerializeField] float retryReinitializationDuration = 1f;
|
[SerializeField] float retryReinitializationDuration = 1f;
|
||||||
|
[SerializeField]
|
||||||
|
bool useThread = false;
|
||||||
|
|
||||||
private Coroutine renderCoroutine_ = null;
|
private Coroutine renderCoroutine_ = null;
|
||||||
private bool shouldReinitialize_ = false;
|
private bool shouldReinitialize_ = false;
|
||||||
@@ -143,7 +145,7 @@ public class Manager : MonoBehaviour
|
|||||||
public void Reinitialize()
|
public void Reinitialize()
|
||||||
{
|
{
|
||||||
Debug.Log("[uDD] Reinitialize");
|
Debug.Log("[uDD] Reinitialize");
|
||||||
Lib.Reinitialize();
|
Lib.Reinitialize(useThread);
|
||||||
CreateMonitors();
|
CreateMonitors();
|
||||||
if (onReinitialized != null) {
|
if (onReinitialized != null) {
|
||||||
onReinitialized();
|
onReinitialized();
|
||||||
|
|||||||
@@ -11,16 +11,23 @@ using namespace Microsoft::WRL;
|
|||||||
Monitor::Monitor(int id)
|
Monitor::Monitor(int id)
|
||||||
: id_(id)
|
: id_(id)
|
||||||
{
|
{
|
||||||
|
ZeroMemory(&monitorInfo_, sizeof(monitorInfo_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Monitor::~Monitor()
|
Monitor::~Monitor()
|
||||||
{
|
{
|
||||||
|
m_stopLoop = true;
|
||||||
|
|
||||||
if (deskDupl_)
|
if (deskDupl_)
|
||||||
{
|
{
|
||||||
deskDupl_->Release();
|
deskDupl_->Release();
|
||||||
deskDupl_ = nullptr;
|
deskDupl_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_desktopDuplicationThread.joinable()) {
|
||||||
|
m_desktopDuplicationThread.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
enum class MonitorState
|
enum class MonitorState
|
||||||
@@ -23,6 +24,8 @@ enum class MonitorState
|
|||||||
|
|
||||||
class Monitor
|
class Monitor
|
||||||
{
|
{
|
||||||
|
class ThreadedDesktopDuplicator *m_threaded = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using State = MonitorState;
|
using State = MonitorState;
|
||||||
|
|
||||||
@@ -57,6 +60,19 @@ public:
|
|||||||
bool UseGetPixels() const;
|
bool UseGetPixels() const;
|
||||||
bool GetPixels(BYTE* output, int x, int y, int width, int height);
|
bool GetPixels(BYTE* output, int x, int y, int width, int height);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void InitializeThreaded(const Microsoft::WRL::ComPtr<struct IDXGIAdapter> &adapter
|
||||||
|
, bool isUnityDeviceAdapter
|
||||||
|
, const Microsoft::WRL::ComPtr<struct IDXGIOutput> &output);
|
||||||
|
void CopyTextureFromThread();
|
||||||
|
private:
|
||||||
|
void DuplicateAndCopyLoop();
|
||||||
|
void DuplicateAndMapLoop();
|
||||||
|
std::shared_ptr<class IsolatedD3D11Device> m_pIsolated;
|
||||||
|
std::thread m_desktopDuplicationThread;
|
||||||
|
volatile bool m_stopLoop = false;
|
||||||
|
std::shared_ptr<class TextureQueue> m_textureQueue;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
void UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||||
void UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
void UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||||
@@ -79,4 +95,4 @@ private:
|
|||||||
Buffer<BYTE> bufferForGetPixels_;
|
Buffer<BYTE> bufferForGetPixels_;
|
||||||
UINT moveRectSize_ = 0;
|
UINT moveRectSize_ = 0;
|
||||||
UINT dirtyRectSize_ = 0;;
|
UINT dirtyRectSize_ = 0;;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
using namespace Microsoft::WRL;
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
|
|
||||||
MonitorManager::MonitorManager()
|
MonitorManager::MonitorManager(LUID unityAdapterLuid)
|
||||||
|
: unityAdapterLuid_(unityAdapterLuid)
|
||||||
{
|
{
|
||||||
Initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ MonitorManager::~MonitorManager()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MonitorManager::Initialize()
|
void MonitorManager::Initialize(LUID unityAdapterLuid, bool useThread)
|
||||||
{
|
{
|
||||||
Finalize();
|
Finalize();
|
||||||
|
|
||||||
@@ -46,12 +46,23 @@ void MonitorManager::Initialize()
|
|||||||
ComPtr<IDXGIAdapter1> adapter;
|
ComPtr<IDXGIAdapter1> adapter;
|
||||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||||
{
|
{
|
||||||
|
DXGI_ADAPTER_DESC desc;
|
||||||
|
adapter->GetDesc(&desc);
|
||||||
|
|
||||||
// Search the main monitor from all outputs
|
// Search the main monitor from all outputs
|
||||||
ComPtr<IDXGIOutput> output;
|
ComPtr<IDXGIOutput> output;
|
||||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||||
{
|
{
|
||||||
auto monitor = std::make_shared<Monitor>(id++);
|
auto monitor = std::make_shared<Monitor>(id++);
|
||||||
monitor->Initialize(output.Get());
|
if (useThread) {
|
||||||
|
monitor->InitializeThreaded(adapter
|
||||||
|
, desc.AdapterLuid.HighPart == unityAdapterLuid.HighPart
|
||||||
|
&& desc.AdapterLuid.LowPart == unityAdapterLuid.LowPart
|
||||||
|
, output);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
monitor->Initialize(output.Get());
|
||||||
|
}
|
||||||
monitors_.push_back(monitor);
|
monitors_.push_back(monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,8 +81,9 @@ void MonitorManager::RequireReinitilization()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MonitorManager::Reinitialize()
|
void MonitorManager::Reinitialize(bool useThread)
|
||||||
{
|
{
|
||||||
|
useThread_ = useThread;
|
||||||
Debug::Log("MonitorManager::Reinitialize()");
|
Debug::Log("MonitorManager::Reinitialize()");
|
||||||
Initialize();
|
Initialize();
|
||||||
SendMessageToUnity(Message::Reinitialized);
|
SendMessageToUnity(Message::Reinitialized);
|
||||||
@@ -104,6 +116,9 @@ bool MonitorManager::HasMonitorCountChanged() const
|
|||||||
|
|
||||||
std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
|
std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
|
||||||
{
|
{
|
||||||
|
if(monitors_.empty()) {
|
||||||
|
const_cast<MonitorManager*>(this)->Initialize();
|
||||||
|
}
|
||||||
if (id >= 0 && id < static_cast<int>(monitors_.size()))
|
if (id >= 0 && id < static_cast<int>(monitors_.size()))
|
||||||
{
|
{
|
||||||
return monitors_[id];
|
return monitors_[id];
|
||||||
@@ -122,7 +137,7 @@ void MonitorManager::Update()
|
|||||||
{
|
{
|
||||||
if (isReinitializationRequired_)
|
if (isReinitializationRequired_)
|
||||||
{
|
{
|
||||||
Reinitialize();
|
Reinitialize(useThread_);
|
||||||
isReinitializationRequired_ = false;
|
isReinitializationRequired_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,6 +157,9 @@ int MonitorManager::GetTimeout() const
|
|||||||
|
|
||||||
int MonitorManager::GetMonitorCount() const
|
int MonitorManager::GetMonitorCount() const
|
||||||
{
|
{
|
||||||
|
if (monitors_.empty()) {
|
||||||
|
const_cast<MonitorManager*>(this)->Initialize();
|
||||||
|
}
|
||||||
return static_cast<int>(monitors_.size());
|
return static_cast<int>(monitors_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,4 +189,4 @@ int MonitorManager::GetTotalHeight() const
|
|||||||
const auto minTop = *std::min_element(tops.begin(), tops.end());
|
const auto minTop = *std::min_element(tops.begin(), tops.end());
|
||||||
const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end());
|
const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end());
|
||||||
return maxBottom - minTop;
|
return maxBottom - minTop;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ class Cursor;
|
|||||||
class MonitorManager
|
class MonitorManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MonitorManager();
|
explicit MonitorManager(LUID unityAdapterLuid_);
|
||||||
~MonitorManager();
|
~MonitorManager();
|
||||||
void Reinitialize();
|
void Reinitialize(bool useThread);
|
||||||
bool HasMonitorCountChanged() const;
|
bool HasMonitorCountChanged() const;
|
||||||
void RequireReinitilization();
|
void RequireReinitilization();
|
||||||
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
|
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
|
||||||
@@ -24,7 +24,8 @@ public:
|
|||||||
std::shared_ptr<Cursor> GetCursor() const;
|
std::shared_ptr<Cursor> GetCursor() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Initialize();
|
void Initialize(){ Initialize(unityAdapterLuid_, useThread_); }
|
||||||
|
void Initialize(LUID unityAdapterLuid, bool useThread);
|
||||||
void Finalize();
|
void Finalize();
|
||||||
|
|
||||||
// Setters from Unity
|
// Setters from Unity
|
||||||
@@ -38,12 +39,16 @@ public:
|
|||||||
int GetMonitorCount() const;
|
int GetMonitorCount() const;
|
||||||
int GetTotalWidth() const;
|
int GetTotalWidth() const;
|
||||||
int GetTotalHeight() const;
|
int GetTotalHeight() const;
|
||||||
|
bool UseThread()const { return useThread_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
LUID unityAdapterLuid_;
|
||||||
|
bool useThread_ = false;
|
||||||
|
|
||||||
int timeout_ = 10;
|
int timeout_ = 10;
|
||||||
bool enableTextureCopyFromGpuToCpu_ = false;
|
bool enableTextureCopyFromGpuToCpu_ = false;
|
||||||
std::vector<std::shared_ptr<Monitor>> monitors_;
|
std::vector<std::shared_ptr<Monitor>> monitors_;
|
||||||
std::shared_ptr<Cursor> cursor_ = std::make_shared<Cursor>();
|
std::shared_ptr<Cursor> cursor_ = std::make_shared<Cursor>();
|
||||||
int cursorMonitorId_ = -1;
|
int cursorMonitorId_ = -1;
|
||||||
bool isReinitializationRequired_ = false;
|
bool isReinitializationRequired_ = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,386 @@
|
|||||||
|
#include "Monitor.h"
|
||||||
|
#include "MonitorManager.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include <ShellScalingApi.h>
|
||||||
|
#include <queue>
|
||||||
|
#pragma comment(lib, "d3d11.lib")
|
||||||
|
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Thraed safe self created ID3D11Device from specified adapter
|
||||||
|
///
|
||||||
|
class IsolatedD3D11Device
|
||||||
|
{
|
||||||
|
ComPtr<ID3D11Device> m_device;
|
||||||
|
ComPtr<ID3D11Texture2D> m_copyTarget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ComPtr<ID3D11Device> GetDevice()const { return m_device; }
|
||||||
|
|
||||||
|
bool CreateDevice(const ComPtr<IDXGIAdapter> &adapter)
|
||||||
|
{
|
||||||
|
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT // D2D Compatible
|
||||||
|
//| D3D11_CREATE_DEVICE_SINGLETHREADED
|
||||||
|
//| D3D11_CREATE_DEVICE_VIDEO_SUPPORT // MediaFoundation
|
||||||
|
;
|
||||||
|
|
||||||
|
D3D_FEATURE_LEVEL FeatureLevelsRequested[6] = {
|
||||||
|
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
|
||||||
|
D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3,
|
||||||
|
D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 };
|
||||||
|
|
||||||
|
UINT numLevelsRequested = sizeof(FeatureLevelsRequested) / sizeof(D3D_FEATURE_LEVEL);
|
||||||
|
D3D_FEATURE_LEVEL FeatureLevelsSupported;
|
||||||
|
|
||||||
|
if (FAILED(D3D11CreateDevice(adapter.Get()
|
||||||
|
, adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr
|
||||||
|
, flags
|
||||||
|
, FeatureLevelsRequested, numLevelsRequested
|
||||||
|
, D3D11_SDK_VERSION
|
||||||
|
, &m_device
|
||||||
|
, &FeatureLevelsSupported
|
||||||
|
, nullptr
|
||||||
|
))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<ID3D11Texture2D> CreateCopyTargetWithSharedFlag(const ComPtr<ID3D11Texture2D> &src)
|
||||||
|
{
|
||||||
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
src->GetDesc(&desc);
|
||||||
|
|
||||||
|
if (m_copyTarget) {
|
||||||
|
D3D11_TEXTURE2D_DESC target_desc;
|
||||||
|
m_copyTarget->GetDesc(&target_desc);
|
||||||
|
if (
|
||||||
|
target_desc.Format == desc.Format
|
||||||
|
&& target_desc.Width == desc.Width
|
||||||
|
&& target_desc.Height == desc.Height
|
||||||
|
) {
|
||||||
|
// already created
|
||||||
|
return m_copyTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; // for share texture with unity device
|
||||||
|
|
||||||
|
if (FAILED(m_device->CreateTexture2D(&desc, NULL, &m_copyTarget)))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return m_copyTarget;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// RAII helper
|
||||||
|
class ReleaseGuard
|
||||||
|
{
|
||||||
|
ComPtr<IDXGIOutputDuplication> m_dd;
|
||||||
|
|
||||||
|
ReleaseGuard(const ReleaseGuard &)=delete;
|
||||||
|
ReleaseGuard& operator=(const ReleaseGuard &)=delete;
|
||||||
|
public:
|
||||||
|
ReleaseGuard(const ComPtr<IDXGIOutputDuplication> &dd)
|
||||||
|
: m_dd(dd)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~ReleaseGuard()
|
||||||
|
{
|
||||||
|
m_dd->ReleaseFrame();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct QueueItem
|
||||||
|
{
|
||||||
|
ComPtr<ID3D11Texture2D> Texture;
|
||||||
|
DXGI_OUTDUPL_FRAME_INFO Info;
|
||||||
|
|
||||||
|
QueueItem()
|
||||||
|
{}
|
||||||
|
|
||||||
|
QueueItem(const ComPtr<ID3D11Texture2D> &texture
|
||||||
|
, const DXGI_OUTDUPL_FRAME_INFO &info
|
||||||
|
)
|
||||||
|
: Texture(texture), Info(info)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
class TextureQueue
|
||||||
|
{
|
||||||
|
std::queue<QueueItem> m_queue;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Enqueue(const QueueItem &item)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(m_mutex);
|
||||||
|
m_queue.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueItem Dequeue()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(m_mutex);
|
||||||
|
if (m_queue.empty()) {
|
||||||
|
return QueueItem();
|
||||||
|
}
|
||||||
|
auto front = m_queue.front();
|
||||||
|
m_queue.pop();
|
||||||
|
return front;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Monitor::InitializeThreaded(
|
||||||
|
const ComPtr<IDXGIAdapter> &adapter
|
||||||
|
, bool isUnityDeviceAdapter
|
||||||
|
, const ComPtr<IDXGIOutput> &output
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_pIsolated = std::make_shared<IsolatedD3D11Device>();
|
||||||
|
m_textureQueue = std::make_shared<TextureQueue>();
|
||||||
|
|
||||||
|
if (!m_pIsolated->CreateDevice(adapter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(output->GetDesc(&outputDesc_)))
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
|
||||||
|
if (!GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_))
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Initialize() => GetMonitorInfo() failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto rect = monitorInfo_.rcMonitor;
|
||||||
|
width_ = rect.right - rect.left;
|
||||||
|
height_ = rect.bottom - rect.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_)))
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Initialize() => GetDpiForMonitor() failed.");
|
||||||
|
// DPI is set as -1, so the application has to use the appropriate value.
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<IDXGIOutput1> output1;
|
||||||
|
if (FAILED(output.As(&output1))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use self created device
|
||||||
|
auto hr = output1->DuplicateOutput(m_pIsolated->GetDevice().Get(), &deskDupl_);
|
||||||
|
switch (hr)
|
||||||
|
{
|
||||||
|
case S_OK:
|
||||||
|
{
|
||||||
|
state_ = State::Available;
|
||||||
|
const auto rot = static_cast<DXGI_MODE_ROTATION>(GetRotation());
|
||||||
|
Debug::Log("Monitor::Initialize() => OK.");
|
||||||
|
Debug::Log(" ID : ", GetId());
|
||||||
|
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
|
||||||
|
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
|
||||||
|
Debug::Log(" Rot : ",
|
||||||
|
rot == DXGI_MODE_ROTATION_IDENTITY ? "Landscape" :
|
||||||
|
rot == DXGI_MODE_ROTATION_ROTATE90 ? "Portrait" :
|
||||||
|
rot == DXGI_MODE_ROTATION_ROTATE180 ? "Landscape (flipped)" :
|
||||||
|
rot == DXGI_MODE_ROTATION_ROTATE270 ? "Portrait (flipped)" :
|
||||||
|
"Unspecified");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case E_INVALIDARG:
|
||||||
|
{
|
||||||
|
state_ = State::InvalidArg;
|
||||||
|
Debug::Error("Monitor::Initialize() => Invalid arguments.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case E_ACCESSDENIED:
|
||||||
|
{
|
||||||
|
// For example, when the user presses Ctrl + Alt + Delete and the screen
|
||||||
|
// switches to admin screen, this error occurs.
|
||||||
|
state_ = State::AccessDenied;
|
||||||
|
Debug::Error("Monitor::Initialize() => Access denied.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_UNSUPPORTED:
|
||||||
|
{
|
||||||
|
// If the display adapter on the computer is running under the Microsoft Hybrid system,
|
||||||
|
// this error occurs.
|
||||||
|
state_ = State::Unsupported;
|
||||||
|
Debug::Error("Monitor::Initialize() => Unsupported display.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
|
||||||
|
{
|
||||||
|
// When other application use Desktop Duplication API, this error occurs.
|
||||||
|
state_ = State::CurrentlyNotAvailable;
|
||||||
|
Debug::Error("Monitor::Initialize() => Currently not available.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_SESSION_DISCONNECTED:
|
||||||
|
{
|
||||||
|
state_ = State::SessionDisconnected;
|
||||||
|
Debug::Error("Monitor::Initialize() => Session disconnected.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state_ = State::Unknown;
|
||||||
|
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start desktop duplication thread
|
||||||
|
m_stopLoop = false;
|
||||||
|
if (isUnityDeviceAdapter) {
|
||||||
|
m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndCopyLoop, this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndMapLoop, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::CopyTextureFromThread()
|
||||||
|
{
|
||||||
|
QueueItem item;
|
||||||
|
if (m_textureQueue) {
|
||||||
|
item=m_textureQueue->Dequeue();
|
||||||
|
}
|
||||||
|
auto texture = item.Texture;
|
||||||
|
if (!texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &frameInfo = item.Info;
|
||||||
|
|
||||||
|
// Get texture
|
||||||
|
if (unityTexture_)
|
||||||
|
{
|
||||||
|
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||||
|
texture->GetDesc(&srcDesc);
|
||||||
|
unityTexture_->GetDesc(&dstDesc);
|
||||||
|
if (srcDesc.Width != dstDesc.Width ||
|
||||||
|
srcDesc.Height != dstDesc.Height)
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
||||||
|
Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")");
|
||||||
|
Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")");
|
||||||
|
//Debug::Log(" => Try modifying width/height using reported value from DDA.");
|
||||||
|
//width_ = srcDesc.Width;
|
||||||
|
//height_ = srcDesc.Height;
|
||||||
|
state_ = MonitorState::TextureSizeInconsistent;
|
||||||
|
//SendMessageToUnity(Message::TextureSizeChanged);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ComPtr<ID3D11DeviceContext> context;
|
||||||
|
GetDevice()->GetImmediateContext(&context);
|
||||||
|
context->CopyResource(unityTexture_, texture.Get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateMetadata(frameInfo);
|
||||||
|
|
||||||
|
if (frameInfo.PointerPosition.Visible)
|
||||||
|
{
|
||||||
|
GetMonitorManager()->SetCursorMonitorId(id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetMonitorManager()->GetCursorMonitorId() == id_)
|
||||||
|
{
|
||||||
|
UpdateCursor(frameInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UseGetPixels())
|
||||||
|
{
|
||||||
|
CopyTextureFromGpuToCpu(texture.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
hasBeenUpdated_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::DuplicateAndCopyLoop()
|
||||||
|
{
|
||||||
|
if (!deskDupl_)return;
|
||||||
|
|
||||||
|
while (!m_stopLoop)
|
||||||
|
{
|
||||||
|
ComPtr<IDXGIResource> resource;
|
||||||
|
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||||
|
auto hr = deskDupl_->AcquireNextFrame(INFINITE, &frameInfo, &resource);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
switch (hr)
|
||||||
|
{
|
||||||
|
case DXGI_ERROR_ACCESS_LOST:
|
||||||
|
{
|
||||||
|
// If any monitor setting has changed (e.g. monitor size has changed),
|
||||||
|
// it is necessary to re-initialize monitors.
|
||||||
|
//Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
||||||
|
state_ = State::AccessLost;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_WAIT_TIMEOUT:
|
||||||
|
{
|
||||||
|
// This often occurs when timeout value is small and it is not problem.
|
||||||
|
// Debug::Log("Monitor::Render() => DXGI_ERROR_WAIT_TIMEOUT.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_INVALID_CALL:
|
||||||
|
{
|
||||||
|
//Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case E_INVALIDARG:
|
||||||
|
{
|
||||||
|
//Debug::Error("Monitor::Render() => E_INVALIDARG.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state_ = State::Unknown;
|
||||||
|
//Debug::Error("Monitor::Render() => Unknown Error.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReleaseGuard guard(deskDupl_);
|
||||||
|
|
||||||
|
ComPtr<ID3D11Texture2D> texture;
|
||||||
|
if (FAILED(resource.As(&texture))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy target
|
||||||
|
auto copyTarget = m_pIsolated->CreateCopyTargetWithSharedFlag(texture);
|
||||||
|
if (!copyTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy
|
||||||
|
ComPtr<ID3D11DeviceContext> context;
|
||||||
|
m_pIsolated->GetDevice()->GetImmediateContext(&context);
|
||||||
|
context->CopyResource(copyTarget.Get(), texture.Get());
|
||||||
|
|
||||||
|
m_textureQueue->Enqueue(QueueItem(copyTarget, frameInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::DuplicateAndMapLoop()
|
||||||
|
{
|
||||||
|
// not implemented;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "IUnityInterface.h"
|
#include "IUnityInterface.h"
|
||||||
#include "IUnityGraphics.h"
|
#include "IUnityGraphics.h"
|
||||||
|
#include "include/IUnityGraphicsD3D11.h"
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
@@ -36,7 +37,25 @@ extern "C"
|
|||||||
if (g_unity && !g_manager)
|
if (g_unity && !g_manager)
|
||||||
{
|
{
|
||||||
Debug::Initialize();
|
Debug::Initialize();
|
||||||
g_manager = std::make_unique<MonitorManager>();
|
|
||||||
|
auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
|
||||||
|
if (FAILED(device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))){
|
||||||
|
Debug::Error("fatal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||||
|
if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter))) {
|
||||||
|
Debug::Error("fatal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DXGI_ADAPTER_DESC desc;
|
||||||
|
dxgiAdapter->GetDesc(&desc);
|
||||||
|
|
||||||
|
g_manager = std::make_unique<MonitorManager>(desc.AdapterLuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +106,12 @@ extern "C"
|
|||||||
if (!g_manager) return;
|
if (!g_manager) return;
|
||||||
if (auto monitor = g_manager->GetMonitor(id))
|
if (auto monitor = g_manager->GetMonitor(id))
|
||||||
{
|
{
|
||||||
monitor->Render(g_manager->GetTimeout());
|
if (g_manager->UseThread()) {
|
||||||
|
monitor->CopyTextureFromThread();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
monitor->Render(g_manager->GetTimeout());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,10 +120,10 @@ extern "C"
|
|||||||
return OnRenderEvent;
|
return OnRenderEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Reinitialize()
|
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Reinitialize(int useThread)
|
||||||
{
|
{
|
||||||
if (!g_manager) return;
|
if (!g_manager) return;
|
||||||
return g_manager->Reinitialize();
|
return g_manager->Reinitialize(useThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update()
|
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update()
|
||||||
|
|||||||
@@ -90,7 +90,8 @@
|
|||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"
|
||||||
|
copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName).pdb" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
@@ -144,6 +145,7 @@
|
|||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="Monitor.cpp" />
|
<ClCompile Include="Monitor.cpp" />
|
||||||
<ClCompile Include="Cursor.cpp" />
|
<ClCompile Include="Cursor.cpp" />
|
||||||
|
<ClCompile Include="ThreadedDesktopDuplicator.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Common.h" />
|
<ClInclude Include="Common.h" />
|
||||||
|
|||||||
@@ -28,5 +28,6 @@
|
|||||||
<ClCompile Include="MonitorManager.cpp" />
|
<ClCompile Include="MonitorManager.cpp" />
|
||||||
<ClCompile Include="Common.cpp" />
|
<ClCompile Include="Common.cpp" />
|
||||||
<ClCompile Include="Debug.cpp" />
|
<ClCompile Include="Debug.cpp" />
|
||||||
|
<ClCompile Include="ThreadedDesktopDuplicator.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user