upload cursor texture in native plugin.

This commit is contained in:
hecomi
2016-11-20 22:35:52 +09:00
parent 49aef432e7
commit ddbfad6e95
13 changed files with 181 additions and 153 deletions
@@ -83,7 +83,7 @@ public:
return value_ != nullptr;
}
T operator [](UINT index) const
const T operator [](UINT index) const
{
if (index >= size_)
{
@@ -93,6 +93,16 @@ public:
return value_[index];
}
T& operator [](UINT index)
{
if (index >= size_)
{
Debug::Error("Array index out of range: ", index, size_);
return value_[0];
}
return value_[index];
}
private:
std::unique_ptr<T[]> value_;
UINT size_ = 0;
@@ -79,33 +79,43 @@ void Cursor::UpdateTexture()
return;
}
// Check desktop texure
if (monitor_->GetUnityTexture() == nullptr)
{
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
return;
}
// 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();
// Captured area
// Captured size
auto capturedImageWidth = cursorImageWidth;
auto capturedImageHeight = cursorImageHeight;
// Convert the buffer given by API into BGRA32
const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4;
bgra32Buffer_.ExpandIfNeeded(bgraBufferSize);
bgraBuffer_.ExpandIfNeeded(bgraBufferSize);
// Check buffers
if (!bgra32Buffer_ || !apiBuffer_)
if (!bgraBuffer_ || !apiBuffer_)
{
return;
}
// If masked, copy the desktop image and merge it with masked image.
if (isMono || isColorMask)
// Calculate information to capture desktop image under cursor.
D3D11_BOX box;
const auto monitorRot = static_cast<DXGI_MODE_ROTATION>(monitor_->GetRotation());
auto colMin = 0;
auto colMax = cursorImageWidth;
auto rowMin = 0;
auto rowMax = cursorImageHeight;
{
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;
@@ -114,10 +124,6 @@ void Cursor::UpdateTexture()
auto x = x_;
auto y = y_;
auto colMin = 0;
auto colMax = cursorImageWidth;
auto rowMin = 0;
auto rowMax = cursorImageHeight;
if (x < 0)
{
@@ -142,7 +148,6 @@ void Cursor::UpdateTexture()
rowMax = capturedImageHeight;
}
D3D11_BOX box;
box.front = 0;
box.back = 1;
@@ -196,13 +201,11 @@ void Cursor::UpdateTexture()
"(", desktopImageWidth, ", ", desktopImageHeight, ")");
return;
}
}
if (monitor_->GetUnityTexture() == nullptr)
{
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
return;
}
// Create texture
ComPtr<ID3D11Texture2D> texture;
{
D3D11_TEXTURE2D_DESC desc;
desc.Width = capturedImageWidth;
desc.Height = capturedImageHeight;
@@ -216,83 +219,89 @@ void Cursor::UpdateTexture()
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ComPtr<ID3D11Texture2D> texture;
if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
{
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
return;
}
}
// Copy desktop image to the texture
{
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
}
// Get mapped surface
ComPtr<IDXGISurface> surface;
if (FAILED(texture.As(&surface)))
{
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
return;
}
DXGI_MAPPED_RECT mappedSurface;
if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ)))
{
Debug::Error("Cursor::UpdateTexture() => surface->Map() failed.");
return;
}
// Finally, get the desktop texture under the mouse cursor.
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)
{
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
case DXGI_MODE_ROTATION_ROTATE90:
return desktop32[(capturedImageWidth - 1 - col) * desktopPitch + row];
case DXGI_MODE_ROTATION_ROTATE180:
return desktop32[(capturedImageHeight - 1 - row) * desktopPitch + (capturedImageWidth - 1 - col)];
case DXGI_MODE_ROTATION_ROTATE270:
return desktop32[col * desktopPitch + (capturedImageHeight - 1 - row)];
case DXGI_MODE_ROTATION_IDENTITY:
case DXGI_MODE_ROTATION_UNSPECIFIED:
return desktop32[row * desktopPitch + col];
}
};
ComPtr<IDXGISurface> surface;
if (FAILED(texture.As(&surface)))
// Access RGBA values at the same time
Buffer<BYTE> output;
output.ExpandIfNeeded(bgraBuffer_.Size());
auto output32 = output.As<UINT>();
switch (GetType())
{
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
{
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
return;
}
DXGI_MAPPED_RECT mappedSurface;
if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ)))
{
Debug::Error("Cursor::UpdateTexture() => surface->Map() failed.");
return;
}
// Finally, get the texture behind the mouse cursor.
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)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
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());
if (isMono)
{
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = col + row * cursorImageWidth;
BYTE mask = 0b10000000 >> (col % 8);
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[row * cursorImageWidth + col] = (getDesktop32(x, y) & andMask32) ^ xorMask32;
output32[i] = (getDesktop32(x, y) & andMask32) ^ xorMask32;
}
}
break;
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
{
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.Get());
const auto buffer32 = apiBuffer_.As<UINT>();
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = col + row * cursorImageWidth;
const int j = col + row * cursorImagePitch / sizeof(UINT);
@@ -308,28 +317,92 @@ void Cursor::UpdateTexture()
}
}
}
break;
}
if (FAILED(surface->Unmap()))
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
{
return;
const auto buffer32 = apiBuffer_.As<UINT>();
auto output32 = bgraBuffer_.As<UINT>();
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = 4 * (col + row * cursorImageWidth);
const auto desktop32 = getDesktop32(x, y);
const auto desktop = (BYTE*)(&desktop32);
const auto desktopB = desktop[0];
const auto desktopG = desktop[1];
const auto desktopR = desktop[2];
const auto desktopA = desktop[3];
const auto cursorB = apiBuffer_[i + 0];
const auto cursorG = apiBuffer_[i + 1];
const auto cursorR = apiBuffer_[i + 2];
const auto cursorA = apiBuffer_[i + 3];
const auto a0 = cursorA / 255.f;
const auto a1 = 1.f - a0;
output[i + 0] = static_cast<BYTE>(cursorB * a0 + desktopB * a1);
output[i + 1] = static_cast<BYTE>(cursorG * a0 + desktopG * a1);
output[i + 2] = static_cast<BYTE>(cursorR * a0 + desktopR * a1);
output[i + 3] = desktopA;
}
}
break;
}
default:
{
Debug::Error("Cursor::UpdateTexture() => Unknown cursor type");
break;
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
// Rotation
auto bgraBuffer32 = bgraBuffer_.As<UINT>();
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.Get());
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.Get());
for (int i = 0; i < cursorImageWidth * cursorImageHeight; ++i)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
output32[i] = buffer32[i];
const auto i = col + row * cursorImageWidth;
switch (monitorRot)
{
case DXGI_MODE_ROTATION_ROTATE90:
bgraBuffer32[i] = output32[col * cursorImageHeight + (cursorImageHeight - 1 - row)];
break;
case DXGI_MODE_ROTATION_ROTATE180:
bgraBuffer32[i] = output32[(cursorImageHeight - 1 - row) * cursorImageWidth + (cursorImageWidth - 1 - col)];
break;
case DXGI_MODE_ROTATION_ROTATE270:
bgraBuffer32[i] = output32[(cursorImageWidth - 1 - col) * cursorImageHeight + row];
break;
case DXGI_MODE_ROTATION_IDENTITY:
case DXGI_MODE_ROTATION_UNSPECIFIED:
bgraBuffer32[i] = output32[i];
break;
}
}
}
{
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(monitor_->GetUnityTexture(), 0, &box, bgraBuffer_.Get(), GetWidth() * 4, 0);
}
if (FAILED(surface->Unmap()))
{
Debug::Error("Cursor::UpdateTexture() => surface->Unmap() failed.");
return;
}
}
void Cursor::GetTexture(ID3D11Texture2D* texture)
{
if (!bgra32Buffer_)
if (!bgraBuffer_)
{
Debug::Error("Cursor::GetTexture() => bgra32Buffer is null.");
return;
@@ -356,7 +429,7 @@ void Cursor::GetTexture(ID3D11Texture2D* texture)
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.Get(), GetWidth() * 4, 0);
context->UpdateSubresource(texture, 0, nullptr, bgraBuffer_.Get(), GetWidth() * 4, 0);
}
@@ -32,7 +32,7 @@ private:
int x_ = -1;
int y_ = -1;
Buffer<BYTE> apiBuffer_;
Buffer<BYTE> bgra32Buffer_;
Buffer<BYTE> bgraBuffer_;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
LARGE_INTEGER timestamp_;
};
@@ -112,10 +112,11 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>