doitsujin / dxvk

Vulkan-based implementation of D3D8, 9, 10 and 11 for Linux / Wine
zlib License
12.99k stars 833 forks source link

game freeze when its first run on JX3 #1568

Closed dm0619 closed 1 month ago

dm0619 commented 4 years ago

Hi, we are the developer of the JX3 game, (a popular mmorpg game in China). JX3 is a game based on DX11, and we are currently trying to use DXVK as a temporary way to port the game from DX11 to Vulkan. Most things just work fine, but there is a annoying freeze in game, especially when the game‘s first run. the dx shader has already been cached, so we doubt maybe the freeze comes from the conversion from dxbc to spirv or something like that? we also notice there is a .dxvk-cache file in the game's working directory, but from the source, there is only some state information cached in this file, not the real spirv code. so the basic question is, how can we solve the freeze problem in our game? is there some pre-cache work we need to do and distribute to our player?

thanks in advance

doitsujin commented 4 years ago

is there some pre-cache work we need to do and distribute to our player?

It is probably a good idea to ship the .dxvk-cache file with the game. An easy way to populate the cache file with data would be to visit all areas in the game once and run around for a bit, until most (preferably all) shaders get used in a draw call at least once.

In order for the cache to be effective, games also have to load all their shaders before they are used for drawing, e.g. during startup or while loading an area. In other words, make sure to call D3D11Device::CreateVertexShader etc. as early as possble.

dm0619 commented 4 years ago

Thanks for your reply, and I have two more questions. 1) Is there a way to pre-cache the file by programming rather than running in the world? I can get all the shaders and its variations. I tried to call D3DDevice::CreatePixelShader etc with those shaders, but it seems not work. 2) the .dxvk-cache file seems continuing increasing, even I just go into the same world and exit repeatedly. BTW, I am using DXVK 1.2.1 for some reason.

doitsujin commented 4 years ago

Is there a way to pre-cache the file by programming rather than running in the world?

In theory, yes, but it is probably not feasible. You'd have to issue empty draw calls for every possible combination of shaders and dynamic state:

for (auto pass : renderPasses) {
  float blendConstant[4];
  ctx->OMSetRenderTargets(pass->rtCount, pass->rtv, pass->dsv);
  ctx->OMSetDepthStencilState(pass->depthStencilState, 0);
  ctx->OMSetBlendState(pass->blendState, blendConstant, 0xFFFFFFFF);
  for (auto asset : assets) {
    ctx->SetVertexShader(asset->vs[pass], ...);
    ctx->SetPixelShader(asset->ps[pass], ...);
    ctx->IASetPrimitiveTopology(asset->topology);
    ctx->IASetInputLayout(asset->inputLayout);
    ctx->RSSetState(asset->rsState);
    // bind dummy resources to all used slots
    ctx->Draw(0, 0);
  }
}

All state would have to match, this includes bound resources (the views and samplers don't have to match exactly, but whether a resource is bound or not does matter, and the resource type must also be correct).

The only exceptions which do not have to match are the stencil reference and blend constants.

The reason why all of this is necessary is because Vulkan requires us to provide most state at pipeline compile time, whereas in D3D11 we don't know anything in advance.