深度バッファ法は並列性が損なわれませんか？


私はグラフィックプログラミングをしたことがないのですが、GPUに関する記事を読んでいると、ピクセルの描画をするのに複数の三角形の前後を判定するために深度バッファ法を用いると書いてありました。

それについて調べてみると、深度バッファ法というのは深度バッファを見て自らの深度値と比較し更新することで、上書きするかどうか決めるアルゴリズムのようでしたが、これは複数のピクセル処理が同時に同じ深度バッファに読み書きする可能性があるということですから、アトミック操作で更新する必要があるように見えます。しかしこれでは、三角形がたくさん重なってる場面では並列性が損なわれるように思います。更に、同じ三角形について近くのZバッファを読み書きするわけですから、何度も同じキャッシュラインが無効化されそうにも見えます。（GPUのアーキテクチャをよくわかっていないので、これに関してはかなり意味不明なことを言っているかもしれません）

  1. そもそも、GPUはピクセルごとに並列ななんらかの計算していますか？
  2. これは現代のGPUでも用いられている手法ですか？
  3. 三角形がたくさん重なっているときに並列性が損なわれてしまうことに対するなんらかの解決策がありますか？
  4. あるいは、そのCAS程度ではほとんど並列性が損なわれないという見方がありますか？

私はグラフィックについて全く知識がないため、変なことに疑問を持っていたらすみません。




# Vulkanの仕様から

Vulkan の仕様書におけるラスタライゼーションに関する規定を参照すると:  
(以下、強調は私)

> ## [25.2. Rasterization
> Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap25.html#primrast-
> order)
>
> Within a subpass of a render pass instance, **for a given (x,y,layer,sample)
> sample location** , the following operations are guaranteed to execute in
> _rasterization order_ , **for each separate primitive that includes that
> sample location** :
>
>   1. Fragment operations, in the order defined
>
>   2. Blending, logic operations, and color writes
>
>

>
> Each operation is atomically executed for each primitive and sample
> location.  
>  Execution of these operations **for each primitive** in a subpass occurs in
> **primitive order**.

つまり、レンダーターゲットのフラグメント(i.e ピクセル)中のサンプル位置(マルチサンプリングも考慮した文言)について、  
そのサンプル位置を含むプリミティブ(ここでは三角形としていいでしょう)毎に、以下で定義される`fragment operations`が実行されます:

> ## [26\. Fragment
> Operations](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap26.html)
>
> (前略)  
>  7\. Depth test  
>  (後略)

`depth test`とは[26.7. Depth
Test](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap26.html#fragops-
depth)で定義されているように、デプスへの書き込みも含みます.

そしてあるサンプル位置の`fragment operations`は上記引用の[25.2. Rasterization
Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap25.html#primrast-
order)の規定から`primitive order`で実行されます:

> ## [20.2. Primitive
> Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap20.html#drawing-
> primitive-order)
>
>   1. **Submission order** determines the initial ordering
>   2. (省略)
>   3. (省略)
>   4. The order in which primitives are specified by a draw command:
>

>   * For non-indexed draws, **from vertices with a lower numbered vertexIndex
> to a higher numbered vertexIndex**.
>   * For indexed draws, **vertices sourced from a lower index buffer
> addresses to higher addresses**.
>

>
> (中略)  
>  Primitive order is later used to define rasterization order, which
> **determines the order in which fragments output results** to a framebuffer.

要するに描画コマンド順、そしてその中ではプリミティブの定義順になります.

# 結論

つまり、深度バッファの同じ位置について、そこに同時に値が書き込まれることはなく、  
その位置に相当するプリミティブ達を描画コマンドで定義された順番で処理していく、  
と言うことがVulkanの仕様書の表記から言えるかと思います.

ラスタライゼーションを使ったグラフィクスパイプラインにおいて大量の実行ユニットにより「並列で処理される」のは個々のフラグメントであり、  
1つのフラグメントを複数の実行ユニットが処理する、というわけではない、ということかと思います.




# Vulkanの仕様から

Vulkan の仕様書におけるラスタライゼーションに関する規定を参照すると:  
(以下、強調は私)

> ## [25.2. Rasterization
> Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap25.html#primrast-
> order)
>
> Within a subpass of a render pass instance, **for a given (x,y,layer,sample)
> sample location** , the following operations are guaranteed to execute in
> _rasterization order_ , **for each separate primitive that includes that
> sample location** :
>
>   1. Fragment operations, in the order defined
>
>   2. Blending, logic operations, and color writes
>
>

>
> Each operation is atomically executed for each primitive and sample
> location.  
>  Execution of these operations **for each primitive** in a subpass occurs in
> **primitive order**.

つまり、レンダーターゲットのフラグメント(i.e ピクセル)中のサンプル位置(マルチサンプリングも考慮した文言)について、  
そのサンプル位置を含むプリミティブ(ここでは三角形としていいでしょう)毎に、以下で定義される`fragment operations`が実行されます:

> ## [26\. Fragment
> Operations](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap26.html)
>
> (前略)  
>  7\. Depth test  
>  (後略)

`depth test`とは[26.7. Depth
Test](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap26.html#fragops-
depth)で定義されているように、デプスへの書き込みも含みます.

そしてあるサンプル位置の`fragment operations`は上記引用の[25.2. Rasterization
Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap25.html#primrast-
order)の規定から`primitive order`で実行されます:

> ## [20.2. Primitive
> Order](https://www.khronos.org/registry/vulkan/specs/1.2/html/chap20.html#drawing-
> primitive-order)
>
>   1. **Submission order** determines the initial ordering
>   2. (省略)
>   3. (省略)
>   4. The order in which primitives are specified by a draw command:
>

>   * For non-indexed draws, **from vertices with a lower numbered vertexIndex
> to a higher numbered vertexIndex**.
>   * For indexed draws, **vertices sourced from a lower index buffer
> addresses to higher addresses**.
>

>
> (中略)  
>  Primitive order is later used to define rasterization order, which
> **determines the order in which fragments output results** to a framebuffer.

要するに描画コマンド順、そしてその中ではプリミティブの定義順になります.

# 結論

つまり、深度バッファの同じ位置について、そこに同時に値が書き込まれることはなく、  
その位置に相当するプリミティブ達を描画コマンドで定義された順番で処理していく、  
と言うことがVulkanの仕様書の表記から言えるかと思います.

ラスタライゼーションを使ったグラフィクスパイプラインにおいて大量の実行ユニットにより「並列で処理される」のは個々のフラグメントであり、  
1つのフラグメントを複数の実行ユニットが処理する、というわけではない、ということかと思います.

