Dxvk: Project Cars 2 support / D3D11ImmediateContext::Map length

Created on 15 Sep 2018  路  16Comments  路  Source: doitsujin/dxvk

Hi,

firstly, dxvk is amazing, I'm impressed how well it works!

I quite enjoy Project Cars 2, so I spent some time debugging while it wouldn't run in Wine. After some initial hacking it would go into the menu, but then crash during the game loading screen at 68%.

At 68% it seems to call D3D11ImmediateContext::Map(...) on two buffers a and b, and then does a checked_memcpy(a.data, a.length, b.data, b.length). This checked_memcpy copies from b to a, and ensures that a.length >= b.length.
That check fails with current dxvk master, and it throws an exception and crashes.

So I added some logging, and it seems that b.length == 48128, but a.length == 48000.

If I add the following hack to d3d11_context_imm.cpp D3D11ImmediateContext::MapBuffer the game runs:

374     auto l = physicalSlice.length();                                                            
375     if (l == 48128) {                                                                           
376         pMappedResource->RowPitch   = 48000;                                                    
377         pMappedResource->DepthPitch = 48000;                                                    
378     }                                                                                           
379     if (l == 16128) {                                                                           
380         pMappedResource->RowPitch   = 16000;                                                    
381         pMappedResource->DepthPitch = 16000;                                                    
382     }                                                                                           
383     if (l == 12032) {                                                                           
384         pMappedResource->RowPitch   = 12000;                                                    
385         pMappedResource->DepthPitch = 12000;                                                    
386     } 

The other two cases were necessary, but it seems that's it.

I have little experience with graphics programming, but I would suspect that it sometimes rounds up e.g. 48000 to 48128, and that causes the two buffers to be different sizes.

While I'm quite happy that my hack makes it run this doesn't seem like something we want to hardcode :)

Do you have some advice how to fix this properly? I haven't really looked through the rest of the code yet, but I could imagine that we might want to either disable the rounding up or somehow keep track what the originally requested size was and then use that instead of physicalSlice.length().

GPU is Radeon RX 570 Series (POLARIS10, DRM 3.26.0, 4.18.6-arch1-1-ARCH, LLVM 6.0.1).

bug

Most helpful comment

Uh, okay. Looks like we're actually supposed to return the virtual buffer length in Row/Depth Pitch and not the actual buffer length (unlike for images). It's still weird that the game relies on this.

I'll do some testing and should have a fix soon. Thanks for the trace and doing the debugging, that really helps.

All 16 comments

Can you try to record an apitrace (while using your "fixed" DXVK build) so that I can get a more complete picture of what it's doing?

I think buffers in D3D11 are guaranteed to have a 512-byte alignment in memory or something like that (not entirely sure), so on Windows it might return inflated values and this game may rely on that. This would be a game bug, but it should be possible to work around it.

Sure, will do. What's the right method for steam, use the dlls from the wiki?

Also, how do you replay those traces? Just interested for the future, a few days ago I downloaded a trace from someone else but coudln't replay it with just wine apitrace.exe (or whatever it's called), I just got a pink screen.

The DLLs should work. d3dretrace game.trace should work, although sometimes some trickery is necessary to replay a trace.

Seems to crash with this, just looking if I can make it run:

arn:  DxgiAdapter::QueryInterface: Unknown interface query
warn:  645967a4-1392-4310-a798-8053ce3e93fd
warn:  DxgiOutput::QueryInterface: Unknown interface query
warn:  80a07424-ab52-42eb-833c-0c42fd282d98
warn:  DxgiOutput::QueryInterface: Unknown interface query
warn:  dc7dca35-2196-414d-9f53-617884032a60
warn:  DxgiOutput::QueryInterface: Unknown interface query
warn:  8a6bb301-7e7e-41f4-a8e0-5b32f7f99b18
warn:  DxgiOutput::QueryInterface: Unknown interface query
warn:  595e39d1-2724-4663-99b1-da969de28364
warn:  DxgiOutput::QueryInterface: Unknown interface query
warn:  00cddea8-939b-4b83-a340-a685226666cc
apitrace: warning: ID3D11Device1::QueryInterface: unsupported IID uuid(79352328-16f2-4f81-9746-9c2e2ccd43cf)
apitrace: warning: pVtbl = 000000000D338A60 (C:\windows\system32\d3d11.dll!+0x208a60)
apitrace: warning: caught exception 0xc0000005
apitrace: flushing trace
01d4:fixme:ver:GetCurrentPackageId (0x24f4fdc0 (nil)): stub
01d4:fixme:dbghelp:MiniDumpWriteDump NIY MiniDumpWithDataSegs

Trace so far:
pCARS2.trace.not_really.txt

Wine trace:

... removed noise ...

3 0x0000000000dbabde in gameoverlayrenderer64 (+0x8abdd) (0x0000000004520a20)

Steam overlay enabled by any chance? If so, please disable it.

Yep, hopefully gone now, but getting this:

removed noise

This looks similar to the issue I had to fix to even make it start at all, I think 0x00000001419b8005 is strcpy or something like that, and originally it was crashing on a strcpy of some cpu id field. This is different though, it's not the same call stack and I still have the original strcpy nop'ed out.

Ha, I seem to have gotten it to work :)

Trace is here, xz is slightly compressed and smaller:
http://andreas.heider.io/cars.trace
http://andreas.heider.io/cars.trace.xz

In case it's useful for others: I replaced the original exe with this:

#include <stdlib.h>                                                                             

int main()                                                                                      
{                                                                                               
    system ("apitrace.exe trace -v -a dxgi -o cars.trace pCARS2_orig.exe -novr");            
    return 0;                                                                                   
 }                                                                                               

Compile with x86_64-w64-mingw32-g++ wrapper.cpp -o wrapper.exe -static, then replace the original pCARS2.exe with that. I've seen people overwrite pCARS2.exe with apitrace.exe directly, but that didn't work for me as there was this hardcoded -novr argument that tripped up apitrace.

This part of the apitrace looks related:

2028366 ID3D11Device1::CreateShaderResourceView(this = 0x139df60, pResource = 0x30020d30, pDesc = &{Format = DXGI_FORMAT_B8G8R8A8_UNORM, ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D, Texture2D = {MostDetailedMip = 0, MipLevels = 1}}, ppSRView = &0x30020ef0) = S_OK
2028367 ID3D11Device1::CreateShaderResourceView(this = 0x139df60, pResource = 0x30020d30, pDesc = &{Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D, Texture2D = {MostDetailedMip = 0, MipLevels = 1}}, ppSRView = &0x30021010) = S_OK
2028368 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 64, Usage = D3D11_USAGE_DEFAULT, BindFlags = D3D11_BIND_CONSTANT_BUFFER, CPUAccessFlags = 0x0, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x30021130) = S_OK
2028369 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 64, Usage = D3D11_USAGE_DEFAULT, BindFlags = D3D11_BIND_CONSTANT_BUFFER, CPUAccessFlags = 0x0, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x300212f0) = S_OK
2028370 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 12000, Usage = D3D11_USAGE_STAGING, BindFlags = 0x0, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x300214b0) = S_OK
2028371 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 12000, Usage = D3D11_USAGE_DYNAMIC, BindFlags = D3D11_BIND_INDEX_BUFFER, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x30050870) = S_OK
2028372 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 48000, Usage = D3D11_USAGE_STAGING, BindFlags = 0x0, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x30021880) = S_OK
2028373 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 48000, Usage = D3D11_USAGE_DYNAMIC, BindFlags = D3D11_BIND_VERTEX_BUFFER, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x30021a40) = S_OK
2028374 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 32000, Usage = D3D11_USAGE_STAGING, BindFlags = 0x0, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x30021cb0) = S_OK
2028375 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 32000, Usage = D3D11_USAGE_DYNAMIC, BindFlags = D3D11_BIND_VERTEX_BUFFER, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x3003d180) = S_OK
2028376 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 16000, Usage = D3D11_USAGE_STAGING, BindFlags = 0x0, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x3003d3b0) = S_OK
2028377 ID3D11Device1::CreateBuffer(this = 0x139df60, pDesc = &{ByteWidth = 16000, Usage = D3D11_USAGE_DYNAMIC, BindFlags = D3D11_BIND_VERTEX_BUFFER, CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, MiscFlags = 0x0, StructureByteStride = 0}, pInitialData = NULL, ppBuffer = &0x3003d570) = S_OK
2028378 ID3D11Device1::CreateInputLayout(this = 0x139df60, pInputElementDescs = {{SemanticName = "POSITION", SemanticIndex = 0, Format = DXGI_FORMAT_R32G32B32_FLOAT, InputSlot = 0, AlignedByteOffset = 0, InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate = 0}, {SemanticName = "COLOR", SemanticIndex = 0, Format = DXGI_FORMAT_B8G8R8A8_UNORM, InputSlot = 2, AlignedByteOffset = 0, InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate = 0}, {SemanticName = "TEXCOORD", SemanticIndex = 0, Format = DXGI_FORMAT_R32G32_FLOAT, InputSlot = 1, AlignedByteOffset = 0, InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate = 0}}, NumElements = 3, pShaderBytecodeWithInputSignature = blob(564), BytecodeLength = 564, ppInputLayout = &0x3003da20) = S_OK
2028379 ID3D11InputLayout::AddRef(this = 0x28447c50) = 2
2028380 ID3D11InputLayout::AddRef(this = 0x3003da20) = 1
2028381 ID3D11InputLayout::AddRef(this = 0x28447c50) = 3
2028382 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021880, Subresource = 0, MapType = D3D11_MAP_READ_WRITE, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28ab1b1f00, RowPitch = 48000, DepthPitch = 48000}) = S_OK
2028383 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021cb0, Subresource = 0, MapType = D3D11_MAP_READ_WRITE, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28aa4ec000, RowPitch = 32000, DepthPitch = 32000}) = S_OK
2028384 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x3003d3b0, Subresource = 0, MapType = D3D11_MAP_READ_WRITE, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28aba7e000, RowPitch = 16000, DepthPitch = 16000}) = S_OK
2028385 memcpy(dest = 0x7f28ab1b1f00, src = blob(48000), n = 48000) // fake
2028386 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021880, Subresource = 0)
2028387 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021880, Subresource = 0, MapType = D3D11_MAP_READ, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28ab1b1f00, RowPitch = 48000, DepthPitch = 48000}) = S_OK
2028388 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021880, Subresource = 0)
2028389 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021880, Subresource = 0, MapType = D3D11_MAP_READ, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28ab1b1f00, RowPitch = 48000, DepthPitch = 48000}) = S_OK
2028390 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021a40, Subresource = 0, MapType = D3D11_MAP_WRITE_DISCARD, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28efc10900, RowPitch = 48000, DepthPitch = 48000}) = S_OK
2028391 memcpy(dest = 0x7f28efc10900, src = blob(48000), n = 48000) // fake
2028392 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021a40, Subresource = 0)
2028393 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021880, Subresource = 0)
2028394 memcpy(dest = 0x7f28aa4ec000, src = blob(32000), n = 32000) // fake
2028395 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021cb0, Subresource = 0)
2028396 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30021cb0, Subresource = 0, MapType = D3D11_MAP_READ, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28aa4ec000, RowPitch = 32000, DepthPitch = 32000}) = S_OK
2028397 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x3003d180, Subresource = 0, MapType = D3D11_MAP_WRITE_DISCARD, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28efcd9700, RowPitch = 32000, DepthPitch = 32000}) = S_OK
2028398 memcpy(dest = 0x7f28efcd9700, src = blob(32000), n = 32000) // fake
2028399 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x3003d180, Subresource = 0)
2028400 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30021cb0, Subresource = 0)
2028401 memcpy(dest = 0x7f28aba7e000, src = blob(16000), n = 16000) // fake
2028402 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x3003d3b0, Subresource = 0)
2028403 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x3003d3b0, Subresource = 0, MapType = D3D11_MAP_READ, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28aba7e000, RowPitch = 16000, DepthPitch = 16000}) = S_OK
2028404 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x3003d570, Subresource = 0, MapType = D3D11_MAP_WRITE_DISCARD, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28efc28100, RowPitch = 16000, DepthPitch = 16000}) = S_OK
2028405 memcpy(dest = 0x7f28efc28100, src = blob(16000), n = 16000) // fake
2028406 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x3003d570, Subresource = 0)
2028407 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x3003d3b0, Subresource = 0)
2028408 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x300214b0, Subresource = 0, MapType = D3D11_MAP_READ_WRITE, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28abcf1e00, RowPitch = 12000, DepthPitch = 12000}) = S_OK
2028409 memcpy(dest = 0x7f28abcf1e00, src = blob(12000), n = 12000) // fake
2028410 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x300214b0, Subresource = 0)
2028411 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x300214b0, Subresource = 0, MapType = D3D11_MAP_READ, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28abcf1e00, RowPitch = 12000, DepthPitch = 12000}) = S_OK
2028412 ID3D11DeviceContext1::Map(this = 0x13b1630, pResource = 0x30050870, Subresource = 0, MapType = D3D11_MAP_WRITE_DISCARD, MapFlags = 0x0, pMappedResource = &{pData = 0x7f28efcc0000, RowPitch = 12000, DepthPitch = 12000}) = S_OK
2028413 memcpy(dest = 0x7f28efcc0000, src = blob(12000), n = 12000) // fake
2028414 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x30050870, Subresource = 0)
2028415 ID3D11DeviceContext1::Unmap(this = 0x13b1630, pResource = 0x300214b0, Subresource = 0)

Uh, okay. Looks like we're actually supposed to return the virtual buffer length in Row/Depth Pitch and not the actual buffer length (unlike for images). It's still weird that the game relies on this.

I'll do some testing and should have a fix soon. Thanks for the trace and doing the debugging, that really helps.

Should be fixed with 19408f0ebede526a1aad2a594b3b25619d1737e5.

Project Cars 2 no longer crashes on map load for me. Thanks!

Project Cars 2 demo tested here. And no more crashes.

Yes, runs great now. Thanks for fixing!

Can someone give me a build with this change? Please :)

dxvk.zip

There you go, master from about 1h ago.

Thank you very, very much!!!

Was this page helpful?
0 / 5 - 0 ratings