Change the way to get pixels and finish the implementation of the APIs 🎉
This commit is contained in:
@@ -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 () {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc0250b1a79f38b48bfddf1e05bda638
|
||||
timeCreated: 1480420057
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+3
-3
@@ -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<Renderer>().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;
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::mutex> lock(mutex_);
|
||||
|
||||
ComPtr<ID3D11DeviceContext> 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<int>(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<DXGI_MODE_ROTATION>(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<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(textureForGetPixels_.Get(), texture);
|
||||
}
|
||||
|
||||
ComPtr<IDXGISurface> 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<ID3D11Texture2D> 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<std::mutex> lock(mutex_);
|
||||
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, ddaTexture_.Get(), 0, &box);
|
||||
|
||||
ComPtr<IDXGISurface> 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<UINT*>(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_;
|
||||
}
|
||||
@@ -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<ID3D11Texture2D> ddaTexture_;
|
||||
DXGI_OUTPUT_DESC outputDesc_;
|
||||
MONITORINFOEX monitorInfo_;
|
||||
Buffer<BYTE> metaData_;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> textureForGetPixels_;
|
||||
Buffer<BYTE> bufferForGetPixels_;
|
||||
UINT moveRectSize_ = 0;
|
||||
UINT dirtyRectSize_ = 0;;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
@@ -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<int>(monitors_.size());
|
||||
|
||||
@@ -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<std::shared_ptr<Monitor>> monitors_;
|
||||
std::shared_ptr<Cursor> cursor_ = std::make_shared<Cursor>();
|
||||
int cursorMonitorId_ = -1;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
IUnityInterfaces* g_unity = nullptr;
|
||||
std::unique_ptr<MonitorManager> g_manager;
|
||||
std::queue<Message> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user