Open6

C-WebGL: Vulkanオブジェクトをキャッシュする

okuokuokuoku

遅い

というわけでSwiftShaderで安定して絵が出るようになったが、めっちゃ遅い。1フレームシティ。これはその筈で今はVulkanのオブジェクトを1描画毎に生成→破棄を繰り返しているため。SwiftShaderはオブジェクトの生成時にJITCもするのでその負荷が重い。

GPUではハードウェアを設定するだけで終わったりするので、この辺の負荷は見えづらい。

オブジェクトのキャッシュを実装することでこの辺を常識的な速度にしていきたい。

okuokuokuoku

シザーテストを修正

なんか左のWindowの内容が出ていないのが気になるので修正した。Vulkan 1.1ではNegative viewport機能があり、負のサイズのviewportを設定することで座標系をDirectXやMetalと同じにできる。が、viewport座標を調節したためscissorの座標も調節の必要がある。

https://github.com/okuoku/yuniframe/commit/68ee947e1ef18f67f6a6ace176a0204174fa1041

... いや冷静に考えるとなんかおかしい気がするな。。ScissorはViewport座標なんだから同じように動かないといけない気もする。。

okuokuokuoku

RenderPassとFramebuffer

オブジェクトは64bitのモノトニックカウンタをコンテキストに用意して、Vulkan側のオブジェクトを取得する度にユニークな番号が振られるようにした。

例えば、RenderPassはVulkan側のImageViewオブジェクトに依存するので、

  1. オブジェクトを確保する度にidentをアサインし、
  2. 自分に関連付けられた元オブジェクトのidentが一致していたら更新しない

という処理でキャッシュを実現する。

モノトニックなカウンタを使うのは、ポインタ値は再利用されてしまう可能性があるため。

okuokuokuoku

ScissorとViewportのDynamic state化

Vulkan的なPipeline stateをキャッシュする前に、ScissorとViewportは頻繁に変更されてもキャッシュに影響が無いようにDynamic stateに逃がしておく。というかDirectXもMetalもこれらはDynamicしか無いので何故Vulkanがこれらをpipeline stateに含めたのか。。まぁシェーダでやる方向性も無くは無い気もするけど。。

https://github.com/okuoku/yuniframe/commit/b2e9f34016c32e713e40c08f8970e5c0a83e89de

どのAPIでもシザーテストを無効化する方法は提供されない。とりあえず無効な場合はViewport全領域がpassするように設定しておく。

okuokuokuoku

Pipelineのキャッシュ

本命のPipelineのキャッシュ ...といっても、SwiftShaderの場合何もしなくてもそれなりに賢くキャッシュしてくれるためこれ単体ではあんまり効果が出ない。

https://github.com/okuoku/yuniframe/commit/b7f7e28c6a83d262724009df8372ee866143a0e8

Pipelineの構成要素を構造体に引き出し、それを単に memcmp で比較してキャッシュにヒットしたかどうか判定している。 ...たぶんハッシュとか取って効率化した方が良いんじゃないかという気はする。

struct cwgl_backend_pipeline_identity_s {
    /* Cache data for global context */
    uint64_t framebuffer_ident;
    uint64_t program_ident;
    float blend_color[4]; // FIXME: Dynamic?
    VkPipelineRasterizationStateCreateInfo rsi;
    VkPipelineMultisampleStateCreateInfo msi;
    VkPipelineDepthStencilStateCreateInfo dsi;
    VkPipelineInputAssemblyStateCreateInfo iai;
    VkPipelineColorBlendAttachmentState cbas_color; /* for color attachment */
    /* Cache data for vertex attr fetching */
    int bind_count;
    VkVertexInputAttributeDescription attrs[CWGL_MAX_VAO_SIZE];
    VkVertexInputBindingDescription binds[CWGL_MAX_VAO_SIZE];
};

Pipelineキャッシュの対象には、ラスタライザの構成情報と頂点アトリビュートのバッファフォーマットが含まれる。後者がpipelineに入っているのは、Vulkanが頂点アトリビュートのフェッチ自体もシェーダに逃がせるように配慮しているためと見られる。

CWGL_MAX_VAO_SIZE は簡単のために固定サイズにしていて、これが頂点アトリビュートの最大数になる。

Blend colorはDynamic stateに追い出してPipelineからは外しても良いかな。。