Compare commits

...

10 Commits

Author SHA1 Message Date
hecomi
372e44d8c1 output logs. 2016-11-10 22:35:46 +09:00
hecomi
d79eb91333 fix freeze bug caused by masked cursor boundary conditions. 2016-11-10 02:50:59 +09:00
hecomi
f654df7f5b add debug logs and use safer code. 2016-11-09 21:58:00 +09:00
hecomi
620762dba7 add logging and use smart pointers for buffers. 2016-11-09 19:40:05 +09:00
hecomi
43ba445623 Merge branch 'master' of github.com:hecomi/uDesktopDuplication 2016-11-09 02:55:32 +09:00
hecomi
c7c12de730 move dll location. 2016-11-09 02:55:26 +09:00
hecomi
1086595d6b fix bug that did not remove unsupported monitor element in list. 2016-11-09 02:54:49 +09:00
hecomi
f69fb6a7bb remove monitor if unsupported. 2016-11-09 00:50:57 +09:00
hecomi
b661b4a93f modify zoom scene. 2016-11-09 00:23:25 +09:00
hecomi
8d9ef71829 update monitor id of loupe. 2016-11-09 00:18:52 +09:00
25 changed files with 484 additions and 149 deletions

1
.gitignore vendored
View File

@@ -27,3 +27,4 @@ sysinfo.txt
.DS_Store
/Assets/AssetStoreTools*
/Assets/Extensions*
/uDesktopDuplication.log

View File

@@ -7,21 +7,19 @@ public class Loupe : MonoBehaviour
public float aspect = 1f;
void Start()
{
uddTexture_ = GetComponent<uDesktopDuplication.Texture>();
{
uddTexture_ = GetComponent<uDesktopDuplication.Texture>();
uddTexture_.useClip = true;
}
void Update()
{
// To get other monitor textures, set dirty flag.
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
monitor.CreateTexture();
monitor.shouldBeUpdated = true;
}
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
if (!uddTexture_.monitor.isCursorVisible) {
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
// To get other monitor textures, set dirty flag.
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
monitor.CreateTexture();
monitor.shouldBeUpdated = true;
}
var x = (float)uddTexture_.monitor.cursorX / uddTexture_.monitor.width;

View File

@@ -4,6 +4,10 @@ using System.Collections.Generic;
public class MultipleMonitorCreator : MonoBehaviour
{
[SerializeField] GameObject monitorPrefab;
[SerializeField] bool removeIfUnsupported = true;
[SerializeField] float removeWaitDuration = 5f;
bool hasMonitorUnsupportStateChecked = false;
float removeWaitTimer_ = 0f;
public class MonitorInfo
{
@@ -13,14 +17,21 @@ public class MultipleMonitorCreator : MonoBehaviour
public Vector3 meshBounds;
}
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
public List<MonitorInfo> monitors { get { return monitors_; } }
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
public List<MonitorInfo> monitors { get { return monitors_; } }
void Start()
{
Create();
}
void Update()
{
if (removeIfUnsupported) {
RemoveUnsupportedDisplayAfterRemoveTimer();
}
}
void OnEnable()
{
uDesktopDuplication.Manager.onReinitialized += Recreate;
@@ -31,14 +42,38 @@ public class MultipleMonitorCreator : MonoBehaviour
uDesktopDuplication.Manager.onReinitialized -= Recreate;
}
void RemoveUnsupportedDisplayAfterRemoveTimer()
{
if (!hasMonitorUnsupportStateChecked) {
removeWaitTimer_ += Time.deltaTime;
if (removeWaitTimer_ > removeWaitDuration) {
hasMonitorUnsupportStateChecked = true;
foreach (var info in monitors_) {
if (info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported) {
Destroy(info.gameObject);
}
}
monitors_.RemoveAll(info => info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported);
}
}
}
void ResetRemoveTimer()
{
hasMonitorUnsupportStateChecked = false;
removeWaitTimer_ = 0f;
}
void Create()
{
ResetRemoveTimer();
// Sort monitors in coordinate order
var monitors = uDesktopDuplication.Manager.monitors;
monitors.Sort((a, b) => a.left - b.left);
// Create monitors
for (int i = 0 ; i < uDesktopDuplication.Manager.monitorCount; ++i) {
for (int i = 0; i < uDesktopDuplication.Manager.monitorCount; ++i) {
// Create monitor obeject
var go = Instantiate(monitorPrefab);
go.name = "Monitor " + i;

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 99257566ccd0582439a44abad90e65d4
folderAsset: yes
timeCreated: 1478626361
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using UnityEngine.Assertions;
using System.Collections.Generic;
namespace uDesktopDuplication
@@ -53,6 +54,7 @@ public class Cursor : MonoBehaviour
}
var cursorTexture = textures_[key];
Assert.IsNotNull(cursorTexture);
monitor.GetCursorTexture(cursorTexture.GetNativeTexturePtr());
uddTexture_.material.SetTexture("_CursorTex", cursorTexture);
}

View File

@@ -39,9 +39,18 @@ public enum MonitorState
AccessLost = 6,
}
public enum DebugMode
{
None = 0,
File = 1,
UnityLog = 2, /* currently has bug when app exits. */
}
public static class Lib
{
public delegate void MessageHandler(Message message);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogDelegate(string str);
[DllImport("uDesktopDuplication")]
public static extern void InitializeUDD();
@@ -54,6 +63,16 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern Message PopMessage();
[DllImport("uDesktopDuplication")]
public static extern void EnableDebug();
[DllImport("uDesktopDuplication")]
public static extern void DisableDebug();
[DllImport("uDesktopDuplication")]
public static extern void SetDebugMode(DebugMode mode);
[DllImport("uDesktopDuplication")]
public static extern void SetLogFunc(IntPtr func);
[DllImport("uDesktopDuplication")]
public static extern void SetErrorFunc(IntPtr func);
[DllImport("uDesktopDuplication")]
public static extern int GetMonitorCount();
[DllImport("uDesktopDuplication")]
public static extern int GetCursorMonitorId();

View File

@@ -1,6 +1,7 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace uDesktopDuplication
{
@@ -51,18 +52,20 @@ public class Manager : MonoBehaviour
}
}
[SerializeField] DebugMode debugMode = DebugMode.File;
[SerializeField] int desktopDuplicationApiTimeout = 0;
[SerializeField] float retryReinitializationDuration = 1f;
private Coroutine renderCoroutine_ = null;
private bool shouldReinitialize = false;
private float reinitializationTimer = 0f;
private bool shouldReinitialize_ = false;
private float reinitializationTimer_ = 0f;
public delegate void ReinitializeHandler();
public static event ReinitializeHandler onReinitialized;
void Awake()
{
Lib.SetDebugMode(debugMode);
Lib.InitializeUDD();
if (instance_ != null) return;
@@ -96,12 +99,6 @@ public class Manager : MonoBehaviour
Lib.Update();
ReinitializeIfNeeded();
UpdateMessage();
/*
foreach (var monitor in monitors_) {
Debug.LogFormat("[{0}] {1}", monitor.id, monitor.state);
}
*/
}
[ContextMenu("Reinitialize")]
@@ -120,20 +117,20 @@ public class Manager : MonoBehaviour
monitor.state == MonitorState.AccessLost ||
monitor.state == MonitorState.AccessDenied ||
monitor.state == MonitorState.SessionDisconnected) {
if (!shouldReinitialize) {
shouldReinitialize = true;
reinitializationTimer = 0f;
if (!shouldReinitialize_) {
shouldReinitialize_ = true;
reinitializationTimer_ = 0f;
break;
}
}
}
if (shouldReinitialize) {
if (reinitializationTimer > retryReinitializationDuration) {
if (shouldReinitialize_) {
if (reinitializationTimer_ > retryReinitializationDuration) {
Reinitialize();
shouldReinitialize = false;
shouldReinitialize_ = false;
}
reinitializationTimer += Time.deltaTime;
reinitializationTimer_ += Time.deltaTime;
}
}
@@ -168,6 +165,7 @@ public class Manager : MonoBehaviour
void CreateMonitors()
{
monitors.Clear();
for (int i = 0; i < monitorCount; ++i) {
monitors.Add(new Monitor(i));
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <queue>
#include <unordered_map>
#include <iostream>
#include <d3d11.h>
#include "IUnityInterface.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
extern IUnityInterfaces* g_unity;
extern std::unique_ptr<MonitorManager> g_manager;
extern std::queue<Message> g_messages;
IUnityInterfaces* GetUnity()
{
return g_unity;
}
ID3D11Device* GetDevice()
{
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
}
const std::unique_ptr<MonitorManager>& GetMonitorManager()
{
return g_manager;
}
void SendMessageToUnity(Message message)
{
g_messages.push(message);
}

View File

@@ -1,15 +1,40 @@
#pragma once
#include <memory>
#include "IUnityInterface.h"
#include <string>
#include <functional>
class MonitorManager;
// Unity interface and ID3D11Device getters
struct IUnityInterfaces;
IUnityInterfaces* GetUnity();
struct ID3D11Device;
ID3D11Device* GetDevice();
// Utility
template <class T>
auto MakeUniqueWithReleaser(T* ptr)
{
const auto deleter = [](T* ptr)
{
if (ptr != nullptr) ptr->Release();
};
return std::unique_ptr<T, decltype(deleter)>(ptr, deleter);
}
// Manager getter
class MonitorManager;
const std::unique_ptr<MonitorManager>& GetMonitorManager();
// Message is pooled and fetch from Unity.
enum class Message
{
None = -1,
Reinitialized = 0,
};
void SendMessageToUnity(Message message);

View File

@@ -1,5 +1,6 @@
#include <d3d11.h>
#include "Common.h"
#include "Debug.h"
#include "MonitorManager.h"
#include "Monitor.h"
#include "Cursor.h"
@@ -13,16 +14,6 @@ Cursor::Cursor(Monitor* monitor)
Cursor::~Cursor()
{
if (apiBuffer_ != nullptr)
{
delete[] apiBuffer_;
apiBuffer_ = nullptr;
}
if (bgra32Buffer_ != nullptr)
{
delete[] bgra32Buffer_;
bgra32Buffer_ = nullptr;
}
}
@@ -43,6 +34,11 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
}
if (!IsCursorOnParentMonitor())
{
return;
}
if (frameInfo.PointerShapeBufferSize == 0)
{
return;
@@ -51,54 +47,95 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
// Increase the buffer size if needed
if (frameInfo.PointerShapeBufferSize > apiBufferSize_)
{
if (apiBuffer_) delete[] apiBuffer_;
apiBuffer_ = new BYTE[frameInfo.PointerShapeBufferSize];
apiBufferSize_ = frameInfo.PointerShapeBufferSize;
apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_);
}
if (apiBuffer_ == nullptr) return;
if (!apiBuffer_) return;
// Get mouse pointer information
UINT bufferSize;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(apiBuffer_),
apiBufferSize_,
reinterpret_cast<void*>(apiBuffer_.get()),
&bufferSize,
&shapeInfo_);
&shapeInfo);
if (FAILED(hr))
{
delete[] apiBuffer_;
apiBuffer_ = nullptr;
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
apiBuffer_.reset();
apiBufferSize_ = 0;
}
shapeInfo_ = shapeInfo;
}
void Cursor::UpdateTexture()
{
if (!IsCursorOnParentMonitor())
{
return;
}
// cursor type
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
// Size
const auto w = GetWidth();
const auto h = GetHeight();
const auto w0 = GetWidth();
const auto h0 = GetHeight();
const auto p = GetPitch();
auto w = w0;
auto h = h0;
// Convert the buffer given by API into BGRA32
const UINT bgraBufferSize = w * h * 4;
const UINT bgraBufferSize = w0 * h0 * 4;
if (bgraBufferSize > bgra32BufferSize_)
{
if (bgra32Buffer_) delete[] bgra32Buffer_;
bgra32Buffer_ = new BYTE[bgraBufferSize];
bgra32BufferSize_ = bgraBufferSize;
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
}
if (bgra32Buffer_ == nullptr) return;
if (!bgra32Buffer_) return;
// If masked, copy the desktop image and merge it with masked image.
if (isMono || isColorMask)
{
HRESULT hr;
const auto mw = monitor_->GetWidth();
const auto mh = monitor_->GetHeight();
auto x = x_;
auto y = y_;
auto colMin = 0;
auto colMax = w0;
auto rowMin = 0;
auto rowMax = h0;
if (x < 0)
{
x = 0;
w = w0 + x_;
colMin = w0 - w;
}
if (x + w >= mw)
{
w = mw - x_;
colMax = w;
}
if (y < 0)
{
y = 0;
h = h0 + y_;
rowMin = h0 - h;
}
if (y + h >= mh)
{
h = mh - y_;
rowMax = h;
}
D3D11_TEXTURE2D_DESC desc;
desc.Width = w;
desc.Height = h;
@@ -114,18 +151,26 @@ void Cursor::UpdateTexture()
ID3D11Texture2D* texture = nullptr;
hr = GetDevice()->CreateTexture2D(&desc, nullptr, &texture);
const auto textureReleaser = MakeUniqueWithReleaser(texture);
if (FAILED(hr))
{
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
return;
}
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.left = x_;
box.top = y_;
box.right = x_ + w;
box.bottom = y_ + h;
box.left = x;
box.top = y;
box.right = x + w;
box.bottom = y + h;
if (monitor_->GetUnityTexture() == nullptr)
{
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
return;
}
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
@@ -134,9 +179,10 @@ void Cursor::UpdateTexture()
IDXGISurface* surface = nullptr;
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
texture->Release();
const auto surfaceReleaser = MakeUniqueWithReleaser(surface);
if (FAILED(hr))
{
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
return;
}
@@ -144,7 +190,7 @@ void Cursor::UpdateTexture()
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
if (FAILED(hr))
{
surface->Release();
Debug::Error("Cursor::UpdateTexture() => surface->Map() failed.");
return;
}
@@ -153,40 +199,39 @@ void Cursor::UpdateTexture()
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
// Access RGBA values at the same time
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
if (isMono)
{
for (int row = 0; row < h; ++row)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
BYTE mask = 0x80;
for (int col = 0; col < w; ++col)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = row * w + col;
BYTE mask = 0b10000000 >> (col % 8);
const int i = row * w0 + col;
const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask;
const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask;
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
output32[i] = (desktop32[y * desktopPitch + x] & andMask32) ^ xorMask32;
}
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
{
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
for (int row = 0; row < h; ++row)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (int col = 0; col < w; ++col)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = row * w + col;
const int j = row * p / sizeof(UINT) + col;
const int i = col + row * w0;
const int j = col + row * p / sizeof(UINT);
UINT mask = 0xFF000000 & buffer32[j];
if (mask)
{
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000;
}
else
{
@@ -197,7 +242,6 @@ void Cursor::UpdateTexture()
}
hr = surface->Unmap();
surface->Release();
if (FAILED(hr))
{
return;
@@ -205,24 +249,46 @@ void Cursor::UpdateTexture()
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
{
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
for (int i = 0; i < w * h; ++i)
{
output32[i] = buffer32[i];
}
}
return;
}
void Cursor::GetTexture(ID3D11Texture2D* texture)
{
if (bgra32Buffer_ == nullptr || texture == nullptr) return;
if (bgra32Buffer_ == nullptr)
{
Debug::Error("Cursor::GetTexture() => bgra32Buffer is null.");
return;
}
if (texture == nullptr)
{
Debug::Error("Cursor::GetTexture() => The given texture is null.");
return;
}
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
if ((int)desc.Width < GetWidth() || (int)desc.Height < GetHeight())
{
char buf[256];
sprintf_s(buf, 256,
"Cursor::GetTexture() => The given texture has smaller width / height.\n"
"Given => (%d, %d) Buffer => (%d, %d)",
desc.Width, desc.Height, GetWidth(), GetHeight());
Debug::Error(buf);
return;
}
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0);
context->Release();
}
@@ -269,3 +335,9 @@ int Cursor::GetType() const
{
return shapeInfo_.Type;
}
bool Cursor::IsCursorOnParentMonitor() const
{
return GetMonitorManager()->GetCursorMonitorId() == monitor_->GetId();
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <memory>
@@ -22,13 +24,15 @@ public:
int GetType() const;
private:
bool IsCursorOnParentMonitor() const;
Monitor* monitor_;
bool isVisible_ = false;
int x_ = -1;
int y_ = -1;
BYTE* apiBuffer_ = nullptr;
std::unique_ptr<BYTE[]> apiBuffer_ = nullptr;
UINT apiBufferSize_ = 0;
BYTE* bgra32Buffer_ = nullptr;
std::unique_ptr<BYTE[]> bgra32Buffer_ = nullptr;
UINT bgra32BufferSize_ = 0;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
LARGE_INTEGER timestamp_;

View File

@@ -0,0 +1,84 @@
#pragma once
#include <cstdio>
#include "Debug.h"
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::kFile;
decltype(Debug::logFunc_) Debug::logFunc_ = nullptr;
decltype(Debug::errFunc_) Debug::errFunc_ = nullptr;
decltype(Debug::fs_) Debug::fs_;
void Debug::Initialize()
{
if (mode_ == Mode::kFile)
{
fs_.open("uDesktopDuplication.log");
}
}
void Debug::Finalize()
{
fs_.close();
}
void Debug::Log(const char* msg)
{
switch (mode_)
{
case Mode::kNone:
{
break;
}
case Mode::kFile:
{
if (fs_.good())
{
fs_ << "[uDD::Log] " << msg << std::endl;
}
break;
}
case Mode::kUnityLog:
{
if (logFunc_ == nullptr)
{
char buf[256];
sprintf_s(buf, 256, "[uDD::Log] %s", msg);
logFunc_(buf);
break;
}
}
}
}
void Debug::Error(const char* msg)
{
switch (mode_)
{
case Mode::kNone:
{
break;
}
case Mode::kFile:
{
if (fs_.good())
{
fs_ << "[uDD::Err] " << msg << std::endl;
}
break;
}
case Mode::kUnityLog:
{
if (logFunc_ == nullptr)
{
char buf[256];
sprintf_s(buf, 256, "[uDD::Err] %s", msg);
errFunc_(buf);
}
}
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <fstream>
#include "IUnityInterface.h"
// Logging
class Debug
{
public:
enum class Mode
{
kNone = 0,
kFile = 1,
kUnityLog = 2,
};
using DebugLogFuncPtr = void(UNITY_INTERFACE_API *)(const char*);
static void SetMode(Mode mode) { mode_ = mode; }
static void Initialize();
static void Finalize();
static void SetLogFunc(DebugLogFuncPtr func) { logFunc_ = func; }
static void SetErrorFunc(DebugLogFuncPtr func) { errFunc_ = func; }
public:
static void Log(const char* msg);
static void Error(const char* msg);
private:
static Mode mode_;
static std::ofstream fs_;
static DebugLogFuncPtr logFunc_;
static DebugLogFuncPtr errFunc_;
};

View File

@@ -1,6 +1,7 @@
#include <d3d11.h>
#include <ShellScalingAPI.h>
#include "Common.h"
#include "Debug.h"
#include "Cursor.h"
#include "MonitorManager.h"
#include "Monitor.h"
@@ -13,7 +14,12 @@ Monitor::Monitor(int id)
}
HRESULT Monitor::Initialize(IDXGIOutput* output)
Monitor::~Monitor()
{
}
void Monitor::Initialize(IDXGIOutput* output)
{
output->GetDesc(&outputDesc_);
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
@@ -22,7 +28,11 @@ HRESULT Monitor::Initialize(IDXGIOutput* output)
GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_);
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl_);
IDXGIOutputDuplication* deskDupl;
const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl);
deskDupl_ = std::shared_ptr<IDXGIOutputDuplication>(
deskDupl,
[](IDXGIOutputDuplication* ptr) { ptr->Release(); });
// TODO: error check
switch (hr)
@@ -32,50 +42,43 @@ HRESULT Monitor::Initialize(IDXGIOutput* output)
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;
}
return hr;
}
Monitor::~Monitor()
void Monitor::Render(UINT timeout)
{
if (deskDupl_ != nullptr)
{
deskDupl_->Release();
}
}
HRESULT Monitor::Render(UINT timeout)
{
if (deskDupl_ == nullptr)
{
return S_OK;
}
if (!deskDupl_) return;
IDXGIResource* resource = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
HRESULT hr;
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
const auto resourceReleaser = MakeUniqueWithReleaser(resource);
if (FAILED(hr))
{
switch (hr)
@@ -83,16 +86,23 @@ HRESULT Monitor::Render(UINT timeout)
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:
break;
}
return hr;
return;
}
if (unityTexture_)
@@ -104,16 +114,16 @@ HRESULT Monitor::Render(UINT timeout)
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture);
context->Release();
resource->Release();
}
cursor_->UpdateBuffer(frameInfo);
cursor_->UpdateTexture();
deskDupl_->ReleaseFrame();
return S_OK;
hr = deskDupl_->ReleaseFrame();
if (FAILED(hr))
{
Debug::Error("Monitor::Render() => ReleaseFrame() failed.");
}
}
@@ -141,7 +151,7 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const
}
IDXGIOutputDuplication* Monitor::GetDeskDupl()
const std::shared_ptr<IDXGIOutputDuplication>& Monitor::GetDeskDupl()
{
return deskDupl_;
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <memory>
@@ -23,8 +25,8 @@ public:
explicit Monitor(int id);
~Monitor();
HRESULT Initialize(IDXGIOutput* output);
HRESULT Render(UINT timeout = 0);
void Initialize(IDXGIOutput* output);
void Render(UINT timeout = 0);
void GetCursorTexture(ID3D11Texture2D* texture);
public:
@@ -43,7 +45,7 @@ public:
int GetRotation() const;
int GetDpiX() const;
int GetDpiY() const;
IDXGIOutputDuplication* GetDeskDupl();
const std::shared_ptr<IDXGIOutputDuplication>& GetDeskDupl();
const std::unique_ptr<Cursor>& GetCursor();
private:
@@ -51,7 +53,7 @@ private:
UINT dpiX_ = -1, dpiY_ = -1;
State state_ = State::NotSet;
std::unique_ptr<Cursor> cursor_;
IDXGIOutputDuplication* deskDupl_ = nullptr;
std::shared_ptr<IDXGIOutputDuplication> deskDupl_;
ID3D11Texture2D* unityTexture_ = nullptr;
DXGI_OUTPUT_DESC outputDesc_;
MONITORINFOEX monitorInfo_;

View File

@@ -32,24 +32,24 @@ void MonitorManager::Initialize()
// Get factory
IDXGIFactory1* factory;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
const auto factoryReleaser = MakeUniqueWithReleaser(factory);
// Check all display adapters
int id = 0;
IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
const auto adapterReleaser = MakeUniqueWithReleaser(adapter);
// Search the main monitor from all outputs
IDXGIOutput* output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{
const auto outputReleaser = MakeUniqueWithReleaser(output);
auto monitor = std::make_shared<Monitor>(id++);
monitor->Initialize(output);
monitors_.push_back(monitor);
output->Release();
}
adapter->Release();
}
factory->Release();
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>

View File

@@ -7,9 +7,9 @@
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
#include "Debug.h"
#include "Monitor.h"
#include "Cursor.h"
#include "MonitorManager.h"
@@ -18,36 +18,9 @@
#pragma comment(lib, "Shcore.lib")
namespace
{
IUnityInterfaces* g_unity = nullptr;
std::unique_ptr<MonitorManager> g_manager;
std::queue<Message> g_messages;
}
IUnityInterfaces* GetUnity()
{
return g_unity;
}
ID3D11Device* GetDevice()
{
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
}
const std::unique_ptr<MonitorManager>& GetMonitorManager()
{
return g_manager;
}
void SendMessageToUnity(Message message)
{
g_messages.push(message);
}
IUnityInterfaces* g_unity = nullptr;
std::unique_ptr<MonitorManager> g_manager;
std::queue<Message> g_messages;
extern "C"
@@ -57,12 +30,20 @@ extern "C"
if (g_unity && !g_manager)
{
g_manager = std::make_unique<MonitorManager>();
Debug::Initialize();
}
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
{
g_manager.reset();
std::queue<Message> empty;
g_messages.swap(empty);
Debug::SetLogFunc(nullptr);
Debug::SetErrorFunc(nullptr);
Debug::Finalize();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
@@ -73,8 +54,8 @@ extern "C"
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload()
{
g_unity = nullptr;
FinalizeUDD();
g_unity = nullptr;
}
void UNITY_INTERFACE_API OnRenderEvent(int id)
@@ -103,7 +84,7 @@ extern "C"
g_manager->Update();
}
UNITY_INTERFACE_EXPORT Message PopMessage()
UNITY_INTERFACE_EXPORT Message UNITY_INTERFACE_API PopMessage()
{
if (g_messages.empty()) return Message::None;
@@ -112,6 +93,21 @@ extern "C"
return message;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetDebugMode(Debug::Mode mode)
{
Debug::SetMode(mode);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetLogFunc(Debug::DebugLogFuncPtr func)
{
Debug::SetLogFunc(func);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetErrorFunc(Debug::DebugLogFuncPtr func)
{
Debug::SetErrorFunc(func);
}
UNITY_INTERFACE_EXPORT size_t UNITY_INTERFACE_API GetMonitorCount()
{
if (!g_manager) return 0;

View File

@@ -89,7 +89,7 @@
<SDLCheck>true</SDLCheck>
</ClCompile>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -122,10 +122,12 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Common.cpp" />
<ClCompile Include="Debug.cpp" />
<ClCompile Include="MonitorManager.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Monitor.cpp" />
@@ -133,6 +135,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Common.h" />
<ClInclude Include="Debug.h" />
<ClInclude Include="MonitorManager.h" />
<ClInclude Include="include\IUnityGraphics.h" />
<ClInclude Include="include\IUnityGraphicsD3D11.h" />

View File

@@ -19,11 +19,14 @@
<ClInclude Include="Cursor.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="MonitorManager.h" />
<ClInclude Include="Debug.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Monitor.cpp" />
<ClCompile Include="Cursor.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MonitorManager.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="Debug.cpp" />
</ItemGroup>
</Project>