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 {
|
namespace dxvk {
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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) {
|
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
||||||
POINT currentPos = { };
|
POINT currentPos = { };
|
||||||
if (::GetCursorPos(¤tPos) && currentPos == POINT{ X, Y })
|
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) {
|
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||||
if (likely(m_hCursor != nullptr))
|
if (likely(m_hCursor != nullptr))
|
||||||
::SetCursor(bShow ? m_hCursor : nullptr);
|
::SetCursor(bShow ? m_hCursor : nullptr);
|
||||||
else
|
|
||||||
Logger::debug("D3D9Cursor::ShowCursor: Software cursor not implemented.");
|
|
||||||
|
|
||||||
return std::exchange(m_visible, bShow);
|
return std::exchange(m_visible, bShow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
|
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;
|
CursorMask mask;
|
||||||
std::memset(mask, ~0, sizeof(mask));
|
std::memset(mask, ~0, sizeof(mask));
|
||||||
|
|
||||||
@ -48,12 +77,43 @@ namespace dxvk {
|
|||||||
|
|
||||||
return D3D_OK;
|
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
|
#else
|
||||||
|
void D3D9Cursor::ResetCursor() {
|
||||||
|
Logger::warn("D3D9Cursor::ResetCursor: Not supported on current platform.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
||||||
Logger::warn("D3D9Cursor::UpdateCursor: Not supported on current platform.");
|
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) {
|
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||||
Logger::warn("D3D9Cursor::ShowCursor: Not supported on current platform.");
|
Logger::warn("D3D9Cursor::ShowCursor: Not supported on current platform.");
|
||||||
return std::exchange(m_visible, bShow);
|
return std::exchange(m_visible, bShow);
|
||||||
@ -65,6 +125,12 @@ namespace dxvk {
|
|||||||
|
|
||||||
return D3D_OK;
|
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
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,25 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
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 HardwareCursorFormatSize = 4u;
|
||||||
constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
|
constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
|
||||||
|
|
||||||
// Format Size of 4 bytes (ARGB)
|
// Format Size of 4 bytes (ARGB)
|
||||||
using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
|
using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
|
||||||
// Monochrome mask (1 bit)
|
// Monochrome mask (1 bit)
|
||||||
using CursorMask = uint8_t[HardwareCursorHeight * HardwareCursorWidth / 8];
|
using CursorMask = uint8_t[HardwareCursorHeight * HardwareCursorWidth / 8];
|
||||||
|
|
||||||
class D3D9Cursor {
|
class D3D9Cursor {
|
||||||
|
|
||||||
@ -25,18 +35,37 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void ResetCursor();
|
||||||
|
|
||||||
void UpdateCursor(int X, int Y);
|
void UpdateCursor(int X, int Y);
|
||||||
|
|
||||||
|
void RefreshSoftwareCursorPosition();
|
||||||
|
|
||||||
BOOL ShowCursor(BOOL bShow);
|
BOOL ShowCursor(BOOL bShow);
|
||||||
|
|
||||||
HRESULT SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap);
|
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:
|
private:
|
||||||
|
|
||||||
BOOL m_visible = FALSE;
|
BOOL m_visible = FALSE;
|
||||||
|
D3D9_SOFTWARE_CURSOR m_sCursor;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HCURSOR m_hCursor = nullptr;
|
HCURSOR m_hCursor = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -354,14 +354,14 @@ namespace dxvk {
|
|||||||
hwCursor |= inputWidth <= HardwareCursorWidth
|
hwCursor |= inputWidth <= HardwareCursorWidth
|
||||||
|| inputHeight <= HardwareCursorHeight;
|
|| 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) {
|
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.
|
// Windows works with a stride of 128, lets respect that.
|
||||||
// Copy data to the bitmap...
|
// Copy data to the bitmap...
|
||||||
CursorBitmap bitmap = { 0 };
|
CursorBitmap bitmap = { 0 };
|
||||||
@ -376,10 +376,58 @@ namespace dxvk {
|
|||||||
|
|
||||||
// Set this as our cursor.
|
// Set this as our cursor.
|
||||||
return m_cursor.SetHardwareCursor(XHotSpot, YHotSpot, bitmap);
|
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;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,6 +507,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_flags.clr(D3D9DeviceFlag::InScene);
|
m_flags.clr(D3D9DeviceFlag::InScene);
|
||||||
|
m_cursor.ResetCursor();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before calling the IDirect3DDevice9::Reset method for a device,
|
* Before calling the IDirect3DDevice9::Reset method for a device,
|
||||||
@ -3852,6 +3901,19 @@ namespace dxvk {
|
|||||||
HWND hDestWindowOverride,
|
HWND hDestWindowOverride,
|
||||||
const RGNDATA* pDirtyRegion,
|
const RGNDATA* pDirtyRegion,
|
||||||
DWORD dwFlags) {
|
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(
|
return m_implicitSwapchain->Present(
|
||||||
pSourceRect,
|
pSourceRect,
|
||||||
pDestRect,
|
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) {
|
HRESULT D3D9SwapChainEx::SetDialogBoxMode(bool bEnableDialogs) {
|
||||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||||
|
|
||||||
|
@ -118,6 +118,10 @@ namespace dxvk {
|
|||||||
|
|
||||||
void Invalidate(HWND hWindow);
|
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);
|
HRESULT SetDialogBoxMode(bool bEnableDialogs);
|
||||||
|
|
||||||
D3D9Surface* GetBackBuffer(UINT iBackBuffer);
|
D3D9Surface* GetBackBuffer(UINT iBackBuffer);
|
||||||
|
Loading…
Reference in New Issue
Block a user