diff --git a/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs b/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs deleted file mode 100644 index 61e8bd0..0000000 --- a/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs +++ /dev/null @@ -1,15 +0,0 @@ -using UnityEngine; -using System.Collections; - -public class GetPixels : MonoBehaviour { - - // Use this for initialization - void Start () { - - } - - // Update is called once per frame - void Update () { - - } -} diff --git a/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs.meta b/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs.meta deleted file mode 100644 index e390621..0000000 --- a/Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: bc0250b1a79f38b48bfddf1e05bda638 -timeCreated: 1480420057 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GetPixelsExample.cs b/Assets/uDesktopDuplication/Examples/Scripts/GetPixelsExample.cs similarity index 93% rename from Assets/GetPixelsExample.cs rename to Assets/uDesktopDuplication/Examples/Scripts/GetPixelsExample.cs index 9172ed8..a7d33b0 100644 --- a/Assets/GetPixelsExample.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/GetPixelsExample.cs @@ -14,15 +14,15 @@ public class GetPixelsExample : MonoBehaviour void Start() { - // must be called (performance will be slightly down). - uDesktopDuplication.Manager.useGetPixels = true; - texture = new Texture2D(width, height, TextureFormat.ARGB32, false); GetComponent().material.mainTexture = texture; } void Update() { + // must be called (performance will be slightly down). + uDesktopDuplication.Manager.primary.useGetPixels = true; + var monitor = uddTexture.monitor; if (!monitor.hasBeenUpdated) return; diff --git a/Assets/GetPixelsExample.cs.meta b/Assets/uDesktopDuplication/Examples/Scripts/GetPixelsExample.cs.meta similarity index 100% rename from Assets/GetPixelsExample.cs.meta rename to Assets/uDesktopDuplication/Examples/Scripts/GetPixelsExample.cs.meta diff --git a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index 74c8f9f..1d61bb8 100644 Binary files a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll and b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll differ diff --git a/Assets/uDesktopDuplication/Scripts/Lib.cs b/Assets/uDesktopDuplication/Scripts/Lib.cs index b39e726..8163559 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -172,7 +172,7 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern bool HasBeenUpdated(int id); [DllImport("uDesktopDuplication")] - public static extern bool UseGetPixels(bool use); + public static extern bool UseGetPixels(int id, bool use); public static string GetName(int id) { @@ -216,10 +216,6 @@ public static class Lib public static bool GetPixels(int id, Color32[] colors, int x, int y, int width, int height) { - if (!Mathf.IsPowerOfTwo(width) || !Mathf.IsPowerOfTwo(height)) { - Debug.LogErrorFormat("width and height must be power of two."); - return false; - } if (colors.Length < width * height) { Debug.LogErrorFormat("colors is small.", id, x, y, width, height); return false; diff --git a/Assets/uDesktopDuplication/Scripts/Manager.cs b/Assets/uDesktopDuplication/Scripts/Manager.cs index 5cff3b3..aee4e7b 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -52,14 +52,6 @@ public class Manager : MonoBehaviour } } - static public bool useGetPixels - { - set - { - Lib.UseGetPixels(value); - } - } - [Tooltip("Debug mode is not applied while running.")] [SerializeField] DebugMode debugMode = DebugMode.File; @@ -169,7 +161,8 @@ public class Manager : MonoBehaviour state == MonitorState.NotSet || state == MonitorState.AccessLost || state == MonitorState.AccessDenied || - state == MonitorState.SessionDisconnected + state == MonitorState.SessionDisconnected || + state == MonitorState.Unknown ) { reinitializeNeeded = true; break; diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index 07f0ceb..d6f89fe 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -237,6 +237,20 @@ public class Monitor get { return Lib.HasBeenUpdated(id); } } + bool useGetPixels_ = false; + public bool useGetPixels + { + get + { + return useGetPixels_; + } + set + { + useGetPixels_ = value; + Lib.UseGetPixels(id, value); + } + } + public bool shouldBeUpdated { get; @@ -325,16 +339,28 @@ public class Monitor public Color32[] GetPixels(int x, int y, int width, int height) { + if (!useGetPixels_) { + Debug.LogErrorFormat("Please set Monitor[{0}].useGetPixels as true.", id); + return null; + } return Lib.GetPixels(id, x, y, width, height); } public bool GetPixels(Color32[] colors, int x, int y, int width, int height) { + if (!useGetPixels_) { + Debug.LogErrorFormat("Please set Monitor[{0}].useGetPixels as true.", id); + return false; + } return Lib.GetPixels(id, colors, x, y, width, height); } public Color32 GetPixel(int x, int y) { + if (!useGetPixels_) { + Debug.LogErrorFormat("Please set Monitor[{0}].useGetPixels as true.", id); + return Color.black; + } return Lib.GetPixel(id, x, y); } } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 5e25881..95fa7ee 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -162,16 +162,16 @@ void Monitor::Render(UINT timeout) return; } + ID3D11Texture2D* texture; + if (FAILED(resource.CopyTo(&texture))) + { + Debug::Error("Monitor::Render() => resource.As() failed."); + return; + } + // Get texture if (unityTexture_) { - ID3D11Texture2D* texture; - if (FAILED(resource.CopyTo(&texture))) - { - Debug::Error("Monitor::Render() => resource.As() failed."); - return; - } - D3D11_TEXTURE2D_DESC srcDesc, dstDesc; texture->GetDesc(&srcDesc); unityTexture_->GetDesc(&dstDesc); @@ -193,22 +193,6 @@ void Monitor::Render(UINT timeout) GetDevice()->GetImmediateContext(&context); context->CopyResource(unityTexture_, texture); } - - { - std::lock_guard lock(mutex_); - - ComPtr context; - if (!ddaTexture_) - { - if (FAILED(GetDevice()->CreateTexture2D(&dstDesc, nullptr, &ddaTexture_))) - { - Debug::Error("Monitor::Render() => GetDevice()->CreateTexture2D() failed."); - return; - } - } - GetDevice()->GetImmediateContext(&context); - context->CopyResource(ddaTexture_.Get(), texture); - } } UpdateMetadata(frameInfo); @@ -223,6 +207,11 @@ void Monitor::Render(UINT timeout) UpdateCursor(frameInfo); } + if (UseGetPixels()) + { + CopyTextureFromGpuToCpu(texture); + } + hr = deskDupl_->ReleaseFrame(); if (FAILED(hr)) { @@ -399,6 +388,12 @@ bool Monitor::IsPrimary() const } +bool Monitor::HasBeenUpdated() const +{ + return hasBeenUpdated_; +} + + int Monitor::GetLeft() const { return static_cast(outputDesc_.DesktopCoordinates.left); @@ -477,17 +472,94 @@ RECT* Monitor::GetDirtyRects() const } -bool Monitor::GetPixels(UINT* ptr, int x, int y, int width, int height) +void Monitor::UseGetPixels(bool use) { - if (!GetMonitorManager()->UseGetPixels()) + useGetPixels_ = use; +} + + +bool Monitor::UseGetPixels() const +{ + return useGetPixels_; +} + + +void Monitor::CopyTextureFromGpuToCpu(ID3D11Texture2D* texture) +{ + const auto monitorRot = static_cast(GetRotation()); + const auto monitorWidth = GetWidth(); + const auto monitorHeight = GetHeight(); + 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; + + if (!textureForGetPixels_) + { + D3D11_TEXTURE2D_DESC desc; + desc.Width = desktopImageWidth; + desc.Height = desktopImageHeight; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + + if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &textureForGetPixels_))) + { + Debug::Error("Monitor::CopyTextureFromGpuToCpu() => GetDevice()->CreateTexture2D() failed."); + return; + } + } + + { + ComPtr context; + GetDevice()->GetImmediateContext(&context); + context->CopyResource(textureForGetPixels_.Get(), texture); + } + + ComPtr surface; + if (FAILED(textureForGetPixels_.As(&surface))) + { + Debug::Error("Monitor::CopyTextureFromGpuToCpu() => texture.As() failed."); + return; + } + + DXGI_MAPPED_RECT mappedSurface; + if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ))) + { + Debug::Error("Monitor::CopyTextureFromGpuToCpu() => surface->Map() failed."); + return; + } + + const UINT size = desktopImageWidth * desktopImageHeight * sizeof(UINT); + bufferForGetPixels_.ExpandIfNeeded(size); + std::memcpy(bufferForGetPixels_.Get(), mappedSurface.pBits, size); + + if (FAILED(surface->Unmap())) + { + Debug::Error("Monitor::CopyTextureFromGpuToCpu() => surface->Unmap() failed."); + return; + } +} + + +bool Monitor::GetPixels(BYTE* output, int x, int y, int width, int height) +{ + if (!UseGetPixels()) { Debug::Error("Monitor::GetPixels() => UseGetPixels(true) must have been called when you want to use GetPixels()."); return false; } - if (!ddaTexture_) + if (!bufferForGetPixels_) { - Debug::Error("Monitor::GetPixels() => texture is not set."); + Debug::Error("Monitor::GetPixels() => CopyTextureFromGpuToCpu() has not been called yet."); return false; } @@ -500,6 +572,7 @@ bool Monitor::GetPixels(UINT* ptr, int x, int y, int width, int height) const auto desktopImageWidth = !isVertical ? monitorWidth : monitorHeight; const auto desktopImageHeight = !isVertical ? monitorHeight : monitorWidth; + // check area in destop coorinates. int left, top, right, bottom; switch (monitorRot) @@ -554,75 +627,46 @@ bool Monitor::GetPixels(UINT* ptr, int x, int y, int width, int height) return false; } - D3D11_BOX box; - box.left = left; - box.top = top; - box.front = 0; - box.right = right; - box.bottom = bottom; - box.back = 1; - - // Create texture for capturing desktop image - ComPtr texture; - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - - if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) - { - Debug::Error("Monitor::GetPixels() => GetDevice()->CreateTexture2D() failed."); - return false; - } - - std::lock_guard lock(mutex_); - - ComPtr context; - GetDevice()->GetImmediateContext(&context); - context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, ddaTexture_.Get(), 0, &box); - - ComPtr surface; - if (FAILED(texture.As(&surface))) - { - Debug::Error("Monitor::GetPixels() => texture.As() failed."); - return false; - } - - DXGI_MAPPED_RECT mappedSurface; - if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ))) - { - Debug::Error("Monitor::GetPixels() => surface->Map() failed."); - return false; - } - - const auto colors = reinterpret_cast(mappedSurface.pBits); - std::memcpy(ptr, colors, width * height * sizeof(UINT)); - std::reverse(&ptr[0], &ptr[width * height - 1]); for (int row = 0; row < height; ++row) { - const auto start = width * row; - const auto end = width * (row + 1) - 1; - std::reverse(&ptr[start], &ptr[end]); - } + for (int col = 0; col < width; ++col) + { + int inRow, inCol; + switch (monitorRot) + { + case DXGI_MODE_ROTATION_ROTATE90: + inCol = left + row; + inRow = bottom - 1 - col; + break; + case DXGI_MODE_ROTATION_ROTATE180: + inCol = right - 1 - col; + inRow = bottom - 1 - row; + break; + case DXGI_MODE_ROTATION_ROTATE270: + inCol = right - 1 - row; + inRow = top + col; + break; + case DXGI_MODE_ROTATION_IDENTITY: + case DXGI_MODE_ROTATION_UNSPECIFIED: + default: + inCol = left + col; + inRow = top + row; + break; + } + const auto inIndex = 4 * (inRow * desktopImageWidth + inCol); - if (FAILED(surface->Unmap())) - { - Debug::Error("Monitor::GetPixels() => surface->Unmap() failed."); - return false; + const auto outRow = height - 1 - row; + const auto outCol = col; + const auto outIndex = 4 * (outRow * width + outCol); + + + // BGRA -> RGBA + output[outIndex + 0] = bufferForGetPixels_[inIndex + 2]; + output[outIndex + 1] = bufferForGetPixels_[inIndex + 1]; + output[outIndex + 2] = bufferForGetPixels_[inIndex + 0]; + output[outIndex + 3] = bufferForGetPixels_[inIndex + 3]; + } } return true; } - -bool Monitor::HasBeenUpdated() const -{ - return hasBeenUpdated_; -} \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h index 18443c8..ecba0ab 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h @@ -38,6 +38,7 @@ public: ID3D11Texture2D* GetUnityTexture() const; void GetName(char* buf, int len) const; bool IsPrimary() const; + bool HasBeenUpdated() const; int GetLeft() const; int GetRight() const; int GetTop() const; @@ -52,27 +53,30 @@ public: DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const; int GetDirtyRectCount() const; RECT* GetDirtyRects() const; - bool GetPixels(UINT* ptr, int x, int y, int width, int height); - bool HasBeenUpdated() const; + void UseGetPixels(bool use); + bool UseGetPixels() const; + bool GetPixels(BYTE* output, int x, int y, int width, int height); private: void UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); void UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); void UpdateMoveRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); void UpdateDirtyRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); + void CopyTextureFromGpuToCpu(ID3D11Texture2D* texture); int id_ = -1; UINT dpiX_ = -1, dpiY_ = -1; int width_ = -1, height_ = -1; bool hasBeenUpdated_ = false; + bool useGetPixels_ = false; State state_ = State::NotSet; IDXGIOutputDuplication* deskDupl_ = nullptr; ID3D11Texture2D* unityTexture_ = nullptr; - Microsoft::WRL::ComPtr ddaTexture_; DXGI_OUTPUT_DESC outputDesc_; MONITORINFOEX monitorInfo_; Buffer metaData_; + Microsoft::WRL::ComPtr textureForGetPixels_; + Buffer bufferForGetPixels_; UINT moveRectSize_ = 0; UINT dirtyRectSize_ = 0;; - mutable std::mutex mutex_; }; \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp index 475d8a2..f7a12f8 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp @@ -140,18 +140,6 @@ int MonitorManager::GetTimeout() const } -void MonitorManager::UseGetPixels(bool use) -{ - useGetPixels_ = use; -} - - -bool MonitorManager::UseGetPixels() const -{ - return useGetPixels_; -} - - int MonitorManager::GetMonitorCount() const { return static_cast(monitors_.size()); diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h index e4f3b62..4c2f383 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h @@ -32,8 +32,6 @@ public: void Update(); void SetTimeout(int timeout); int GetTimeout() const; - void UseGetPixels(bool use); - bool UseGetPixels() const; // Getters from Unity public: @@ -43,7 +41,7 @@ public: private: int timeout_ = 10; - bool useGetPixels_ = false; + bool enableTextureCopyFromGpuToCpu_ = false; std::vector> monitors_; std::shared_ptr cursor_ = std::make_shared(); int cursorMonitorId_ = -1; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index f35916e..f686d25 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -21,6 +21,7 @@ IUnityInterfaces* g_unity = nullptr; std::unique_ptr g_manager; std::queue g_messages; +ID3D11DeviceContext* g_deviceContextForMainThread = nullptr; extern "C" @@ -393,12 +394,12 @@ extern "C" return nullptr; } - UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API GetPixels(int id, UINT* ptr, int x, int y, int width, int height) + UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API GetPixels(int id, BYTE* output, int x, int y, int width, int height) { if (!g_manager) return nullptr; if (auto monitor = g_manager->GetMonitor(id)) { - return monitor->GetPixels(ptr, x, y, width, height); + return monitor->GetPixels(output, x, y, width, height); } return false; } @@ -413,9 +414,12 @@ extern "C" return false; } - UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UseGetPixels(bool use) + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UseGetPixels(int id, bool use) { if (!g_manager) return; - g_manager->UseGetPixels(use); + if (auto monitor = g_manager->GetMonitor(id)) + { + return monitor->UseGetPixels(use); + } } } \ No newline at end of file diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index c3cd3f2..71fa213 100644 Binary files a/ProjectSettings/ProjectSettings.asset and b/ProjectSettings/ProjectSettings.asset differ diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 0e714bd..d6ee4c3 100644 Binary files a/ProjectSettings/QualitySettings.asset and b/ProjectSettings/QualitySettings.asset differ