From 583af4ff4665c8b81e8e6b559dded842c334ba51 Mon Sep 17 00:00:00 2001 From: hecomi Date: Thu, 1 Dec 2016 22:29:52 +0900 Subject: [PATCH] Change the way to get pixels and finish the implementation of the APIs :tada: --- .../Examples/Scripts/GetPixels.cs | 15 -- .../Examples/Scripts/GetPixels.cs.meta | 12 - .../Examples/Scripts}/GetPixelsExample.cs | 6 +- .../Scripts}/GetPixelsExample.cs.meta | 0 .../Plugins/x86_64/uDesktopDuplication.dll | Bin 80896 -> 80384 bytes Assets/uDesktopDuplication/Scripts/Lib.cs | 6 +- Assets/uDesktopDuplication/Scripts/Manager.cs | 11 +- Assets/uDesktopDuplication/Scripts/Monitor.cs | 26 ++ .../uDesktopDuplication/Monitor.cpp | 228 +++++++++++------- .../uDesktopDuplication/Monitor.h | 12 +- .../uDesktopDuplication/MonitorManager.cpp | 12 - .../uDesktopDuplication/MonitorManager.h | 4 +- .../uDesktopDuplication/main.cpp | 12 +- ProjectSettings/ProjectSettings.asset | Bin 43789 -> 43789 bytes ProjectSettings/QualitySettings.asset | Bin 4736 -> 4756 bytes 15 files changed, 185 insertions(+), 159 deletions(-) delete mode 100644 Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs delete mode 100644 Assets/uDesktopDuplication/Examples/Scripts/GetPixels.cs.meta rename Assets/{ => uDesktopDuplication/Examples/Scripts}/GetPixelsExample.cs (93%) rename Assets/{ => uDesktopDuplication/Examples/Scripts}/GetPixelsExample.cs.meta (100%) 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 74c8f9fe73ae8027a3ea1415d7817b4b77c39f29..1d61bb89373f56ca34440d6e316a13a0dc81720c 100644 GIT binary patch delta 33856 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 delta 34296 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 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 c3cd3f2366a955b8f18a8394dbf8ad87669832d1..71fa213392708d6fbadf3361d512b7cad2a5c966 100644 GIT binary patch delta 16 YcmeCZ#?*U_X@l=vM#jy4bNBNC06lO9(EtDd delta 16 YcmeCZ#?*U_X@l=vMuyFPbNBNC06l63&;S4c diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 0e714bdb6238a05389aac751f3060d5a5513db5f..d6ee4c3355a3bbd1066661c9fa00ef886762c36a 100644 GIT binary patch delta 79 zcmZoroubOYz`!2Hz#uebBZm(=&lDyG27Lw){{Me-BKu;F&CCLhOsr?l_}IOhd{!)Mr6#8d JiLn4>831t-48;Hd