mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2024-12-02 18:17:16 +01:00
88 lines
4.1 KiB
Markdown
88 lines
4.1 KiB
Markdown
|
# Notes outlining some aspects of the DirectX calls which were required to know to implement a up-/downscaling feature
|
||
|
As the title says, this outlines some aspects I needed to figure out in order to implement a up-/downscaling feature
|
||
|
within the d3d9 hook module that works on all currently available IIDX versions (9 to 26).
|
||
|
|
||
|
To analyze the rendering loops, I have used a tool called apitrace which traces the calls of many graphic APIs:
|
||
|
https://github.com/apitrace/apitrace
|
||
|
|
||
|
Defintely recommended to quickly figure out what is going on regarding rendering. It also allows you to let you render
|
||
|
parts of a scene after the application exited because it records all API calls and data passed to them.
|
||
|
|
||
|
Anyway, considering the various iterations in (GPU) hardware the game had to undergo combined with weird quirks and
|
||
|
"fixes" Bemanitools is undoing, I wouldn't have guessed that their rendering engine was nearly the same until IIDX 20.
|
||
|
That's when they introduced SD/HD mode.
|
||
|
|
||
|
In this case, that's great news because I had to craft a solution that allows up-/downscaling the final frame to
|
||
|
different resolutions (see the iidxhook-util/d3d9 module for more details about the feature).
|
||
|
|
||
|
But first, we need a breakdown of the render loop's most relevant parts for this:
|
||
|
|
||
|
## IIDX pre 20
|
||
|
Using apitrace, we can see the following outline of a frame (not counting the first one that does a lot of setup in
|
||
|
the beginning):
|
||
|
```
|
||
|
BeginScene
|
||
|
Clear
|
||
|
...
|
||
|
// Here are the main draw calls for the scene rendering to the back buffer
|
||
|
EndScene
|
||
|
Present
|
||
|
```
|
||
|
|
||
|
No render target switching, simply render everything to the back buffer...plain and simple.
|
||
|
|
||
|
Note: The viewport size is determined by the size returned by GetClientRect, wtf.
|
||
|
Welp, no official Konmai seal of approval without that. ¯\_(ツ)_/¯
|
||
|
|
||
|
## IIDX 20+
|
||
|
Using apitrace, we can see the following outline of a frame (not counting the first one that does a lot of setup in
|
||
|
the beginning):
|
||
|
```
|
||
|
BeginScene
|
||
|
// tex1 is a render target texture with size 1280x720 (also in SD mode)
|
||
|
// The game will render to this intermediate target and not directly to the fram ebuffer
|
||
|
SetRenderTarget(0, tex1)
|
||
|
...
|
||
|
Clear
|
||
|
BeginScene -> ErrInvalidCall return code
|
||
|
Clear
|
||
|
...
|
||
|
// Here are the main draw calls for the scene rendering to tex1
|
||
|
...
|
||
|
// Sets the render target to the original frame buffer. The size of the framebuffer is set to the output mode
|
||
|
// resolution, e.g. 1280x720 for HD mode and 640x480 for SD mode
|
||
|
SetRenderTarget(0, frame_buffer)
|
||
|
...
|
||
|
Clear
|
||
|
EndScene
|
||
|
...
|
||
|
// Render, texture and sampler state updates as well as a draw call that draws tex1 to a quad which fills the
|
||
|
// screen space.
|
||
|
...
|
||
|
EndScene -> ErrInvalidCall return code
|
||
|
Present
|
||
|
```
|
||
|
|
||
|
This is quite a different flow to implement HD and SD mode but the solution to solve that particular problem is straight
|
||
|
forward and easy to understand. This means that the game will always render in HD mode and only downscale the final
|
||
|
frame to SD resolution for 640x480 output.
|
||
|
|
||
|
Also, why the fuck do they call BeginScene and EndScene twice? Looks like they wanted to do this in two separate scenes
|
||
|
for some reason. Checking the return values would have revealed to them that something's not right...lucky them that
|
||
|
this code works nevertheless.
|
||
|
Another Konmai seal of approval, a job well done. ¯\_(ツ)_/¯
|
||
|
|
||
|
## iidxhook's up-/downscaling solution
|
||
|
The initial solution simply hooked into BeginScene and EndScene and let the game render to an intermediate render
|
||
|
target texture. The texture was scaled according to the actual target frame buffer size before getting presented. This
|
||
|
solution worked fine for pre IIDX 20 games but created a black screen on IIDX 20+.
|
||
|
|
||
|
In order to avoid two different scaling flows, the final solution that works for both does the following:
|
||
|
* Create a render target texture with native resolution and let the game render to it
|
||
|
* Set the render target to that intermediate render target texture on BeginScene
|
||
|
* Before Present
|
||
|
* Scale the intermediate render target texture to the back buffer
|
||
|
* Set the back buffer as the render target
|
||
|
* Present frame
|
||
|
|
||
|
Just an outline which follows the actual implementation that you can find in the iidxhook-util/d3d9.
|