refactoring.

This commit is contained in:
hecomi
2016-11-28 02:30:09 +09:00
parent 67c90073d9
commit 87557ed5ff
3 changed files with 192 additions and 213 deletions
@@ -40,8 +40,8 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame
return; return;
} }
apiBuffer_.ExpandIfNeeded(frameInfo.PointerShapeBufferSize); buffer_.ExpandIfNeeded(frameInfo.PointerShapeBufferSize);
if (!apiBuffer_) if (!buffer_)
{ {
return; return;
} }
@@ -50,15 +50,15 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame
UINT bufferSize; UINT bufferSize;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
const auto hr = monitor->GetDeskDupl()->GetFramePointerShape( const auto hr = monitor->GetDeskDupl()->GetFramePointerShape(
apiBuffer_.Size(), buffer_.Size(),
apiBuffer_.Get(), buffer_.Get(),
&bufferSize, &bufferSize,
&shapeInfo); &shapeInfo);
if (FAILED(hr)) if (FAILED(hr))
{ {
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed."); Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
apiBuffer_.Reset(); buffer_.Reset();
return; return;
} }
@@ -76,137 +76,143 @@ void Cursor::Draw(Monitor* monitor)
} }
// Cursor information // Cursor information
const auto cursorImageWidth = GetWidth(); const auto cursorImageWidth = GetWidth();
const auto cursorImageHeight = GetHeight(); const auto cursorImageHeight = GetHeight();
const auto cursorImagePitch = GetPitch(); const auto cursorImagePitch = GetPitch();
// Captured size // Monitor orientation
auto capturedImageWidth = cursorImageWidth; const auto monitorRot = static_cast<DXGI_MODE_ROTATION>(monitor->GetRotation());
auto capturedImageHeight = cursorImageHeight; const auto isMonitorPortrait =
monitorRot == DXGI_MODE_ROTATION_ROTATE90 ||
monitorRot == DXGI_MODE_ROTATION_ROTATE270;
// Captured size (desktop cooridinates).
auto capturedImageWidth = !isMonitorPortrait ? cursorImageWidth : cursorImageHeight;
auto capturedImageHeight = !isMonitorPortrait ? cursorImageHeight : cursorImageWidth;
// Convert the buffer given by API into BGRA32 // Convert the buffer given by API into BGRA32
const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4; const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4;
bgraBuffer_.ExpandIfNeeded(bgraBufferSize); bgraBuffer_.ExpandIfNeeded(bgraBufferSize);
// Check buffers // Check buffers
if (!bgraBuffer_ || !apiBuffer_) if (!bgraBuffer_ || !buffer_)
{ {
return; return;
} }
// Calculate information to capture desktop image under cursor. // Desktop size
D3D11_BOX box; const int monitorWidth = monitor->GetWidth();
const auto monitorRot = static_cast<DXGI_MODE_ROTATION>(monitor->GetRotation()); const int monitorHeight = monitor->GetHeight();
auto colMin = 0; const int desktopImageWidth = !isMonitorPortrait ? monitorWidth : monitorHeight;
auto colMax = cursorImageWidth; const int desktopImageHeight = !isMonitorPortrait ? monitorHeight : monitorWidth;
auto rowMin = 0;
auto rowMax = cursorImageHeight;
// x_, y_ are cooridinates in rotated monitor.
// desktopX, desktopY are coordinates in captured desktop image (always landscape).
int desktopX, desktopY;
switch (monitorRot)
{ {
const auto monitorWidth = monitor->GetWidth(); case DXGI_MODE_ROTATION_ROTATE90:
const auto monitorHeight = monitor->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;
auto x = x_;
auto y = y_;
if (x < 0)
{ {
x = 0; desktopX = y_;
capturedImageWidth = cursorImageWidth + x_; desktopY = (desktopImageHeight - 1) - x_ - cursorImageWidth;
colMin = cursorImageWidth - capturedImageWidth; break;
} }
if (x + capturedImageWidth >= monitorWidth) case DXGI_MODE_ROTATION_ROTATE180:
{ {
capturedImageWidth = monitorWidth - x_; desktopX = (desktopImageWidth - 1) - x_ - cursorImageWidth;
colMax = capturedImageWidth; desktopY = (desktopImageHeight - 1) - y_ - cursorImageHeight;
break;
} }
if (y < 0) case DXGI_MODE_ROTATION_ROTATE270:
{ {
y = 0; desktopX = (desktopImageWidth - 1) - y_ - cursorImageHeight;
capturedImageHeight = cursorImageHeight + y_; desktopY = x_;
rowMin = cursorImageHeight - capturedImageHeight; break;
} }
if (y + capturedImageHeight >= monitorHeight) case DXGI_MODE_ROTATION_IDENTITY:
case DXGI_MODE_ROTATION_UNSPECIFIED:
default:
{ {
capturedImageHeight = monitorHeight - y_; desktopX = x_;
rowMax = capturedImageHeight; desktopY = y_;
} break;
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;
} }
} }
// Create texture // Calculate information to capture desktop image under cursor.
int cursorOffsetX = 0;
int cursorOffsetY = 0;
int capturedImageLeft = desktopX;
int capturedImageTop = desktopY;
int capturedImageRight = desktopX + capturedImageWidth;
int capturedImageBottom = desktopY + capturedImageHeight;
if (capturedImageLeft < 0)
{
capturedImageWidth -= -desktopX;
cursorOffsetX = -desktopX;
capturedImageLeft = 0;
}
if (capturedImageRight >= desktopImageWidth)
{
capturedImageWidth -= capturedImageRight - desktopImageWidth;
capturedImageRight = desktopImageWidth - 1;
}
if (capturedImageTop < 0)
{
capturedImageHeight -= -desktopY;
cursorOffsetY = -desktopY;
capturedImageTop = 0;
}
if (capturedImageBottom >= monitorHeight)
{
capturedImageHeight -= capturedImageBottom - desktopImageHeight;
capturedImageBottom = desktopImageHeight - 1;
}
// Check if box is inner desktop area
if (capturedImageLeft < 0 ||
capturedImageTop < 0 ||
capturedImageRight > desktopImageWidth ||
capturedImageBottom > desktopImageHeight)
{
Debug::Error("Cursor::UpdateTexture() => box is out of area.");
Debug::Error(
" ",
"(", capturedImageLeft, ", ", capturedImageTop, ")",
" ~ (", capturedImageRight, ", ", capturedImageBottom, ") > ",
"(", desktopImageWidth, ", ", desktopImageHeight, ")");
return;
}
D3D11_BOX capturedImageArea
{
static_cast<UINT>(capturedImageLeft),
static_cast<UINT>(capturedImageTop),
0,
static_cast<UINT>(capturedImageRight),
static_cast<UINT>(capturedImageBottom),
1
};
// Create texture for capturing desktop image
ComPtr<ID3D11Texture2D> texture; ComPtr<ID3D11Texture2D> texture;
{ {
D3D11_TEXTURE2D_DESC desc; D3D11_TEXTURE2D_DESC desc;
desc.Width = capturedImageWidth; desc.Width = capturedImageWidth;
desc.Height = capturedImageHeight; desc.Height = capturedImageHeight;
desc.MipLevels = 1; desc.MipLevels = 1;
desc.ArraySize = 1; desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1; desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0; desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING; desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0; desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0; desc.MiscFlags = 0;
if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
{ {
@@ -219,14 +225,14 @@ void Cursor::Draw(Monitor* monitor)
{ {
ComPtr<ID3D11DeviceContext> context; ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context); GetDevice()->GetImmediateContext(&context);
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor->GetUnityTexture(), 0, &box); context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor->GetUnityTexture(), 0, &capturedImageArea);
} }
// Get mapped surface // Get mapped surface to access pixels in CPU
ComPtr<IDXGISurface> surface; ComPtr<IDXGISurface> surface;
if (FAILED(texture.As(&surface))) if (FAILED(texture.As(&surface)))
{ {
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed."); Debug::Error("Cursor::UpdateTexture() => texture.As() failed.");
return; return;
} }
@@ -241,135 +247,108 @@ void Cursor::Draw(Monitor* monitor)
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits); const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT); const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
// Take the monitor orientation into consideration. // Rotate cursor image to match the monitor orientation
const auto getDesktop32 = [&](int col, int row) Buffer<BYTE> rotatedBuffer_;
rotatedBuffer_.ExpandIfNeeded(buffer_.Size());
for (int y = 0; y < capturedImageHeight; ++y)
{ {
switch (monitorRot) for (int x = 0; x < capturedImageWidth; ++x)
{ {
case DXGI_MODE_ROTATION_ROTATE90: // Cursor coordinates
return desktop32[(capturedImageWidth - 1 - col) * desktopPitch + row]; int cursorX, cursorY;
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:
default:
return desktop32[row * desktopPitch + col];
}
};
Buffer<BYTE> output; switch (monitorRot)
output.ExpandIfNeeded(bgraBuffer_.Size());
// Access RGBA values at the same time
auto output32 = output.As<UINT>();
switch (GetType())
{
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
{
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{ {
for (int col = colMin, x = 0; col < colMax; ++col, ++x) case DXGI_MODE_ROTATION_ROTATE90:
{ {
const int i = col + row * cursorImageWidth; cursorX = (cursorImageWidth - 1) - (y + cursorOffsetY);
cursorY = (x + cursorOffsetX);
BYTE mask = 0b10000000 >> (col % 8); break;
const BYTE andMask = apiBuffer_[col / 8 + row * cursorImagePitch] & mask; }
const BYTE xorMask = apiBuffer_[col / 8 + (row + cursorImageHeight) * cursorImagePitch] & mask; case DXGI_MODE_ROTATION_ROTATE180:
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000; {
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000; cursorX = (cursorImageWidth - 1) - (x + cursorOffsetX);
cursorY = (cursorImageHeight - 1) - (y + cursorOffsetY);
output32[i] = (getDesktop32(x, y) & andMask32) ^ xorMask32; break;
}
case DXGI_MODE_ROTATION_ROTATE270:
{
cursorX = (y + cursorOffsetY);
cursorY = (cursorImageHeight - 1) - (x + cursorOffsetX);
break;
}
case DXGI_MODE_ROTATION_IDENTITY:
case DXGI_MODE_ROTATION_UNSPECIFIED:
default:
{
cursorX = (x + cursorOffsetX);
cursorY = (y + cursorOffsetY);
break;
} }
} }
break;
}
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
{
const auto buffer32 = apiBuffer_.As<UINT>();
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y) const auto outputIndex = y * capturedImageWidth + x;
const auto desktopIndex = y * desktopPitch + x;
const auto cursorIndex = cursorY * cursorImageWidth + cursorX;
const auto buffer32 = buffer_.As<UINT>();
auto output32 = bgraBuffer_.As<UINT>();
switch (GetType())
{ {
for (int col = colMin, x = 0; col < colMax; ++col, ++x) case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
{ {
const int i = col + row * cursorImageWidth; BYTE mask = 0b10000000 >> (cursorX % 8);
const int j = col + row * cursorImagePitch / sizeof(UINT); const BYTE andMask = buffer_[cursorX / 8 + cursorY * cursorImagePitch] & mask;
const BYTE xorMask = buffer_[cursorX / 8 + (cursorY + cursorImageHeight) * cursorImagePitch] & mask;
UINT mask = 0xFF000000 & buffer32[j]; const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
output32[outputIndex] = (desktop32[desktopIndex] & andMask32) ^ xorMask32;
break;
}
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
{
UINT mask = 0xFF000000 & buffer32[cursorIndex];
if (mask) if (mask)
{ {
output32[i] = (getDesktop32(x, y) ^ buffer32[j]) | 0xFF000000; output32[outputIndex] = (desktop32[desktopIndex] ^ buffer32[cursorIndex]) | 0xFF000000;
} }
else else
{ {
output32[i] = buffer32[j] | 0xFF000000; output32[outputIndex] = buffer32[cursorIndex] | 0xFF000000;
} }
break;
} }
} case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
break;
}
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
{
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 desktop = reinterpret_cast<BYTE*>(&desktop32[desktopIndex]);
const auto desktop32 = getDesktop32(x, y);
const auto desktop = (BYTE*)(&desktop32);
const auto desktopB = desktop[0]; const auto desktopB = desktop[0];
const auto desktopG = desktop[1]; const auto desktopG = desktop[1];
const auto desktopR = desktop[2]; const auto desktopR = desktop[2];
const auto desktopA = desktop[3]; const auto desktopA = desktop[3];
const auto cursorB = apiBuffer_[i + 0]; const auto cursor = buffer_.Get(cursorIndex * 4);
const auto cursorG = apiBuffer_[i + 1]; const auto cursorB = cursor[0];
const auto cursorR = apiBuffer_[i + 2]; const auto cursorG = cursor[1];
const auto cursorA = apiBuffer_[i + 3]; const auto cursorR = cursor[2];
const auto cursorA = cursor[3];
const auto a0 = cursorA / 255.f; const auto a0 = cursorA / 255.f;
const auto a1 = 1.f - a0; const auto a1 = 1.f - a0;
output[i + 0] = static_cast<BYTE>(cursorB * a0 + desktopB * a1); auto output = reinterpret_cast<BYTE*>(&output32[outputIndex]);
output[i + 1] = static_cast<BYTE>(cursorG * a0 + desktopG * a1); output[0] = static_cast<BYTE>(cursorB * a0 + desktopB * a1);
output[i + 2] = static_cast<BYTE>(cursorR * a0 + desktopR * a1); output[1] = static_cast<BYTE>(cursorG * a0 + desktopG * a1);
output[i + 3] = desktopA; output[2] = static_cast<BYTE>(cursorR * a0 + desktopR * a1);
} output[3] = desktopA;
}
break;
}
default:
{
Debug::Error("Cursor::UpdateTexture() => Unknown cursor type");
break;
}
}
// Rotation
auto bgraBuffer32 = bgraBuffer_.As<UINT>();
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
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; break;
}
default:
{
Debug::Error("Cursor::UpdateTexture() => Unknown cursor type");
return;
}
} }
} }
} }
@@ -377,7 +356,7 @@ void Cursor::Draw(Monitor* monitor)
{ {
ComPtr<ID3D11DeviceContext> context; ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context); GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(monitor->GetUnityTexture(), 0, &box, bgraBuffer_.Get(), GetWidth() * 4, 0); context->UpdateSubresource(monitor->GetUnityTexture(), 0, &capturedImageArea, bgraBuffer_.Get(), capturedImageWidth * 4, 0);
} }
if (FAILED(surface->Unmap())) if (FAILED(surface->Unmap()))
@@ -28,7 +28,7 @@ private:
bool isVisible_ = false; bool isVisible_ = false;
int x_ = -1; int x_ = -1;
int y_ = -1; int y_ = -1;
Buffer<BYTE> apiBuffer_; Buffer<BYTE> buffer_;
Buffer<BYTE> bgraBuffer_; Buffer<BYTE> bgraBuffer_;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
LARGE_INTEGER timestamp_; LARGE_INTEGER timestamp_;