Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
166d172db2 | ||
|
|
95f8099392 | ||
|
|
9c62157c0c | ||
|
|
be79e52135 | ||
|
|
e9c8b4e571 | ||
|
|
77c95ab1bb |
@@ -5,8 +5,7 @@ using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
|
||||
public class MultipleMonitorCreator : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Create monitors using this prefab.")]
|
||||
[SerializeField]
|
||||
GameObject monitorPrefab;
|
||||
public GameObject monitorPrefab;
|
||||
|
||||
public enum ScaleMode
|
||||
{
|
||||
@@ -16,29 +15,24 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
}
|
||||
|
||||
[Tooltip("Real: DPI-based real scale \nFixed: Same width \nPixel: bigger if screen resolution is high.")]
|
||||
[SerializeField]
|
||||
ScaleMode scaleMode = ScaleMode.Fixed;
|
||||
public ScaleMode scaleMode = ScaleMode.Fixed;
|
||||
|
||||
[Tooltip("Use this sacle as width if scaleMode is Fixed.")]
|
||||
[SerializeField]
|
||||
float scale = 0.5f;
|
||||
[Tooltip("Use this scale as width if scaleMode is Fixed.")]
|
||||
public float scale = 0.5f;
|
||||
|
||||
[Tooltip("Please specify the surface direction of the mesh (e.g. Plane => Y.)")]
|
||||
public MeshForwardDirection meshForwardDirection = MeshForwardDirection.Z;
|
||||
|
||||
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
|
||||
[SerializeField]
|
||||
bool removeIfUnsupported = true;
|
||||
public bool removeIfUnsupported = true;
|
||||
|
||||
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
|
||||
[SerializeField]
|
||||
float removeWaitDuration = 5f;
|
||||
public float removeWaitDuration = 5f;
|
||||
|
||||
[Tooltip("Remove all childrens (for debug).")]
|
||||
[SerializeField]
|
||||
bool removeChildrenWhenClear = true;
|
||||
public bool removeChildrenWhenClear = true;
|
||||
|
||||
bool hasMonitorUnsupportStateChecked = false;
|
||||
bool hasMonitorUnsupportStateChecked_ = false;
|
||||
float removeWaitTimer_ = 0f;
|
||||
|
||||
public class MonitorInfo
|
||||
@@ -81,10 +75,10 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
|
||||
void RemoveUnsupportedDisplayAfterRemoveTimer()
|
||||
{
|
||||
if (!hasMonitorUnsupportStateChecked) {
|
||||
if (!hasMonitorUnsupportStateChecked_) {
|
||||
removeWaitTimer_ += Time.deltaTime;
|
||||
if (removeWaitTimer_ > removeWaitDuration) {
|
||||
hasMonitorUnsupportStateChecked = true;
|
||||
hasMonitorUnsupportStateChecked_ = true;
|
||||
foreach (var info in monitors_) {
|
||||
if (info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported) {
|
||||
Destroy(info.gameObject);
|
||||
@@ -97,7 +91,7 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
|
||||
void ResetRemoveTimer()
|
||||
{
|
||||
hasMonitorUnsupportStateChecked = false;
|
||||
hasMonitorUnsupportStateChecked_ = false;
|
||||
removeWaitTimer_ = 0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
{
|
||||
[SerializeField] float radius = 10f;
|
||||
[SerializeField] Vector3 offsetAngle = Vector3.zero;
|
||||
public float radius = 10f;
|
||||
public Vector3 offsetAngle = Vector3.zero;
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
|
||||
Binary file not shown.
@@ -5,8 +5,7 @@ using System.Collections.Generic;
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
|
||||
[AddComponentMenu("uDesktopDuplication/Cursor"),
|
||||
RequireComponent(typeof(Texture))]
|
||||
[AddComponentMenu("uDesktopDuplication/Cursor"), RequireComponent(typeof(Texture))]
|
||||
public class Cursor : MonoBehaviour
|
||||
{
|
||||
[SerializeField] Vector2 modelScale = Vector2.one;
|
||||
|
||||
@@ -30,13 +30,13 @@ public enum MonitorRotation
|
||||
|
||||
public enum MonitorState
|
||||
{
|
||||
NotSet = -1,
|
||||
Available = 0,
|
||||
InvalidArg = 1,
|
||||
AccessDenied = 2,
|
||||
Unsupported = 3,
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
NotSet = -1,
|
||||
Available = 0,
|
||||
InvalidArg = 1,
|
||||
AccessDenied = 2,
|
||||
Unsupported = 3,
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
TextureSizeInconsistent = 7,
|
||||
Unknown = 999,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
|
||||
[AddComponentMenu("uDesktopDuplication/Texture")]
|
||||
[AddComponentMenu("uDesktopDuplication/Texture"), RequireComponent(typeof(Cursor))]
|
||||
public class Texture : MonoBehaviour
|
||||
{
|
||||
private Monitor monitor_;
|
||||
@@ -13,9 +13,11 @@ public class Texture : MonoBehaviour
|
||||
set
|
||||
{
|
||||
monitor_ = value;
|
||||
material = GetComponent<Renderer>().material; // clone
|
||||
material.mainTexture = monitor_.texture;
|
||||
material.SetFloat("_Width", transform.localScale.x);
|
||||
if (monitor_ != null) {
|
||||
material = GetComponent<Renderer>().material; // clone
|
||||
material.mainTexture = monitor_.texture;
|
||||
material.SetFloat("_Width", transform.localScale.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,10 +107,7 @@ public class Texture : MonoBehaviour
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (!GetComponent<Cursor>())
|
||||
{
|
||||
gameObject.AddComponent<Cursor>();
|
||||
}
|
||||
AddCursorIfNotAttached();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
@@ -130,6 +129,14 @@ public class Texture : MonoBehaviour
|
||||
UpdateMaterial();
|
||||
}
|
||||
|
||||
void AddCursorIfNotAttached()
|
||||
{
|
||||
if (!GetComponent<Cursor>())
|
||||
{
|
||||
gameObject.AddComponent<Cursor>();
|
||||
}
|
||||
}
|
||||
|
||||
void Reinitialize()
|
||||
{
|
||||
// Monitor instance is released here when initialized.
|
||||
|
||||
@@ -33,7 +33,7 @@ enum class Message
|
||||
{
|
||||
None = -1,
|
||||
Reinitialized = 0,
|
||||
TextureSizeChanged = 1,
|
||||
TextureSizeChanged = 1,
|
||||
};
|
||||
|
||||
void SendMessageToUnity(Message message);
|
||||
@@ -54,25 +54,26 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_);
|
||||
}
|
||||
|
||||
if (!apiBuffer_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!apiBuffer_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get mouse pointer information
|
||||
UINT bufferSize;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
|
||||
apiBufferSize_,
|
||||
apiBuffer_.get(),
|
||||
&bufferSize,
|
||||
&shapeInfo);
|
||||
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
|
||||
apiBufferSize_,
|
||||
apiBuffer_.get(),
|
||||
&bufferSize,
|
||||
&shapeInfo);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
|
||||
apiBuffer_.reset();
|
||||
apiBufferSize_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
shapeInfo_ = shapeInfo;
|
||||
@@ -86,64 +87,137 @@ void Cursor::UpdateTexture()
|
||||
return;
|
||||
}
|
||||
|
||||
// cursor type
|
||||
// Cursor information
|
||||
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
||||
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
||||
const auto cursorImageWidth = GetWidth();
|
||||
const auto cursorImageHeight = GetHeight();
|
||||
const auto cursorImagePitch = GetPitch();
|
||||
|
||||
// Size
|
||||
const auto w0 = GetWidth();
|
||||
const auto h0 = GetHeight();
|
||||
const auto p = GetPitch();
|
||||
auto w = w0;
|
||||
auto h = h0;
|
||||
// Captured area
|
||||
auto capturedImageWidth = cursorImageWidth;
|
||||
auto capturedImageHeight = cursorImageHeight;
|
||||
|
||||
// Convert the buffer given by API into BGRA32
|
||||
const UINT bgraBufferSize = w0 * h0 * 4;
|
||||
const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4;
|
||||
if (bgraBufferSize > bgra32BufferSize_)
|
||||
{
|
||||
bgra32BufferSize_ = bgraBufferSize;
|
||||
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
|
||||
}
|
||||
if (!bgra32Buffer_) return;
|
||||
|
||||
// Check buffers
|
||||
if (!bgra32Buffer_ || !apiBuffer_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If masked, copy the desktop image and merge it with masked image.
|
||||
if (isMono || isColorMask)
|
||||
{
|
||||
const auto mw = monitor_->GetWidth();
|
||||
const auto mh = monitor_->GetHeight();
|
||||
const auto monitorWidth = monitor_->GetWidth();
|
||||
const auto monitorHeight = monitor_->GetHeight();
|
||||
const auto monitorRot = static_cast<DXGI_MODE_ROTATION>(monitor_->GetRotation());
|
||||
const auto isVertical =
|
||||
monitorRot == DXGI_MODE_ROTATION_ROTATE90 ||
|
||||
monitorRot == DXGI_MODE_ROTATION_ROTATE270;
|
||||
const auto desktopImageWidth = !isVertical ? monitorWidth : monitorHeight;
|
||||
const auto desktopImageHeight = !isVertical ? monitorHeight : monitorWidth;
|
||||
|
||||
auto x = x_;
|
||||
auto y = y_;
|
||||
auto colMin = 0;
|
||||
auto colMax = w0;
|
||||
auto colMax = cursorImageWidth;
|
||||
auto rowMin = 0;
|
||||
auto rowMax = h0;
|
||||
auto rowMax = cursorImageHeight;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
w = w0 + x_;
|
||||
colMin = w0 - w;
|
||||
capturedImageWidth = cursorImageWidth + x_;
|
||||
colMin = cursorImageWidth - capturedImageWidth;
|
||||
}
|
||||
if (x + w >= mw)
|
||||
if (x + capturedImageWidth >= monitorWidth)
|
||||
{
|
||||
w = mw - x_;
|
||||
colMax = w;
|
||||
capturedImageWidth = monitorWidth - x_;
|
||||
colMax = capturedImageWidth;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
h = h0 + y_;
|
||||
rowMin = h0 - h;
|
||||
capturedImageHeight = cursorImageHeight + y_;
|
||||
rowMin = cursorImageHeight - capturedImageHeight;
|
||||
}
|
||||
if (y + h >= mh)
|
||||
if (y + capturedImageHeight >= monitorHeight)
|
||||
{
|
||||
h = mh - y_;
|
||||
rowMax = h;
|
||||
capturedImageHeight = monitorHeight - y_;
|
||||
rowMax = capturedImageHeight;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
|
||||
switch (monitorRot)
|
||||
{
|
||||
case DXGI_MODE_ROTATION_ROTATE90:
|
||||
{
|
||||
box.left = y;
|
||||
box.top = monitorWidth - x - capturedImageWidth;
|
||||
box.right = y + capturedImageWidth;
|
||||
box.bottom = monitorWidth - x;
|
||||
break;
|
||||
}
|
||||
case DXGI_MODE_ROTATION_ROTATE180:
|
||||
{
|
||||
box.left = monitorWidth - x - capturedImageWidth;
|
||||
box.top = monitorHeight - y - capturedImageHeight;
|
||||
box.right = monitorWidth - x;
|
||||
box.bottom = monitorHeight - y;
|
||||
break;
|
||||
}
|
||||
case DXGI_MODE_ROTATION_ROTATE270:
|
||||
{
|
||||
box.left = monitorHeight - y - capturedImageHeight;
|
||||
box.top = x;
|
||||
box.right = monitorHeight - y;
|
||||
box.bottom = x + capturedImageWidth;
|
||||
break;
|
||||
}
|
||||
case DXGI_MODE_ROTATION_IDENTITY:
|
||||
case DXGI_MODE_ROTATION_UNSPECIFIED:
|
||||
{
|
||||
box.left = x;
|
||||
box.top = y;
|
||||
box.right = x + capturedImageWidth;
|
||||
box.bottom = y + capturedImageHeight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (box.left < 0 ||
|
||||
box.top < 0 ||
|
||||
box.right >= static_cast<UINT>(desktopImageWidth) ||
|
||||
box.bottom >= static_cast<UINT>(desktopImageHeight))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => box is out of area.");
|
||||
Debug::Error(
|
||||
" ",
|
||||
"(", box.left, ", ", box.top, ")",
|
||||
" ~ (", box.right, ", ", box.bottom, ") > ",
|
||||
"(", desktopImageWidth, ", ", desktopImageHeight, ")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (monitor_->GetUnityTexture() == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
desc.Width = capturedImageWidth;
|
||||
desc.Height = capturedImageHeight;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
@@ -161,26 +235,12 @@ void Cursor::UpdateTexture()
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
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;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
|
||||
}
|
||||
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
|
||||
}
|
||||
|
||||
ComPtr<IDXGISurface> surface;
|
||||
if (FAILED(texture.As(&surface)))
|
||||
{
|
||||
@@ -199,6 +259,27 @@ void Cursor::UpdateTexture()
|
||||
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
|
||||
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
||||
|
||||
// Take the monitor orientation into consideration.
|
||||
const auto getDesktop32 = [&](int col, int row)
|
||||
{
|
||||
switch (monitorRot)
|
||||
{
|
||||
case DXGI_MODE_ROTATION_ROTATE90:
|
||||
return desktop32[(capturedImageWidth - 1 - col) * desktopPitch + row];
|
||||
break;
|
||||
case DXGI_MODE_ROTATION_ROTATE180:
|
||||
return desktop32[(capturedImageHeight - 1 - row) * desktopPitch + (capturedImageWidth - 1 - col)];
|
||||
break;
|
||||
case DXGI_MODE_ROTATION_ROTATE270:
|
||||
return desktop32[col * desktopPitch + (capturedImageHeight - 1 - row)];
|
||||
break;
|
||||
case DXGI_MODE_ROTATION_IDENTITY:
|
||||
case DXGI_MODE_ROTATION_UNSPECIFIED:
|
||||
return desktop32[row * desktopPitch + col];
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Access RGBA values at the same time
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||
|
||||
@@ -209,12 +290,11 @@ void Cursor::UpdateTexture()
|
||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||
{
|
||||
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 BYTE andMask = apiBuffer_[col / 8 + row * cursorImagePitch] & mask;
|
||||
const BYTE xorMask = apiBuffer_[col / 8 + (row + capturedImageHeight) * cursorImagePitch] & mask;
|
||||
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
|
||||
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
|
||||
output32[i] = (desktop32[y * desktopPitch + x] & andMask32) ^ xorMask32;
|
||||
output32[row * cursorImageWidth + col] = (getDesktop32(x, y) & andMask32) ^ xorMask32;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,13 +306,13 @@ void Cursor::UpdateTexture()
|
||||
{
|
||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||
{
|
||||
const int i = col + row * w0;
|
||||
const int j = col + row * p / sizeof(UINT);
|
||||
const int i = col + row * cursorImageWidth;
|
||||
const int j = col + row * cursorImagePitch / sizeof(UINT);
|
||||
|
||||
UINT mask = 0xFF000000 & buffer32[j];
|
||||
if (mask)
|
||||
{
|
||||
output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000;
|
||||
output32[i] = (getDesktop32(x, y) ^ buffer32[j]) | 0xFF000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -251,7 +331,7 @@ void Cursor::UpdateTexture()
|
||||
{
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
|
||||
for (int i = 0; i < w * h; ++i)
|
||||
for (int i = 0; i < cursorImageWidth * cursorImageHeight; ++i)
|
||||
{
|
||||
output32[i] = buffer32[i];
|
||||
}
|
||||
|
||||
@@ -28,6 +28,6 @@ void Debug::Finalize()
|
||||
Debug::Log("Stop");
|
||||
fs_.close();
|
||||
}
|
||||
Debug::SetLogFunc(nullptr);
|
||||
Debug::SetErrorFunc(nullptr);
|
||||
Debug::SetLogFunc(nullptr);
|
||||
Debug::SetErrorFunc(nullptr);
|
||||
}
|
||||
@@ -87,34 +87,34 @@ private:
|
||||
Flush(level);
|
||||
}
|
||||
|
||||
static void OutputTime()
|
||||
{
|
||||
auto t = time(nullptr);
|
||||
tm tm;
|
||||
localtime_s(&tm, &t);
|
||||
char buf[64];
|
||||
strftime(buf, 64, "%F %T", &tm);
|
||||
static void OutputTime()
|
||||
{
|
||||
auto t = time(nullptr);
|
||||
tm tm;
|
||||
localtime_s(&tm, &t);
|
||||
char buf[64];
|
||||
strftime(buf, 64, "%F %T", &tm);
|
||||
Output("[");;
|
||||
Output(buf);
|
||||
Output("]");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Log(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
Output("[uDD::Log]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
Output("[uDD::Log]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
_Log(Level::Log, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
|
||||
}
|
||||
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Error(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
Output("[uDD::Err]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
Output("[uDD::Err]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
_Log(Level::Error, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,94 +18,94 @@ Monitor::Monitor(int id)
|
||||
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
if (deskDupl_)
|
||||
{
|
||||
deskDupl_->Release();
|
||||
deskDupl_ = nullptr;
|
||||
}
|
||||
if (deskDupl_)
|
||||
{
|
||||
deskDupl_->Release();
|
||||
deskDupl_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Initialize(IDXGIOutput* output)
|
||||
{
|
||||
if (FAILED(output->GetDesc(&outputDesc_)))
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed.");
|
||||
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 (!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.");
|
||||
return;
|
||||
}
|
||||
if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_)))
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => GetDpiForMonitor() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
|
||||
switch (output1->DuplicateOutput(GetDevice().Get(), &deskDupl_))
|
||||
{
|
||||
case S_OK:
|
||||
{
|
||||
state_ = State::Available;
|
||||
Debug::Log("Monitor::Initialize() => OK.");
|
||||
Debug::Log(" ID : ", GetId());
|
||||
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
|
||||
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
|
||||
break;
|
||||
}
|
||||
{
|
||||
state_ = State::Available;
|
||||
Debug::Log("Monitor::Initialize() => OK.");
|
||||
Debug::Log(" ID : ", GetId());
|
||||
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
|
||||
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
state_ = State::InvalidArg;
|
||||
Debug::Error("Monitor::Initialize() => Invalid arguments.");
|
||||
break;
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,35 +123,35 @@ void Monitor::Render(UINT timeout)
|
||||
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;
|
||||
}
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
{
|
||||
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
Debug::Error("Monitor::Render() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
{
|
||||
Debug::Error("Monitor::Render() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -159,11 +159,11 @@ void Monitor::Render(UINT timeout)
|
||||
if (unityTexture_)
|
||||
{
|
||||
ID3D11Texture2D* texture;
|
||||
if (FAILED(resource.CopyTo(&texture)))
|
||||
{
|
||||
Debug::Error("Monitor::Render() => resource.As() failed.");
|
||||
return;
|
||||
}
|
||||
if (FAILED(resource.CopyTo(&texture)))
|
||||
{
|
||||
Debug::Error("Monitor::Render() => resource.As() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||
texture->GetDesc(&srcDesc);
|
||||
@@ -175,10 +175,10 @@ void Monitor::Render(UINT timeout)
|
||||
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);
|
||||
//width_ = srcDesc.Width;
|
||||
//height_ = srcDesc.Height;
|
||||
state_ = MonitorState::TextureSizeInconsistent;
|
||||
//SendMessageToUnity(Message::TextureSizeChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -296,11 +296,11 @@ int Monitor::GetDpiY() const
|
||||
|
||||
int Monitor::GetWidth() const
|
||||
{
|
||||
return width_;
|
||||
return width_;
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetHeight() const
|
||||
{
|
||||
return height_;
|
||||
return height_;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ enum class MonitorState
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
TextureSizeInconsistent = 7,
|
||||
TextureSizeInconsistent = 7,
|
||||
Unknown = 999,
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
private:
|
||||
int id_ = -1;
|
||||
UINT dpiX_ = -1, dpiY_ = -1;
|
||||
int width_ = -1, height_ = -1;
|
||||
int width_ = -1, height_ = -1;
|
||||
State state_ = State::NotSet;
|
||||
std::unique_ptr<Cursor> cursor_;
|
||||
IDXGIOutputDuplication* deskDupl_ = nullptr;
|
||||
|
||||
@@ -35,11 +35,11 @@ void MonitorManager::Initialize()
|
||||
|
||||
// Get factory
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
|
||||
{
|
||||
Debug::Error("MonitorManager::Initialize() => CreateDXGIFactory1() failed.");
|
||||
return;
|
||||
}
|
||||
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
|
||||
{
|
||||
Debug::Error("MonitorManager::Initialize() => CreateDXGIFactory1() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check all display adapters
|
||||
int id = 0;
|
||||
@@ -47,7 +47,7 @@ void MonitorManager::Initialize()
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
auto monitor = std::make_shared<Monitor>(id++);
|
||||
@@ -81,24 +81,24 @@ void MonitorManager::Reinitialize()
|
||||
bool MonitorManager::HasMonitorCountChanged() const
|
||||
{
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
|
||||
{
|
||||
Debug::Error("MonitorManager::CheckMonitorConnection() => CreateDXGIFactory1() failed.");
|
||||
return false;
|
||||
}
|
||||
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
|
||||
{
|
||||
Debug::Error("MonitorManager::CheckMonitorConnection() => CreateDXGIFactory1() failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
return monitors_.size() != id;
|
||||
return monitors_.size() != id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user