Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[d3d9] Implement a software cursor #4302

Merged
merged 2 commits into from
Oct 5, 2024

Conversation

WinterSnowfall
Copy link
Contributor

@WinterSnowfall WinterSnowfall commented Sep 28, 2024

Probably not an entirely sound approach, but it's a start. I believe we'll actually need to draw the cursor onto the final image ourselves, before the HUD. Some processing on the cursor bitmap surface that a game provides also needs to be done, because it needs to be trimmed to the bounding dimensions of pixels that contain color data and then blended.

I'm fine if @K0bin wants to pick up and reuse some of what I've done here, since the d3d9_cursor.cpp/h additions should be sound.

As is, the implementation is fully functional and sets/shows/hides a software cursor properly. However, the cursor surface is very unceremoniously sent onto the final backbuffer using StretchRect(). I had sort of hoped that would simply work, but alas.

As always, Dungeon Siege 2 is the game to test this with. (Fixes #3020).

@WinterSnowfall WinterSnowfall force-pushed the d3d9-swcursor branch 4 times, most recently from 6c9f93b to ddbdfe1 Compare September 29, 2024 09:02
@WinterSnowfall
Copy link
Contributor Author

WinterSnowfall commented Sep 29, 2024

So, thanks to some nudges in the right direction from @K0bin and @DadSchoorse, I managed to get the blending sorted by rendering the cursor texture to a quad and drawing that on the final render target.

This works just fine for our purposes, and seems rather fast and latency free, at least more than I expected it to be for a bunch of calculations done on each frame. Perhaps there's even room for a bit of optimization, to actually skip some of the coordinate math if the cursor position remains unchanged, but meh.

There's one more thing I actually need tackle though: apparently games expect us to trim/mask edge transparent pixels from the cursor surface they set (which is handled automagically by win32/hardware cursors). Right now, because of this unhandled behavior, the cursor quad dimensions and the cursor tip coordinates are not as/where they should be.

I'll be looking to address this during cursor surface memcpy with some bit-level magic, hopefully.

@K0bin
Copy link
Collaborator

K0bin commented Sep 29, 2024

I gotta say I'm not a fan that you implemented it using D3D9 APIs, especially the fixed function pipeline.

I would've used the underlying DxvkContext directly and wrote some simple GLSL shaders.

@WinterSnowfall
Copy link
Contributor Author

I would've used the underlying DxvkContext directly and wrote some simple GLSL shaders.

That's a bit beyond what I can do. In any case, @doitsujin is considering facilitating something like setCursorBitmap and setCursorPosition for us from the backend eventually, so I wouldn't overthink it at this point.

But if you want, feel free to take it forward are rewrite the offending bits. I'm only working on properly processing the application provided bitmap now, which would be useful anyway.

@WinterSnowfall WinterSnowfall force-pushed the d3d9-swcursor branch 2 times, most recently from 097ad99 to f99ba75 Compare September 29, 2024 16:47
@WinterSnowfall
Copy link
Contributor Author

WinterSnowfall commented Sep 29, 2024

Alright, sorted the pre-processing/clipping of the cursor bitmap too, which is something the frontend needs to handle before storing the cursor bitmap anyway. Would be nice if @Blisto91 has time to test it with Castle Strike, however I can confirm it works just fine with Dungeon Siege 2 and there's no reason for it not to work with anything else really, there's no nasty hacks this time.

Feel free to rewrite the presentation/draw part if you think that's more desirable, but if we can deffer that bit to the backend I'd be even happier (and this should do for now).

@WinterSnowfall
Copy link
Contributor Author

WinterSnowfall commented Sep 30, 2024

Thank you for testing.

In CS as we can see, it works. Problem is that with it enabled (do not happen with disabled), try for example changing resolutions after that enabled - game getting stuck with it. On NINE via d3d8to9 for example both works and not affecting something else like that.

Try with the latest push, should be sorted now. It was an oversight of mine causing that, namely we should release the cursor bitmap texture on device reset, since it counts as a losable resource.

Actually, digging a bit deeper into what happens with cursors on device reset I came across this:

IDirect3DDevice9::SetCursorProperties

The cursor does not survive when the device is lost. This method must be called after the device is reset.

Since the documentation refers to hardware cursors (mostly), I've taken the liberty of resetting those as well on device reset.

Similar like with DS2 missing resolutions in a game options menu, user will probably do some command line width and height to go higher.

You may be hit by the "too many reported modes" situation, that we kind of know exists. Some games will limit the amount of offered resolutions, so you may not have all options visible. Try using #4128 to set only a few higher resolution modes you're interested in, see if they show up like that. If they do, this is indeed the problem, an excess of reported modes caused by your combination of monitor and video card.

@WinterSnowfall
Copy link
Contributor Author

Works now (with enabled cursor) changing resolution do not get stuck

Great, thanks for confirming (and for finding the bug in the first place) 🎉 .

I guess, maybe app cant list all resolutions there because just its GUI is like that limited... whatever i dont mind about that :D

I mean, older games having limited resolution support is nothing new really. In many cases they'll limit the aspect ratio to 4:3, which was common at the time. It's a part of our history that will have to be modded/unofficially patched around for most games if anyone wants to retroactively add widescreen support.

@Blisto91
Copy link
Contributor

Blisto91 commented Oct 1, 2024

Both Dungeon Siege 2 and Castle Strike seem fine here too. Tested both with Proton and the former also with regular Wine + virtual desktop.

@mrdeathjr28
Copy link

In my case cursor work with wine 9.18 new wow64

ds2a

ds2b

curiously in capture linux cursor seems over ds2 cursor but in game show ds2 cursor normally

@WinterSnowfall
Copy link
Contributor Author

curiously in capture linux cursor seems over ds2 cursor but in game show ds2 cursor normally

That is expected. The game cursor with the new software cursor path is essentially a texture overlayed on top of what the game renders. And when you take a screenshot, your compositor will usually also capture your OS cursor pointer (which is hidden/invisible when you play the game).

If you use xfce4-screenshot to take the screenshot, then you can untick the "capture the mouse pointer" option and it should capture it correctly. Mind you, you only need to do this for games using software cursors, since the usual path is to use hardware cursors (thus the OS cursor directly), so this won't be a problem in most cases.

@WinterSnowfall WinterSnowfall marked this pull request as draft October 4, 2024 17:12
@WinterSnowfall WinterSnowfall force-pushed the d3d9-swcursor branch 2 times, most recently from db524e6 to 5303b85 Compare October 5, 2024 11:14
@WinterSnowfall
Copy link
Contributor Author

WinterSnowfall commented Oct 5, 2024

I've reworked the implementation on top of the backend cursor support recently added by @doitsujin. This means a couple of things:

  • the backend provided software cursor will render on top of dxvk's HUD, much like a plain non-d3d cursor
  • the implementation is much leaner and less prone to glitches caused by d3d9 state

@WinterSnowfall WinterSnowfall marked this pull request as ready for review October 5, 2024 11:24
src/d3d9/d3d9_swapchain.cpp Outdated Show resolved Hide resolved
@WinterSnowfall WinterSnowfall force-pushed the d3d9-swcursor branch 4 times, most recently from 2e7ebc2 to b030902 Compare October 5, 2024 15:59
@doitsujin doitsujin merged commit bbe82aa into doitsujin:master Oct 5, 2024
4 checks passed
@WinterSnowfall WinterSnowfall deleted the d3d9-swcursor branch October 5, 2024 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dungeon Siege 2 invisible mouse cursor
5 participants