DX8 → wined3d → gl4es → ANGLE実験
とりあえずクラッシュしないところまで行ったので、後は何とか出画しない原因を探したい。。
SwiftShaderを使う
毎度おなじみSwiftShaderは32bitアプリでも使用できる。メモリ足りるのかな。。SwiftShaderはgitでチェックアウト後CMakeで直接ビルドできる。ビルド後、 Windows\vk_swiftshader_icd.json
を環境変数 VK_ICD_FILENAMES
に指定する。 ...当然、ターゲットアプリを起動するときの環境変数に設定する必要がある 。
VK_ICD_FILENAMES=F:\swiftshader32\Windows\vk_swiftshader_icd.json
IntelのVulkanは自分自身のOpenGLに依存しているため使えなかった。(今回はOpenGLをgl4esを使用して自前で実装しているので、OpenGLに依存している外部ライブラリは一切使えない)
prev
RenderDoc → クラッシュする
Vulkanアプリのデバッグと言えばRenderDocだね! ただ、RenderDocはOpenGLもhookしようとしてしまうため諸々を破壊してしまう。最初のWined3d初期化の部分までは正常に処理できるものの、ゲームに入ると即死する。
RenderDoc読み込み時のクラッシュは前DebugDiagを使って頑張って調べたけど、単に環境変数でimplicit layerとして読まれるRenderDocを有効化すれば十分だった。
ENABLE_VULKAN_RENDERDOC_CAPTURE=1
環境変数 ENABLE_VULKAN_RENDERDOC_CAPTURE
を指定してVulkanアプリを起動すると、RenderDocから接続できるようになる。
gfxreconstruct → キャプチャはできるがフレームがない
余計なAPI hookが無い gfxreconstruct を試してみることにする。
バイナリはVulkan SDKに収録されていて、Layerについては32bit版が提供されている。
VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_gfxreconstruct
GFXRECON_CAPTURE_FILE=f:\capture.gfxr
GFXRECON_CAPTURE_FILE_FLUSH=true
GFXRECON_LOG_LEVEL=debug
GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING=true
VK_LAYER_PATH=C:\VulkanSDK\1.3.236.0\Bin32
キャプチャはできたものの、フレームが無い。このため、ANGLEから見たEGL的なコンテキストが正常にflipできていない可能性が高いと見られる。... まぁ正常にキャプチャできてない可能性も考える必要があるが。。
C:\VulkanSDK\1.3.236.0\Bin>gfxrecon-info f:\capture_20221218T153529.gfxr
File info:
Compression format: LZ4
Total frames: 0
Application info:
Application name: ZWEI2P.exe
Application version: 1
Engine name: ANGLE
Engine version: 1
Target API version: 4198400 (1.1.0)
Physical device info:
Device name: SwiftShader Device (LLVM 10.0.0)
Device ID: 0xc0de
Vendor ID: 0x1ae0
Driver version: 20971520 (0x1400000)
API version: 4206592 (1.3.0)
Physical device info:
Device name: SwiftShader Device (LLVM 10.0.0)
Device ID: 0xc0de
Vendor ID: 0x1ae0
Driver version: 20971520 (0x1400000)
API version: 4206592 (1.3.0)
Device memory allocation info:
Total allocations: 556
Min allocation size: 16
Max allocation size: 5592416
Pipeline info:
Total graphics pipelines: 121
Total compute pipelines: 0
Annotation info:
Total annotations: 1
Operation annotations: 1
{
"tool": "capture",
"timestamp": "2022-11-18T06:35:29Z",
"gfxrecon-version": "0.9.16 (e4b9092)",
"vulkan-version": "1.3.236"
}
File did not contain any frames
確かにFlipしていない
とりあえずgfxrecon-convertでjsonlに変換してみて中身を見ると、
{"index":196,"vkFunc":{"name":"vkGetPhysicalDeviceSurfaceFormats2KHR","return":"VK_SUCCESS","args":{"physicalDevice":2,"pSurfaceInfo":{"sType":"VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR","pNext":null,"surface":14},"pSurfaceFormatCount":2,"pSurfaceFormats":[{"sType":"VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR","pNext":null,"surfaceFormat":{"format":"VK_FORMAT_B8G8R8A8_UNORM","colorSpace":"VK_COLOR_SPACE_SRGB_NONLINEAR_KHR"}},{"sType":"VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR","pNext":null,"surfaceFormat":{"format":"VK_FORMAT_B8G8R8A8_SRGB","colorSpace":"VK_COLOR_SPACE_SRGB_NONLINEAR_KHR"}}]}}}
{"index":198,"vkFunc":{"name":"vkCreateSwapchainKHR","return":"VK_SUCCESS","args":{"device":3,"pCreateInfo":{"sType":"VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR","pNext":null,"flags":0,"surface":14,"minImageCount":3,"imageFormat":"VK_FORMAT_B8G8R8A8_UNORM","imageColorSpace":"VK_COLOR_SPACE_SRGB_NONLINEAR_KHR","imageExtent":{"width":120,"height":1},"imageArrayLayers":1,"imageUsage":151,"imageSharingMode":"VK_SHARING_MODE_EXCLUSIVE","queueFamilyIndexCount":0,"pQueueFamilyIndices":null,"preTransform":"VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR","compositeAlpha":"VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR","presentMode":"VK_PRESENT_MODE_FIFO_KHR","clipped":1,"oldSwapchain":"VK_NULL_HANDLE"},"pAllocator":null,"pSwapchain":15}}}
{"index":199,"vkFunc":{"name":"vkGetSwapchainImagesKHR","return":"VK_SUCCESS","args":{"device":3,"swapchain":15,"pSwapchainImageCount":3,"pSwapchainImages":null}}}
{"index":200,"vkFunc":{"name":"vkGetSwapchainImagesKHR","return":"VK_SUCCESS","args":{"device":3,"swapchain":15,"pSwapchainImageCount":3,"pSwapchainImages":[16,17,18]}}}
{"index":201,"vkFunc":{"name":"vkCreateSemaphore","return":"VK_SUCCESS","args":{"device":3,"pCreateInfo":{"sType":"VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO","pNext":null,"flags":0},"pAllocator":null,"pSemaphore":19}}}
{"index":202,"vkFunc":{"name":"vkCreateSemaphore","return":"VK_SUCCESS","args":{"device":3,"pCreateInfo":{"sType":"VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO","pNext":null,"flags":0},"pAllocator":null,"pSemaphore":20}}}
{"index":203,"vkFunc":{"name":"vkCreateSemaphore","return":"VK_SUCCESS","args":{"device":3,"pCreateInfo":{"sType":"VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO","pNext":null,"flags":0},"pAllocator":null,"pSemaphore":21}}}
{"index":204,"vkFunc":{"name":"vkCreateFence","return":"VK_SUCCESS","args":{"device":3,"pCreateInfo":{"sType":"VK_STRUCTURE_TYPE_FENCE_CREATE_INFO","pNext":null,"flags":0},"pAllocator":null,"pFence":22}}}
{"index":205,"vkFunc":{"name":"vkAcquireNextImageKHR","return":"VK_SUCCESS","args":{"device":3,"swapchain":15,"timeout":18446744073709551615,"semaphore":19,"fence":22,"pImageIndex":0}}}
vkGetSwapchainImagesKHR
でswapchain上のimageを拾っているのに、 vkQueuePresentKHR
の類がダンプにない。
{"index":64339,"vkFunc":{"name":"vkCmdSetStencilTestEnableEXT","args":{"commandBuffer":4282,"stencilTestEnable":0}}}
{"index":64340,"vkFunc":{"name":"vkCmdSetStencilOpEXT","args":{"commandBuffer":4282,"faceMask":1,"failOp":"VK_STENCIL_OP_KEEP","passOp":"VK_STENCIL_OP_KEEP","depthFailOp":"VK_STENCIL_OP_KEEP","compareOp":"VK_COMPARE_OP_ALWAYS"}}}
{"index":64341,"vkFunc":{"name":"vkCmdSetStencilOpEXT","args":{"commandBuffer":4282,"faceMask":2,"failOp":"VK_STENCIL_OP_KEEP","passOp":"VK_STENCIL_OP_KEEP","depthFailOp":"VK_STENCIL_OP_KEEP","compareOp":"VK_COMPARE_OP_ALWAYS"}}}
{"index":64342,"vkFunc":{"name":"vkCmdDraw","args":{"commandBuffer":4282,"vertexCount":4,"instanceCount":1,"firstVertex":0,"firstInstance":0}}}
vkCmdDraw
はあるのでコマンドバッファ自体は構築している。上位層で glFinish
なり glFlush
しないとダメとかあるんだろうか。。
ANGLE側を追う
とりあえず、SwapBuffer自体は呼べているようなので、その処理がどこまで到達しているかを確認する。
EVENT: glGetError(context = 1)
DUMMY: wglSwapBuffers
EVENT: eglPrepareSwapBuffersANGLE(dpy = 0x000000000d627288, surface = 0x0000000000000001)
DUMMY: wglGetPixelFormat (did nothing)
EVENT: glGetError(context = 1)
ねっとりとステップ実行したところ、
ここの val->eglThread->getCurrentDrawSurface() != eglSurface
チェックに失敗していることがわかった。つまり wglMakeCurrent
の実装があやしいな。。
黒画になった
どうもEGL contextに紐付いているdisplayが変えられないようなので、 eglGetDisplay(EGL_DEFAULT_DISPLAY);
を代わりに使うようにしたら黒画になった。
これで再度APIトレースを取って問題分析だな。。
APIトレースにはフレームはある
C:\VulkanSDK\1.3.236.0\Bin>gfxrecon-info.exe f:\capture_20221218T170917.gfxr
File info:
Compression format: LZ4
Total frames: 311
ただリプレイできるデバイスが無い。。一応 --remove-unsupported
オプションはあるものの、やっぱりクラッシュしてしまう。
C:\VulkanSDK\1.3.236.0\Bin>gfxrecon-replay.exe --pause-frame 300 --remove-unsupported -m remap f:\capture_20221218T170917.gfxr
[gfxrecon] WARNING - The replay device differs from the original capture device; replay may fail due to device incompatibilities:
[gfxrecon] WARNING - Capture device info: [vendorID = 0x1ae0, deviceId = 0xc0de, deviceName = SwiftShader Device (LLVM 10.0.0)]
[gfxrecon] WARNING - Replay device info: [vendorID = 0x8086, deviceId = 0x1912, deviceName = Intel(R) HD Graphics 530]
[gfxrecon] WARNING - Extension VK_EXT_load_store_op_none, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_KHR_sampler_ycbcr_conversion, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_EXT_blend_operation_advanced, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_KHR_pipeline_library, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_EXT_graphics_pipeline_library, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_EXT_pipeline_robustness, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Extension VK_EXT_rasterization_order_attachment_access, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Feature rasterizationOrderColorAttachmentAccess, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Feature rasterizationOrderDepthAttachmentAccess, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Feature rasterizationOrderStencilAttachmentAccess, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Feature samplerYcbcrConversion, which is not supported by the replay device, will not be enabled
[gfxrecon] WARNING - Feature rectangularLines, which is not supported by the replay device, will not be enabled
[gfxrecon] INFO - Replay adjusted the vkGetPhysicalDeviceSurfaceFormatsKHR array count: capture count = 2, replay count = 4
[gfxrecon] WARNING - API call vkAcquireNextImageKHR returned value VK_SUBOPTIMAL_KHR that does not match return value from capture file: VK_SUCCESS.
[gfxrecon] WARNING - Failed to map handle for object id 110
とりあえず gfxrecon-replay を手元でもビルドしてみて確認してみたところ、SwiftShader内部でクラッシュしていた。
一旦Vulkan Profilesで機能制限を掛けたうえで実行できないか検討した方が良いかな。。
リプレイできるキャプチャが取れた
VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_gfxreconstruct;VK_LAYER_KHRONOS_profiles
GFXRECON_CAPTURE_FILE=f:\capture.gfxr
GFXRECON_CAPTURE_FILE_FLUSH=true
GFXRECON_LOG_LEVEL=debug
GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING=true
VK_LAYER_PATH=C:\VulkanSDK\1.3.236.0\Bin32;F:\vulkanprofiles32\bin\Debug
VK_KHRONOS_PROFILES_EXCLUDE_DEVICE_EXTENSIONS=VK_EXT_load_store_op_none;VK_KHR_sampler_ycbcr_conversion;VK_EXT_blend_operation_advanced;VK_KHR_pipeline_library;VK_EXT_graphics_pipeline_library;VK_EXT_pipeline_robustness;VK_EXT_rasterization_order_attachment_access;VK_EXT_provoking_vertex;VK_EXT_external_memory_host
VK_KHRONOS_PROFILES_DEBUG_ACTIONS=DEBUG_ACTION_OUTPUT_BIT
VK_ICD_FILENAMES=F:\swiftshader32\Windows\vk_swiftshader_icd.json
WINEDEBUG=+all
ここまでしないといけないの辛いすぎるな。。 VK_EXT_provoking_vertex
VK_EXT_external_memory_host
の2つはRenderDocのキャプチャを入れると無効化されるようなので最初から無効化しておく必要があった。(gfxreconstructはリプレイできるがRenderDocがリプレイできない)
Wined3dは起動時にレンダリングのテストをするので、それが1枚目のWindowとしてリプレイされてしまう。実際のゲームは2枚目のWindowになるので、接続したあとCycleボタンを押してactive windowを切り替える必要がある。
リプレイは直接RenderDoc上で64bitのSwiftShaderを使ったら普通にクラッシュしたので、32bit版のリプレイサーバを使ってみる。
C:\Program Files\RenderDoc\x86>renderdoccmd remoteserver
Spawning a replay host listening on *...
GUIのRenderDocは64bit版しか提供されないものの、 renderdoccmd
は32bit版がある。
JIT session error: Symbols not found: [ __chkstk ]
... Debug版のCRTはダメなのか。。全部をリリース版にしてキャプチャを取りなおす。
キャプチャの分析
タイトル画面の部分をキャプチャしているのでQuadのドローばかりなのは多分正しい。UIテクスチャも正常にアップロードされているようなので、それらの描画を追うことで間違ったパラメーターを発見できそう。
... こういう描画されるべきものが見えない時はPixel historyを使うのが定石な気がするけど、今回はどうもRenderDocがクラッシュしてしまうようなのでPipeline stateを地道に追うことにする。
まず、Mesh viewerで頂点属性、いわゆる gl_Position
の場所を確認する。今回の場合は _input7
が入力、 _sig63._child0
が出力っぽいので、それぞれカラムを右クリックしてPositionに設定する。設定することでワイヤフレームが描画されるようになる。
... が、出力がオールゼロで明かにおかしい。これはgl4esのfixed pipelineエミュレータのバグっぽい気がする。。