mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-11 10:24:10 +01:00
[d3d9] Implement a software cursor
This commit is contained in:
parent
87a7882812
commit
7ff5321910
@ -6,6 +6,21 @@
|
||||
namespace dxvk {
|
||||
|
||||
#ifdef _WIN32
|
||||
void D3D9Cursor::ResetCursor() {
|
||||
ShowCursor(FALSE);
|
||||
|
||||
if (likely(m_hCursor != nullptr)) {
|
||||
::DestroyCursor(m_hCursor);
|
||||
m_hCursor = nullptr;
|
||||
} else {
|
||||
m_sCursor.Width = 0;
|
||||
m_sCursor.Height = 0;
|
||||
m_sCursor.X = 0;
|
||||
m_sCursor.Y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
||||
POINT currentPos = { };
|
||||
if (::GetCursorPos(¤tPos) && currentPos == POINT{ X, Y })
|
||||
@ -15,17 +30,31 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void D3D9Cursor::RefreshSoftwareCursorPosition() {
|
||||
POINT currentPos = { };
|
||||
::GetCursorPos(¤tPos);
|
||||
|
||||
m_sCursor.X = static_cast<UINT>(currentPos.x);
|
||||
m_sCursor.Y = static_cast<UINT>(currentPos.y);
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||
if (likely(m_hCursor != nullptr))
|
||||
::SetCursor(bShow ? m_hCursor : nullptr);
|
||||
else
|
||||
Logger::debug("D3D9Cursor::ShowCursor: Software cursor not implemented.");
|
||||
|
||||
return std::exchange(m_visible, bShow);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
|
||||
if (unlikely(IsSoftwareCursor())) {
|
||||
m_sCursor.Width = 0;
|
||||
m_sCursor.Height = 0;
|
||||
m_sCursor.X = 0;
|
||||
m_sCursor.Y = 0;
|
||||
}
|
||||
|
||||
CursorMask mask;
|
||||
std::memset(mask, ~0, sizeof(mask));
|
||||
|
||||
@ -48,12 +77,43 @@ namespace dxvk {
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Cursor::SetSoftwareCursor(UINT Width, UINT Height, UINT XHotSpot, UINT YHotSpot) {
|
||||
// Make sure to hide the win32 cursor
|
||||
::SetCursor(nullptr);
|
||||
|
||||
if (unlikely(m_hCursor != nullptr)) {
|
||||
::DestroyCursor(m_hCursor);
|
||||
m_hCursor = nullptr;
|
||||
}
|
||||
|
||||
m_sCursor.Width = Width;
|
||||
m_sCursor.Height = Height;
|
||||
m_sCursor.X = XHotSpot;
|
||||
m_sCursor.Y = YHotSpot;
|
||||
|
||||
ShowCursor(m_visible);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
void D3D9Cursor::ResetCursor() {
|
||||
Logger::warn("D3D9Cursor::ResetCursor: Not supported on current platform.");
|
||||
}
|
||||
|
||||
|
||||
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
||||
Logger::warn("D3D9Cursor::UpdateCursor: Not supported on current platform.");
|
||||
}
|
||||
|
||||
|
||||
void D3D9Cursor::RefreshSoftwareCursorPosition() {
|
||||
Logger::warn("D3D9Cursor::RefreshSoftwareCursorPosition: Not supported on current platform.");
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||
Logger::warn("D3D9Cursor::ShowCursor: Not supported on current platform.");
|
||||
return std::exchange(m_visible, bShow);
|
||||
@ -65,6 +125,12 @@ namespace dxvk {
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT D3D9Cursor::SetSoftwareCursor(UINT Width, UINT Height, UINT XHotSpot, UINT YHotSpot) {
|
||||
Logger::warn("D3D9Cursor::SetSoftwareCursor: Not supported on current platform.");
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -4,15 +4,25 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr uint32_t HardwareCursorWidth = 32u;
|
||||
constexpr uint32_t HardwareCursorHeight = 32u;
|
||||
/**
|
||||
* \brief D3D9 Software Cursor
|
||||
*/
|
||||
struct D3D9_SOFTWARE_CURSOR {
|
||||
UINT Width = 0;
|
||||
UINT Height = 0;
|
||||
UINT X = 0;
|
||||
UINT Y = 0;
|
||||
};
|
||||
|
||||
constexpr uint32_t HardwareCursorWidth = 32u;
|
||||
constexpr uint32_t HardwareCursorHeight = 32u;
|
||||
constexpr uint32_t HardwareCursorFormatSize = 4u;
|
||||
constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
|
||||
|
||||
// Format Size of 4 bytes (ARGB)
|
||||
using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
|
||||
// Monochrome mask (1 bit)
|
||||
using CursorMask = uint8_t[HardwareCursorHeight * HardwareCursorWidth / 8];
|
||||
using CursorMask = uint8_t[HardwareCursorHeight * HardwareCursorWidth / 8];
|
||||
|
||||
class D3D9Cursor {
|
||||
|
||||
@ -25,18 +35,37 @@ namespace dxvk {
|
||||
}
|
||||
#endif
|
||||
|
||||
void ResetCursor();
|
||||
|
||||
void UpdateCursor(int X, int Y);
|
||||
|
||||
void RefreshSoftwareCursorPosition();
|
||||
|
||||
BOOL ShowCursor(BOOL bShow);
|
||||
|
||||
HRESULT SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap);
|
||||
|
||||
HRESULT SetSoftwareCursor(UINT Width, UINT Height, UINT XHotSpot, UINT YHotSpot);
|
||||
|
||||
D3D9_SOFTWARE_CURSOR* GetSoftwareCursor() {
|
||||
return &m_sCursor;
|
||||
}
|
||||
|
||||
BOOL IsSoftwareCursor() const {
|
||||
return m_sCursor.Width > 0 && m_sCursor.Height > 0;
|
||||
}
|
||||
|
||||
BOOL IsCursorVisible() const {
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_visible = FALSE;
|
||||
BOOL m_visible = FALSE;
|
||||
D3D9_SOFTWARE_CURSOR m_sCursor;
|
||||
|
||||
#ifdef _WIN32
|
||||
HCURSOR m_hCursor = nullptr;
|
||||
HCURSOR m_hCursor = nullptr;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
@ -354,14 +354,14 @@ namespace dxvk {
|
||||
hwCursor |= inputWidth <= HardwareCursorWidth
|
||||
|| inputHeight <= HardwareCursorHeight;
|
||||
|
||||
D3DLOCKED_BOX lockedBox;
|
||||
HRESULT hr = LockImage(cursorTex, 0, 0, &lockedBox, nullptr, D3DLOCK_READONLY);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(lockedBox.pBits);
|
||||
|
||||
if (hwCursor) {
|
||||
D3DLOCKED_BOX lockedBox;
|
||||
HRESULT hr = LockImage(cursorTex, 0, 0, &lockedBox, nullptr, D3DLOCK_READONLY);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(lockedBox.pBits);
|
||||
|
||||
// Windows works with a stride of 128, lets respect that.
|
||||
// Copy data to the bitmap...
|
||||
CursorBitmap bitmap = { 0 };
|
||||
@ -376,10 +376,58 @@ namespace dxvk {
|
||||
|
||||
// Set this as our cursor.
|
||||
return m_cursor.SetHardwareCursor(XHotSpot, YHotSpot, bitmap);
|
||||
} else {
|
||||
// The cursor bitmap passed by the application has the potential
|
||||
// to not be clipped to the correct dimensions, so we need to
|
||||
// discard any transparent edges and keep only a tight rectangle
|
||||
// bounded by the cursor's visible edge pixels
|
||||
uint32_t leftEdge = inputWidth * HardwareCursorFormatSize;
|
||||
uint32_t topEdge = inputHeight;
|
||||
uint32_t rightEdge = 0;
|
||||
uint32_t bottomEdge = 0;
|
||||
|
||||
uint32_t rowPitch = inputWidth * HardwareCursorFormatSize;
|
||||
|
||||
for (uint32_t h = 0; h < inputHeight; h++) {
|
||||
uint32_t rowOffset = h * rowPitch;
|
||||
for (uint32_t w = 0; w < rowPitch; w += HardwareCursorFormatSize) {
|
||||
// Examine only pixels with non-zero alpha
|
||||
if (data[rowOffset + w + 3] != 0) {
|
||||
if (leftEdge > w) leftEdge = w;
|
||||
if (topEdge > h) topEdge = h;
|
||||
if (rightEdge < w) rightEdge = w;
|
||||
if (bottomEdge < h) bottomEdge = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
leftEdge /= HardwareCursorFormatSize;
|
||||
rightEdge /= HardwareCursorFormatSize;
|
||||
|
||||
if (leftEdge > rightEdge || topEdge > bottomEdge) {
|
||||
UnlockImage(cursorTex, 0, 0);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
// Calculate clipped bitmap dimensions
|
||||
uint32_t clippedInputWidth = rightEdge + 1 - leftEdge + 1;
|
||||
uint32_t clippedInputHeight = bottomEdge + 1 - topEdge + 1;
|
||||
// Windows works with a stride of 128, lets respect that.
|
||||
uint32_t clippedCopyPitch = clippedInputWidth * HardwareCursorFormatSize;
|
||||
|
||||
std::vector<uint8_t> clippedBitmap(clippedInputHeight * clippedCopyPitch, 0);
|
||||
|
||||
for (uint32_t h = 0; h < clippedInputHeight; h++)
|
||||
std::memcpy(&clippedBitmap[h * clippedCopyPitch],
|
||||
&data[(h + topEdge) * lockedBox.RowPitch + leftEdge * HardwareCursorFormatSize], clippedCopyPitch);
|
||||
|
||||
UnlockImage(cursorTex, 0, 0);
|
||||
|
||||
m_implicitSwapchain->SetCursorTexture(clippedInputWidth, clippedInputHeight, &clippedBitmap[0]);
|
||||
|
||||
return m_cursor.SetSoftwareCursor(clippedInputWidth, clippedInputHeight, XHotSpot, YHotSpot);
|
||||
}
|
||||
|
||||
// Software Cursor...
|
||||
Logger::warn("D3D9DeviceEx::SetCursorProperties: Software cursor not implemented.");
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
@ -459,6 +507,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
m_flags.clr(D3D9DeviceFlag::InScene);
|
||||
m_cursor.ResetCursor();
|
||||
|
||||
/*
|
||||
* Before calling the IDirect3DDevice9::Reset method for a device,
|
||||
@ -3852,6 +3901,19 @@ namespace dxvk {
|
||||
HWND hDestWindowOverride,
|
||||
const RGNDATA* pDirtyRegion,
|
||||
DWORD dwFlags) {
|
||||
|
||||
if (m_cursor.IsSoftwareCursor()) {
|
||||
m_cursor.RefreshSoftwareCursorPosition();
|
||||
|
||||
D3D9_SOFTWARE_CURSOR* pSoftwareCursor = m_cursor.GetSoftwareCursor();
|
||||
|
||||
UINT cursorWidth = m_cursor.IsCursorVisible() ? pSoftwareCursor->Width : 0;
|
||||
UINT cursorHeight = m_cursor.IsCursorVisible() ? pSoftwareCursor->Height : 0;
|
||||
|
||||
m_implicitSwapchain->SetCursorPosition(pSoftwareCursor->X, pSoftwareCursor->Y,
|
||||
cursorWidth, cursorHeight);
|
||||
}
|
||||
|
||||
return m_implicitSwapchain->Present(
|
||||
pSourceRect,
|
||||
pDestRect,
|
||||
|
@ -748,6 +748,32 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void D3D9SwapChainEx::SetCursorTexture(UINT Width, UINT Height, uint8_t* pCursorBitmap) {
|
||||
VkExtent2D cursorSize = { uint32_t(Width), uint32_t(Height) };
|
||||
|
||||
m_blitter->setCursorTexture(
|
||||
cursorSize,
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
(void *) pCursorBitmap);
|
||||
}
|
||||
|
||||
|
||||
void D3D9SwapChainEx::SetCursorPosition(UINT X, UINT Y, UINT Width, UINT Height) {
|
||||
VkOffset2D cursorPosition = { int32_t(X), int32_t(Y) };
|
||||
VkExtent2D cursorSize = { uint32_t(Width), uint32_t(Height) };
|
||||
|
||||
VkRect2D cursorRect = { cursorPosition, cursorSize };
|
||||
|
||||
m_parent->EmitCs([
|
||||
cBlitter = m_blitter,
|
||||
cRect = cursorRect
|
||||
] (DxvkContext* ctx) {
|
||||
cBlitter->setCursorPos(
|
||||
cRect);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9SwapChainEx::SetDialogBoxMode(bool bEnableDialogs) {
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
|
@ -118,6 +118,10 @@ namespace dxvk {
|
||||
|
||||
void Invalidate(HWND hWindow);
|
||||
|
||||
void SetCursorTexture(UINT Width, UINT Height, uint8_t* pCursorBitmap);
|
||||
|
||||
void SetCursorPosition(UINT X, UINT Y, UINT Width, UINT Height);
|
||||
|
||||
HRESULT SetDialogBoxMode(bool bEnableDialogs);
|
||||
|
||||
D3D9Surface* GetBackBuffer(UINT iBackBuffer);
|
||||
|
Loading…
Reference in New Issue
Block a user