add Duplicator class to modularize duplication function #10
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
using UnityEngine.Assertions;
|
using UnityEngine.Assertions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
|
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
|
||||||
using MonitorState = uDesktopDuplication.MonitorState;
|
using DuplicatorState = uDesktopDuplication.DuplicatorState;
|
||||||
|
|
||||||
public class MultipleMonitorCreator : MonoBehaviour
|
public class MultipleMonitorCreator : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -92,11 +92,11 @@ public class MultipleMonitorCreator : MonoBehaviour
|
|||||||
if (removeWaitTimer_ > removeWaitDuration) {
|
if (removeWaitTimer_ > removeWaitDuration) {
|
||||||
hasMonitorUnsupportStateChecked_ = true;
|
hasMonitorUnsupportStateChecked_ = true;
|
||||||
foreach (var info in monitors) {
|
foreach (var info in monitors) {
|
||||||
if (info.uddTexture.monitor.state == MonitorState.Unsupported) {
|
if (info.uddTexture.monitor.state == DuplicatorState.Unsupported) {
|
||||||
Destroy(info.gameObject);
|
Destroy(info.gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
monitors.RemoveAll(info => info.uddTexture.monitor.state == MonitorState.Unsupported);
|
monitors.RemoveAll(info => info.uddTexture.monitor.state == DuplicatorState.Unsupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -32,17 +32,18 @@ public enum MonitorRotation
|
|||||||
Rotate270 = 4
|
Rotate270 = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MonitorState
|
public enum DuplicatorState
|
||||||
{
|
{
|
||||||
NotSet = -1,
|
NotSet = -1,
|
||||||
Available = 0,
|
Ready = 0,
|
||||||
InvalidArg = 1,
|
Running = 1,
|
||||||
AccessDenied = 2,
|
InvalidArg = 2,
|
||||||
Unsupported = 3,
|
AccessDenied = 3,
|
||||||
CurrentlyNotAvailable = 4,
|
Unsupported = 4,
|
||||||
SessionDisconnected = 5,
|
CurrentlyNotAvailable = 5,
|
||||||
AccessLost = 6,
|
SessionDisconnected = 6,
|
||||||
TextureSizeInconsistent = 7,
|
AccessLost = 7,
|
||||||
|
TextureSizeInconsistent = 8,
|
||||||
Unknown = 999,
|
Unknown = 999,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ public static class Lib
|
|||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern int GetId(int id);
|
public static extern int GetId(int id);
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern MonitorState GetState(int id);
|
public static extern DuplicatorState GetState(int id);
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
public static extern void GetName(int id, StringBuilder buf, int len);
|
public static extern void GetName(int id, StringBuilder buf, int len);
|
||||||
[DllImport("uDesktopDuplication")]
|
[DllImport("uDesktopDuplication")]
|
||||||
|
|||||||
@@ -160,11 +160,11 @@ public class Manager : MonoBehaviour
|
|||||||
var monitor = monitors[i];
|
var monitor = monitors[i];
|
||||||
var state = monitor.state;
|
var state = monitor.state;
|
||||||
if (
|
if (
|
||||||
state == MonitorState.NotSet ||
|
state == DuplicatorState.NotSet ||
|
||||||
state == MonitorState.AccessLost ||
|
state == DuplicatorState.AccessLost ||
|
||||||
state == MonitorState.AccessDenied ||
|
state == DuplicatorState.AccessDenied ||
|
||||||
state == MonitorState.SessionDisconnected ||
|
state == DuplicatorState.SessionDisconnected ||
|
||||||
state == MonitorState.Unknown
|
state == DuplicatorState.Unknown
|
||||||
) {
|
) {
|
||||||
reinitializeNeeded = true;
|
reinitializeNeeded = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,21 +11,23 @@ public class Monitor
|
|||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case MonitorState.Available:
|
case DuplicatorState.Ready:
|
||||||
break;
|
break;
|
||||||
case MonitorState.InvalidArg:
|
case DuplicatorState.Running:
|
||||||
|
break;
|
||||||
|
case DuplicatorState.InvalidArg:
|
||||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name);
|
Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name);
|
||||||
break;
|
break;
|
||||||
case MonitorState.AccessDenied:
|
case DuplicatorState.AccessDenied:
|
||||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name);
|
Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name);
|
||||||
break;
|
break;
|
||||||
case MonitorState.Unsupported:
|
case DuplicatorState.Unsupported:
|
||||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name);
|
Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name);
|
||||||
break;
|
break;
|
||||||
case MonitorState.SessionDisconnected:
|
case DuplicatorState.SessionDisconnected:
|
||||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name);
|
Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name);
|
||||||
break;
|
break;
|
||||||
case MonitorState.NotSet:
|
case DuplicatorState.NotSet:
|
||||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name);
|
Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -53,14 +55,19 @@ public class Monitor
|
|||||||
get { return id < Manager.monitorCount; }
|
get { return id < Manager.monitorCount; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonitorState state
|
public DuplicatorState state
|
||||||
{
|
{
|
||||||
get { return Lib.GetState(id); }
|
get { return Lib.GetState(id); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool available
|
public bool available
|
||||||
{
|
{
|
||||||
get { return state == MonitorState.Available; }
|
get
|
||||||
|
{
|
||||||
|
return
|
||||||
|
state == DuplicatorState.Ready ||
|
||||||
|
state == DuplicatorState.Running;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string name
|
public string name
|
||||||
|
|||||||
@@ -0,0 +1,296 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Duplicator.h"
|
||||||
|
#include "Monitor.h"
|
||||||
|
#include "Device.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
#include "IUnityInterface.h"
|
||||||
|
#include "IUnityGraphicsD3D11.h"
|
||||||
|
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Duplicator::Duplicator(Monitor* monitor)
|
||||||
|
: monitor_(monitor)
|
||||||
|
{
|
||||||
|
InitializeDevice();
|
||||||
|
InitializeDuplication();
|
||||||
|
CheckUnityAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Duplicator::~Duplicator()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Duplicator::InitializeDevice()
|
||||||
|
{
|
||||||
|
device_ = std::make_shared<IsolatedD3D11Device>();
|
||||||
|
|
||||||
|
if (FAILED(device_->Create(monitor_->GetAdapter())))
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Initialize() => IsolatedD3D11Device::Create() failed.");
|
||||||
|
state_ = State::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Duplicator::InitializeDuplication()
|
||||||
|
{
|
||||||
|
ComPtr<IDXGIOutput1> output1;
|
||||||
|
if (FAILED(monitor_->GetOutput().As(&output1))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hr = output1->DuplicateOutput(device_->GetDevice().Get(), &dupl_);
|
||||||
|
switch (hr)
|
||||||
|
{
|
||||||
|
case S_OK:
|
||||||
|
{
|
||||||
|
state_ = State::Ready;
|
||||||
|
const auto rot = static_cast<DXGI_MODE_ROTATION>(monitor_->GetRotation());
|
||||||
|
Debug::Log("Duplicator::Initialize() => OK.");
|
||||||
|
Debug::Log(" ID : ", monitor_->GetId());
|
||||||
|
Debug::Log(" Size : (", monitor_->GetWidth(), ", ", monitor_->GetHeight(), ")");
|
||||||
|
Debug::Log(" DPI : (", monitor_->GetDpiX(), ", ", monitor_->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("Duplicator::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("Duplicator::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("Duplicator::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("Duplicator::Initialize() => Currently not available.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_SESSION_DISCONNECTED:
|
||||||
|
{
|
||||||
|
state_ = State::SessionDisconnected;
|
||||||
|
Debug::Error("Duplicator::Initialize() => Session disconnected.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state_ = State::Unknown;
|
||||||
|
Debug::Error("Duplicator::Render() => Unknown Error.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Duplicator::CheckUnityAdapter()
|
||||||
|
{
|
||||||
|
DXGI_ADAPTER_DESC desc;
|
||||||
|
monitor_->GetAdapter()->GetDesc(&desc);
|
||||||
|
|
||||||
|
const auto unityAdapterLuid = GetUnityAdapterLuid();
|
||||||
|
const auto isUnityAdapter =
|
||||||
|
(desc.AdapterLuid.LowPart == unityAdapterLuid.LowPart) &&
|
||||||
|
(desc.AdapterLuid.HighPart == unityAdapterLuid.HighPart);
|
||||||
|
|
||||||
|
if (!isUnityAdapter)
|
||||||
|
{
|
||||||
|
Debug::Error("Duplicator::CheckUnityAdapter() => The adapter is not same as Unity, and now this case is not supported.");
|
||||||
|
state_ = State::Unsupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Duplicator::Start()
|
||||||
|
{
|
||||||
|
if (state_ != State::Ready) return;
|
||||||
|
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
thread_ = std::thread([this]
|
||||||
|
{
|
||||||
|
state_ = State::Running;
|
||||||
|
|
||||||
|
shouldRun_ = true;
|
||||||
|
while (shouldRun_)
|
||||||
|
{
|
||||||
|
if (!Duplicate()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ == State::Running)
|
||||||
|
{
|
||||||
|
state_ = State::Ready;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Duplicator::Stop()
|
||||||
|
{
|
||||||
|
shouldRun_ = false;
|
||||||
|
|
||||||
|
if (thread_.joinable())
|
||||||
|
{
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Duplicator::IsRunning() const
|
||||||
|
{
|
||||||
|
return state_ == State::Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Duplicator::IsError() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
state_ != State::Ready &&
|
||||||
|
state_ != State::Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Duplicator::State Duplicator::GetState() const
|
||||||
|
{
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ComPtr<IDXGIOutputDuplication> Duplicator::GetDuplication()
|
||||||
|
{
|
||||||
|
return dupl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Duplicator::Frame& Duplicator::GetFrame() const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
return lastFrame_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Duplicator::Duplicate()
|
||||||
|
{
|
||||||
|
if (!dupl_ || !device_) return false;
|
||||||
|
|
||||||
|
ComPtr<IDXGIResource> resource;
|
||||||
|
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||||
|
const auto hr = dupl_->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedReleaser releaser([this]
|
||||||
|
{
|
||||||
|
const auto hr = dupl_->ReleaseFrame();
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
switch (hr)
|
||||||
|
{
|
||||||
|
case DXGI_ERROR_ACCESS_LOST:
|
||||||
|
{
|
||||||
|
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
||||||
|
state_ = State::AccessLost;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_ERROR_INVALID_CALL:
|
||||||
|
{
|
||||||
|
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state_ = State::Unknown;
|
||||||
|
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ComPtr<ID3D11Texture2D> texture;
|
||||||
|
if (FAILED(resource.As(&texture)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto copyTarget = device_->GetCompatibleSharedTexture(texture);
|
||||||
|
if (!copyTarget)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<ID3D11DeviceContext> context;
|
||||||
|
device_->GetDevice()->GetImmediateContext(&context);
|
||||||
|
context->CopyResource(copyTarget.Get(), texture.Get());
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
lastFrame_ = Frame { copyTarget, frameInfo };
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <dxgi1_2.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <wrl/client.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Monitor;
|
||||||
|
|
||||||
|
|
||||||
|
enum class DuplicatorState
|
||||||
|
{
|
||||||
|
NotSet = -1,
|
||||||
|
Ready = 0,
|
||||||
|
Running = 1,
|
||||||
|
InvalidArg = 2,
|
||||||
|
AccessDenied = 3,
|
||||||
|
Unsupported = 4,
|
||||||
|
CurrentlyNotAvailable = 5,
|
||||||
|
SessionDisconnected = 6,
|
||||||
|
AccessLost = 7,
|
||||||
|
TextureSizeInconsistent = 8,
|
||||||
|
Unknown = 999,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Duplicator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using State = DuplicatorState;
|
||||||
|
|
||||||
|
struct Frame
|
||||||
|
{
|
||||||
|
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
|
||||||
|
DXGI_OUTDUPL_FRAME_INFO info;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Duplicator(Monitor* monitor);
|
||||||
|
~Duplicator();
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
bool IsRunning() const;
|
||||||
|
bool IsError() const;
|
||||||
|
State GetState() const;
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> GetDuplication();
|
||||||
|
const Frame& GetFrame() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeDevice();
|
||||||
|
void InitializeDuplication();
|
||||||
|
void CheckUnityAdapter();
|
||||||
|
bool Duplicate();
|
||||||
|
|
||||||
|
Monitor* monitor_ = nullptr;
|
||||||
|
State state_ = State::Ready;
|
||||||
|
|
||||||
|
std::shared_ptr<class IsolatedD3D11Device> device_;
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> dupl_;
|
||||||
|
Frame lastFrame_;
|
||||||
|
|
||||||
|
volatile bool shouldRun_ = false;
|
||||||
|
std::thread thread_;
|
||||||
|
mutable std::mutex mutex_;
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <ShellScalingAPI.h>
|
#include <ShellScalingAPI.h>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "Monitor.h"
|
#include "Monitor.h"
|
||||||
|
#include "Duplicator.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "MonitorManager.h"
|
#include "MonitorManager.h"
|
||||||
@@ -11,45 +12,6 @@ using namespace Microsoft::WRL;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Monitor::Monitor(int id)
|
Monitor::Monitor(int id)
|
||||||
: id_(id)
|
: id_(id)
|
||||||
{
|
{
|
||||||
@@ -59,17 +21,6 @@ Monitor::Monitor(int id)
|
|||||||
|
|
||||||
Monitor::~Monitor()
|
Monitor::~Monitor()
|
||||||
{
|
{
|
||||||
m_stopLoop = true;
|
|
||||||
|
|
||||||
if (deskDupl_)
|
|
||||||
{
|
|
||||||
deskDupl_->Release();
|
|
||||||
deskDupl_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_desktopDuplicationThread.joinable()) {
|
|
||||||
m_desktopDuplicationThread.join();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,14 +29,8 @@ void Monitor::Initialize(
|
|||||||
const ComPtr<IDXGIOutput> &output
|
const ComPtr<IDXGIOutput> &output
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_pIsolated = std::make_shared<IsolatedD3D11Device>();
|
adapter_ = adapter;
|
||||||
m_textureQueue = std::make_shared<TextureQueue>();
|
output_ = output;
|
||||||
|
|
||||||
if (FAILED(m_pIsolated->Create(adapter)))
|
|
||||||
{
|
|
||||||
Debug::Error("Monitor::Initialize() => IsolatedD3D11Device::Create() failed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(output->GetDesc(&outputDesc_)))
|
if (FAILED(output->GetDesc(&outputDesc_)))
|
||||||
{
|
{
|
||||||
@@ -112,231 +57,21 @@ void Monitor::Initialize(
|
|||||||
// DPI is set as -1, so the application has to use the appropriate value.
|
// DPI is set as -1, so the application has to use the appropriate value.
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<IDXGIOutput1> output1;
|
duplicator_ = std::make_shared<Duplicator>(this);
|
||||||
if (FAILED(output.As(&output1))) {
|
if (duplicator_->GetState() == DuplicatorState::Ready)
|
||||||
return;
|
{
|
||||||
}
|
duplicator_->Start();
|
||||||
|
}
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check adapter
|
|
||||||
DXGI_ADAPTER_DESC adapterDesc;
|
|
||||||
adapter->GetDesc(&adapterDesc);
|
|
||||||
const auto unityAdapterLuid = GetUnityAdapterLuid();
|
|
||||||
const auto isUnityAdapter =
|
|
||||||
adapterDesc.AdapterLuid.HighPart == unityAdapterLuid.HighPart &&
|
|
||||||
adapterDesc.AdapterLuid.LowPart == unityAdapterLuid.LowPart;
|
|
||||||
|
|
||||||
// start desktop duplication thread
|
|
||||||
m_stopLoop = false;
|
|
||||||
if (isUnityAdapter) {
|
|
||||||
m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndCopyLoop, this));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndMapLoop, this));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Monitor::Render(UINT timeout)
|
void Monitor::Render()
|
||||||
{
|
{
|
||||||
if (!deskDupl_) return;
|
const auto frame = duplicator_->GetFrame(); // copy
|
||||||
|
const auto texture = frame.texture;
|
||||||
|
const auto frameInfo = frame.info;
|
||||||
|
|
||||||
HRESULT hr;
|
if (!texture) return;
|
||||||
ComPtr<IDXGIResource> resource;
|
|
||||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
|
||||||
|
|
||||||
hr = deskDupl_->AcquireNextFrame(timeout, &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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11Texture2D* texture;
|
|
||||||
if (FAILED(resource.CopyTo(&texture)))
|
|
||||||
{
|
|
||||||
Debug::Error("Monitor::Render() => resource.As() failed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateMetadata(frameInfo);
|
|
||||||
|
|
||||||
if (frameInfo.PointerPosition.Visible)
|
|
||||||
{
|
|
||||||
GetMonitorManager()->SetCursorMonitorId(id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetMonitorManager()->GetCursorMonitorId() == id_)
|
|
||||||
{
|
|
||||||
UpdateCursor(frameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UseGetPixels())
|
|
||||||
{
|
|
||||||
CopyTextureFromGpuToCpu(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = deskDupl_->ReleaseFrame();
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
switch (hr)
|
|
||||||
{
|
|
||||||
case DXGI_ERROR_ACCESS_LOST:
|
|
||||||
{
|
|
||||||
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
|
||||||
state_ = State::AccessLost;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DXGI_ERROR_INVALID_CALL:
|
|
||||||
{
|
|
||||||
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
state_ = State::Unknown;
|
|
||||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasBeenUpdated_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
// Get texture
|
||||||
if (unityTexture_)
|
if (unityTexture_)
|
||||||
@@ -344,7 +79,7 @@ void Monitor::CopyTextureFromThread()
|
|||||||
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||||
texture->GetDesc(&srcDesc);
|
texture->GetDesc(&srcDesc);
|
||||||
unityTexture_->GetDesc(&dstDesc);
|
unityTexture_->GetDesc(&dstDesc);
|
||||||
if (srcDesc.Width != dstDesc.Width ||
|
if (srcDesc.Width != dstDesc.Width ||
|
||||||
srcDesc.Height != dstDesc.Height)
|
srcDesc.Height != dstDesc.Height)
|
||||||
{
|
{
|
||||||
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
||||||
@@ -353,8 +88,9 @@ void Monitor::CopyTextureFromThread()
|
|||||||
//Debug::Log(" => Try modifying width/height using reported value from DDA.");
|
//Debug::Log(" => Try modifying width/height using reported value from DDA.");
|
||||||
//width_ = srcDesc.Width;
|
//width_ = srcDesc.Width;
|
||||||
//height_ = srcDesc.Height;
|
//height_ = srcDesc.Height;
|
||||||
state_ = MonitorState::TextureSizeInconsistent;
|
//state_ = MonitorState::TextureSizeInconsistent;
|
||||||
//SendMessageToUnity(Message::TextureSizeChanged);
|
//SendMessageToUnity(Message::TextureSizeChanged);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -385,109 +121,6 @@ void Monitor::CopyTextureFromThread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Monitor::DuplicateAndCopyLoop()
|
|
||||||
{
|
|
||||||
if (!deskDupl_) return;
|
|
||||||
|
|
||||||
while (!m_stopLoop)
|
|
||||||
{
|
|
||||||
ComPtr<IDXGIResource> resource;
|
|
||||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
|
||||||
|
|
||||||
const 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedReleaser releaser([this]
|
|
||||||
{
|
|
||||||
const auto hr = deskDupl_->ReleaseFrame();
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
switch (hr)
|
|
||||||
{
|
|
||||||
case DXGI_ERROR_ACCESS_LOST:
|
|
||||||
{
|
|
||||||
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
|
||||||
state_ = State::AccessLost;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DXGI_ERROR_INVALID_CALL:
|
|
||||||
{
|
|
||||||
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
state_ = State::Unknown;
|
|
||||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ComPtr<ID3D11Texture2D> texture;
|
|
||||||
if (FAILED(resource.As(&texture))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy target
|
|
||||||
auto copyTarget = m_pIsolated->GetCompatibleSharedTexture(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||||
{
|
{
|
||||||
auto cursor_ = GetMonitorManager()->GetCursor();
|
auto cursor_ = GetMonitorManager()->GetCursor();
|
||||||
@@ -508,7 +141,7 @@ void Monitor::UpdateMoveRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
|||||||
{
|
{
|
||||||
moveRectSize_ = metaData_.Size();
|
moveRectSize_ = metaData_.Size();
|
||||||
|
|
||||||
const auto hr = deskDupl_->GetFrameMoveRects(
|
const auto hr = GetDeskDupl()->GetFrameMoveRects(
|
||||||
moveRectSize_,
|
moveRectSize_,
|
||||||
metaData_.As<DXGI_OUTDUPL_MOVE_RECT>(),
|
metaData_.As<DXGI_OUTDUPL_MOVE_RECT>(),
|
||||||
&moveRectSize_);
|
&moveRectSize_);
|
||||||
@@ -552,7 +185,7 @@ void Monitor::UpdateDirtyRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
|||||||
{
|
{
|
||||||
dirtyRectSize_ = metaData_.Size() - moveRectSize_;
|
dirtyRectSize_ = metaData_.Size() - moveRectSize_;
|
||||||
|
|
||||||
const auto hr = deskDupl_->GetFrameDirtyRects(
|
const auto hr = GetDeskDupl()->GetFrameDirtyRects(
|
||||||
dirtyRectSize_,
|
dirtyRectSize_,
|
||||||
metaData_.As<RECT>(moveRectSize_ /* offset */),
|
metaData_.As<RECT>(moveRectSize_ /* offset */),
|
||||||
&dirtyRectSize_);
|
&dirtyRectSize_);
|
||||||
@@ -598,9 +231,21 @@ int Monitor::GetId() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MonitorState Monitor::GetState() const
|
ComPtr<struct IDXGIAdapter> Monitor::GetAdapter()
|
||||||
{
|
{
|
||||||
return state_;
|
return adapter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ComPtr<struct IDXGIOutput> Monitor::GetOutput()
|
||||||
|
{
|
||||||
|
return output_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DuplicatorState Monitor::GetDuplicatorState() const
|
||||||
|
{
|
||||||
|
return duplicator_->GetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -616,9 +261,9 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IDXGIOutputDuplication* Monitor::GetDeskDupl()
|
ComPtr<IDXGIOutputDuplication> Monitor::GetDeskDupl()
|
||||||
{
|
{
|
||||||
return deskDupl_;
|
return duplicator_->GetDuplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,38 +8,27 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
enum class MonitorState
|
|
||||||
{
|
enum class DuplicatorState;
|
||||||
NotSet = -1,
|
|
||||||
Available = 0,
|
|
||||||
InvalidArg = 1,
|
|
||||||
AccessDenied = 2,
|
|
||||||
Unsupported = 3,
|
|
||||||
CurrentlyNotAvailable = 4,
|
|
||||||
SessionDisconnected = 5,
|
|
||||||
AccessLost = 6,
|
|
||||||
TextureSizeInconsistent = 7,
|
|
||||||
Unknown = 999,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Monitor
|
class Monitor
|
||||||
{
|
{
|
||||||
class ThreadedDesktopDuplicator *m_threaded = nullptr;
|
class ThreadedDesktopDuplicator *m_threaded = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using State = MonitorState;
|
|
||||||
|
|
||||||
explicit Monitor(int id);
|
explicit Monitor(int id);
|
||||||
~Monitor();
|
~Monitor();
|
||||||
void Initialize(
|
void Initialize(
|
||||||
const Microsoft::WRL::ComPtr<struct IDXGIAdapter> &adapter,
|
const Microsoft::WRL::ComPtr<struct IDXGIAdapter> &adapter,
|
||||||
const Microsoft::WRL::ComPtr<struct IDXGIOutput> &output);
|
const Microsoft::WRL::ComPtr<struct IDXGIOutput> &output);
|
||||||
void CopyTextureFromThread();
|
void Render();
|
||||||
void Render(UINT timeout = 0);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int GetId() const;
|
int GetId() const;
|
||||||
State GetState() const;
|
Microsoft::WRL::ComPtr<struct IDXGIAdapter> GetAdapter();
|
||||||
|
Microsoft::WRL::ComPtr<struct IDXGIOutput> GetOutput();
|
||||||
|
DuplicatorState GetDuplicatorState() const;
|
||||||
void SetUnityTexture(ID3D11Texture2D* texture);
|
void SetUnityTexture(ID3D11Texture2D* texture);
|
||||||
ID3D11Texture2D* GetUnityTexture() const;
|
ID3D11Texture2D* GetUnityTexture() const;
|
||||||
void GetName(char* buf, int len) const;
|
void GetName(char* buf, int len) const;
|
||||||
@@ -54,7 +43,7 @@ public:
|
|||||||
int GetRotation() const;
|
int GetRotation() const;
|
||||||
int GetDpiX() const;
|
int GetDpiX() const;
|
||||||
int GetDpiY() const;
|
int GetDpiY() const;
|
||||||
IDXGIOutputDuplication* GetDeskDupl();
|
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> GetDeskDupl();
|
||||||
int GetMoveRectCount() const;
|
int GetMoveRectCount() const;
|
||||||
DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const;
|
DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const;
|
||||||
int GetDirtyRectCount() const;
|
int GetDirtyRectCount() const;
|
||||||
@@ -63,14 +52,6 @@ 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);
|
||||||
|
|
||||||
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,18 +60,25 @@ private:
|
|||||||
void CopyTextureFromGpuToCpu(ID3D11Texture2D* texture);
|
void CopyTextureFromGpuToCpu(ID3D11Texture2D* texture);
|
||||||
|
|
||||||
int id_ = -1;
|
int id_ = -1;
|
||||||
|
|
||||||
UINT dpiX_ = -1, dpiY_ = -1;
|
UINT dpiX_ = -1, dpiY_ = -1;
|
||||||
int width_ = -1, height_ = -1;
|
int width_ = -1, height_ = -1;
|
||||||
|
|
||||||
bool hasBeenUpdated_ = false;
|
bool hasBeenUpdated_ = false;
|
||||||
bool useGetPixels_ = false;
|
bool useGetPixels_ = false;
|
||||||
State state_ = State::NotSet;
|
|
||||||
IDXGIOutputDuplication* deskDupl_ = nullptr;
|
Microsoft::WRL::ComPtr<IDXGIOutput> output_;
|
||||||
ID3D11Texture2D* unityTexture_ = nullptr;
|
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter_;
|
||||||
DXGI_OUTPUT_DESC outputDesc_;
|
DXGI_OUTPUT_DESC outputDesc_;
|
||||||
MONITORINFOEX monitorInfo_;
|
MONITORINFOEX monitorInfo_;
|
||||||
Buffer<BYTE> metaData_;
|
|
||||||
|
std::shared_ptr<class Duplicator> duplicator_;
|
||||||
|
|
||||||
|
ID3D11Texture2D* unityTexture_ = nullptr;
|
||||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> textureForGetPixels_;
|
Microsoft::WRL::ComPtr<ID3D11Texture2D> textureForGetPixels_;
|
||||||
Buffer<BYTE> bufferForGetPixels_;
|
Buffer<BYTE> bufferForGetPixels_;
|
||||||
|
|
||||||
|
Buffer<BYTE> metaData_;
|
||||||
UINT moveRectSize_ = 0;
|
UINT moveRectSize_ = 0;
|
||||||
UINT dirtyRectSize_ = 0;;
|
UINT dirtyRectSize_ = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Monitor.h"
|
#include "Monitor.h"
|
||||||
|
#include "Duplicator.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "MonitorManager.h"
|
#include "MonitorManager.h"
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ 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->CopyTextureFromThread();
|
monitor->Render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,14 +197,14 @@ extern "C"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id)
|
UNITY_INTERFACE_EXPORT DuplicatorState UNITY_INTERFACE_API GetState(int id)
|
||||||
{
|
{
|
||||||
if (!g_manager) return MonitorState::NotSet;
|
if (!g_manager) return DuplicatorState::NotSet;
|
||||||
if (auto monitor = g_manager->GetMonitor(id))
|
if (auto monitor = g_manager->GetMonitor(id))
|
||||||
{
|
{
|
||||||
return monitor->GetState();
|
return monitor->GetDuplicatorState();
|
||||||
}
|
}
|
||||||
return MonitorState::NotSet;
|
return DuplicatorState::NotSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
|
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName).pdb" "$(Soluti
|
|||||||
<ClCompile Include="Common.cpp" />
|
<ClCompile Include="Common.cpp" />
|
||||||
<ClCompile Include="Debug.cpp" />
|
<ClCompile Include="Debug.cpp" />
|
||||||
<ClCompile Include="Device.cpp" />
|
<ClCompile Include="Device.cpp" />
|
||||||
|
<ClCompile Include="Duplicator.cpp" />
|
||||||
<ClCompile Include="MonitorManager.cpp" />
|
<ClCompile Include="MonitorManager.cpp" />
|
||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="Monitor.cpp" />
|
<ClCompile Include="Monitor.cpp" />
|
||||||
@@ -151,6 +152,7 @@ copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName).pdb" "$(Soluti
|
|||||||
<ClInclude Include="Common.h" />
|
<ClInclude Include="Common.h" />
|
||||||
<ClInclude Include="Debug.h" />
|
<ClInclude Include="Debug.h" />
|
||||||
<ClInclude Include="Device.h" />
|
<ClInclude Include="Device.h" />
|
||||||
|
<ClInclude Include="Duplicator.h" />
|
||||||
<ClInclude Include="MonitorManager.h" />
|
<ClInclude Include="MonitorManager.h" />
|
||||||
<ClInclude Include="include\IUnityGraphics.h" />
|
<ClInclude Include="include\IUnityGraphics.h" />
|
||||||
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
|
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
<ClInclude Include="MonitorManager.h" />
|
<ClInclude Include="MonitorManager.h" />
|
||||||
<ClInclude Include="Debug.h" />
|
<ClInclude Include="Debug.h" />
|
||||||
<ClInclude Include="Device.h" />
|
<ClInclude Include="Device.h" />
|
||||||
|
<ClInclude Include="Duplicator.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Monitor.cpp" />
|
<ClCompile Include="Monitor.cpp" />
|
||||||
@@ -30,5 +31,6 @@
|
|||||||
<ClCompile Include="Common.cpp" />
|
<ClCompile Include="Common.cpp" />
|
||||||
<ClCompile Include="Debug.cpp" />
|
<ClCompile Include="Debug.cpp" />
|
||||||
<ClCompile Include="Device.cpp" />
|
<ClCompile Include="Device.cpp" />
|
||||||
|
<ClCompile Include="Duplicator.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user