Skip to content

Commit 5c89779

Browse files
[d3d9] Add a software cursor emulation config option
1 parent dacb8b4 commit 5c89779

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

dxvk.conf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,17 @@
626626

627627
# d3d9.seamlessCubes = False
628628

629+
# Software Cursor Emulation
630+
#
631+
# Will atempt to emulate a software cursor by using a hardware cursor. This is useful
632+
# for applications that rely on d3d9 API calls to create the cursor and potentially use
633+
# bitmap sizes in excess of 32 x 32.
634+
#
635+
# Supported values:
636+
# - True/False
637+
638+
# d3d9.softwareCursorEmulation = False
639+
629640
# Debug Utils
630641
#
631642
# Enables debug utils as this is off by default, this enables user annotations like BeginEvent()/EndEvent().

src/d3d9/d3d9_cursor.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,53 @@ namespace dxvk {
2525
}
2626

2727

28-
HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
29-
DWORD mask[32];
30-
std::memset(mask, ~0, sizeof(mask));
28+
HRESULT D3D9Cursor::SetHardwareCursor(
29+
UINT XHotSpot,
30+
UINT YHotSpot,
31+
const std::vector<uint8_t>& bitmap,
32+
bool cursorEmulation,
33+
UINT width,
34+
UINT height,
35+
HWND window) {
36+
bool noPreviousHardwareCursor = false;
37+
38+
uint32_t cursorWidth = cursorEmulation ? width : HardwareCursorWidth;
39+
uint32_t cursorHeight = cursorEmulation ? height : HardwareCursorHeight;
40+
41+
// For color icons, the hbmMask and hbmColor bitmaps
42+
// are the same size, each of which is the size of the icon.
43+
std::vector<DWORD> mask(cursorWidth * cursorHeight, ~0);
3144

3245
ICONINFO info;
3346
info.fIcon = FALSE;
3447
info.xHotspot = XHotSpot;
3548
info.yHotspot = YHotSpot;
36-
info.hbmMask = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 1, mask);
37-
info.hbmColor = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 32, &bitmap[0]);
49+
info.hbmMask = ::CreateBitmap(cursorWidth, cursorHeight, 1, 1, &mask[0]);
50+
info.hbmColor = ::CreateBitmap(cursorWidth, cursorHeight, 1, 32, &bitmap[0]);
3851

3952
if (m_hCursor != nullptr)
4053
::DestroyCursor(m_hCursor);
54+
else
55+
noPreviousHardwareCursor = true;
4156

4257
m_hCursor = ::CreateIconIndirect(&info);
4358

4459
::DeleteObject(info.hbmMask);
4560
::DeleteObject(info.hbmColor);
4661

62+
if (cursorEmulation) {
63+
::SetClassLongPtr(window, GCLP_HCURSOR, reinterpret_cast<LONG_PTR>(m_hCursor));
64+
65+
CURSORINFO ci;
66+
while (::GetCursorInfo(&ci) && ci.flags == 0u)
67+
::ShowCursor(TRUE);
68+
69+
// Castle Strike needs one extra initial increment
70+
// to display the emulated cursor on its menu
71+
if (noPreviousHardwareCursor)
72+
::ShowCursor(TRUE);
73+
}
74+
4775
ShowCursor(m_visible);
4876

4977
return D3D_OK;
@@ -60,7 +88,14 @@ namespace dxvk {
6088
}
6189

6290

63-
HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
91+
HRESULT D3D9Cursor::SetHardwareCursor(
92+
UINT XHotSpot,
93+
UINT YHotSpot,
94+
const std::vector<uint8_t>& bitmap,
95+
bool cursorEmulation,
96+
UINT width,
97+
UINT height,
98+
HWND window) {
6499
Logger::warn("D3D9Cursor::SetHardwareCursor: Not supported on current platform.");
65100

66101
return D3D_OK;

src/d3d9/d3d9_cursor.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ namespace dxvk {
99
constexpr uint32_t HardwareCursorFormatSize = 4u;
1010
constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
1111

12-
// Format Size of 4 bytes (ARGB)
13-
using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
14-
1512
class D3D9Cursor {
1613

1714
public:
@@ -20,7 +17,14 @@ namespace dxvk {
2017

2118
BOOL ShowCursor(BOOL bShow);
2219

23-
HRESULT SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap);
20+
HRESULT SetHardwareCursor(
21+
UINT XHotSpot,
22+
UINT YHotSpot,
23+
const std::vector<uint8_t>& bitmap,
24+
bool cursorEmulation,
25+
UINT width,
26+
UINT height,
27+
HWND window);
2428

2529
private:
2630

src/d3d9/d3d9_device.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ namespace dxvk {
345345
// Always use a hardware cursor when windowed.
346346
D3DPRESENT_PARAMETERS params;
347347
m_implicitSwapchain->GetPresentParameters(&params);
348-
bool hwCursor = params.Windowed;
348+
bool hwCursor = params.Windowed || m_d3d9Options.softwareCursorEmulation;
349349

350350
// Always use a hardware cursor w/h <= 32 px
351351
hwCursor |= inputWidth <= HardwareCursorWidth
@@ -359,20 +359,32 @@ namespace dxvk {
359359

360360
const uint8_t* data = reinterpret_cast<const uint8_t*>(lockedBox.pBits);
361361

362+
uint32_t emulatedCursorPitch = inputWidth * HardwareCursorFormatSize;
363+
364+
uint32_t cursorHeight = m_d3d9Options.softwareCursorEmulation ? inputHeight : HardwareCursorHeight;
365+
uint32_t cursorPitch = m_d3d9Options.softwareCursorEmulation ? emulatedCursorPitch : HardwareCursorPitch;
366+
362367
// Windows works with a stride of 128, lets respect that.
363368
// Copy data to the bitmap...
364-
CursorBitmap bitmap = { 0 };
369+
// Format Size of 4 bytes (ARGB)
370+
std::vector<uint8_t> bitmap(cursorHeight * cursorPitch, 0);
365371
size_t copyPitch = std::min<size_t>(
366-
HardwareCursorPitch,
372+
cursorPitch,
367373
inputWidth * inputHeight * HardwareCursorFormatSize);
368374

369-
for (uint32_t h = 0; h < HardwareCursorHeight; h++)
370-
std::memcpy(&bitmap[h * HardwareCursorPitch], &data[h * lockedBox.RowPitch], copyPitch);
375+
for (uint32_t h = 0; h < cursorHeight; h++)
376+
std::memcpy(&bitmap[h * cursorPitch], &data[h * lockedBox.RowPitch], copyPitch);
371377

372378
UnlockImage(cursorTex, 0, 0);
373379

374380
// Set this as our cursor.
375-
return m_cursor.SetHardwareCursor(XHotSpot, YHotSpot, bitmap);
381+
return m_cursor.SetHardwareCursor(XHotSpot,
382+
YHotSpot,
383+
bitmap,
384+
m_d3d9Options.softwareCursorEmulation,
385+
inputWidth,
386+
inputHeight,
387+
m_window);
376388
}
377389

378390
// Software Cursor...

src/d3d9/d3d9_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ namespace dxvk {
7777
this->samplerLodBias = config.getOption<float> ("d3d9.samplerLodBias", 0.0f);
7878
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
7979
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
80+
this->softwareCursorEmulation = config.getOption<bool> ("d3d9.softwareCursorEmulation", false);
8081

8182
// Clamp LOD bias so that people don't abuse this in unintended ways
8283
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);

src/d3d9/d3d9_options.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ namespace dxvk {
144144
/// Clamps negative LOD bias
145145
bool clampNegativeLodBias;
146146

147+
/// Emulate a software cursor using a hardware cursor
148+
bool softwareCursorEmulation;
149+
147150
/// How much virtual memory will be used for textures (in MB).
148151
int32_t textureMemory;
149152

0 commit comments

Comments
 (0)