Compare commits
10 Commits
1e1f61b9e6
...
main
Author | SHA1 | Date | |
---|---|---|---|
4ed086be0a | |||
7ec394db89 | |||
69d33476b8 | |||
0fc185283d | |||
921d1811ec | |||
d10e76d5a1 | |||
ffc5770c1f | |||
66cab59101 | |||
e5488ec6f5 | |||
c6a11711c4 |
9
.bazelrc
9
.bazelrc
@ -1,9 +1,10 @@
|
||||
common --registry=https://bcr.bazel.build
|
||||
common --registry=https://git.stevenlr.com/460nm/bazel-registry.git/plain/
|
||||
common --registry=https://bcr.bazel.build/
|
||||
common --registry=https://bazel.stevenlr.com/registry/
|
||||
|
||||
build --enable_platform_specific_config
|
||||
|
||||
build:windows --extra_execution_platforms=//:x64_windows-clang-cl
|
||||
# @Todo(bazel) We should be able to use @local_config_cc...
|
||||
build:windows --extra_toolchains=@@rules_cc++cc_configure_extension+local_config_cc//:cc-toolchain-x64_windows-clang-cl
|
||||
build:windows --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
|
||||
|
||||
build:windows --cxxopt=-Xclang=-std=c++23
|
||||
|
||||
|
@ -32,3 +32,4 @@ Checks:
|
||||
- "-readability-function-cognitive-complexity"
|
||||
- "-readability-math-missing-parentheses"
|
||||
- "-*-rvalue-reference-param-not-moved"
|
||||
- "-*-enum-size"
|
||||
|
23
MODULE.bazel
23
MODULE.bazel
@ -4,23 +4,14 @@
|
||||
|
||||
module(name = "hk21")
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
bazel_dep(name = "rules_cc", version = "0.0.17")
|
||||
bazel_dep(name = "platforms", version = "0.0.11")
|
||||
bazel_dep(name = "rules_license", version = "1.0.0")
|
||||
|
||||
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
|
||||
git_override(
|
||||
module_name = "hedron_compile_commands",
|
||||
remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
|
||||
commit = "4f28899228fb3ad0126897876f147ca15026151e",
|
||||
)
|
||||
bazel_dep(name = "rules_cc", version = "0.1.1")
|
||||
cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_extension")
|
||||
use_repo(cc_configure, "local_config_cc")
|
||||
|
||||
bazel_dep(name = "hedron_compile_commands", version = "0.1.0", dev_dependency = True)
|
||||
|
||||
bazel_dep(name = "sdl3_windows", version = "3.2.6")
|
||||
|
||||
bazel_dep(name = "asl")
|
||||
git_override(
|
||||
module_name = "asl",
|
||||
commit = "8604c98df53486208cdc15424aae9d9b2fef2d8e",
|
||||
remote = "https://git.stevenlr.com/460nm/asl.git/",
|
||||
)
|
||||
|
||||
bazel_dep(name = "asl", version = "0.4.0")
|
||||
|
102
MODULE.bazel.lock
generated
102
MODULE.bazel.lock
generated
@ -1,6 +1,13 @@
|
||||
{
|
||||
"lockFileVersion": 18,
|
||||
"registryFileHashes": {
|
||||
"https://bazel.stevenlr.com/registry/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
|
||||
"https://bazel.stevenlr.com/registry/modules/asl/0.4.0/MODULE.bazel": "767046b78b3dfeec294ab47800d20d2c3220f6d29aca915fef12868305d4b7eb",
|
||||
"https://bazel.stevenlr.com/registry/modules/asl/0.4.0/source.json": "191cd1a3fd046480ee4f68f6c98566eec1210c4ab358c8d204f5284400ec267c",
|
||||
"https://bazel.stevenlr.com/registry/modules/hedron_compile_commands/0.1.0/MODULE.bazel": "5623ba8f732a01246c388bccebf924357e452314a178f179d3b375b623d5a359",
|
||||
"https://bazel.stevenlr.com/registry/modules/hedron_compile_commands/0.1.0/source.json": "c55f6caa3eb9fb027af66949c23ca537214eb32b0316ae95bcc496f3cd8406b9",
|
||||
"https://bazel.stevenlr.com/registry/modules/sdl3_windows/3.2.6/MODULE.bazel": "857507d99ce37f1a4cb331a7888cec8511f38b0bfd46adb55d1b70a9cbe4e86f",
|
||||
"https://bazel.stevenlr.com/registry/modules/sdl3_windows/3.2.6/source.json": "5196961bbdfc230463ce7ea9049f7bab62b5ea7bccbfd376b85d07b2f909f98b",
|
||||
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
|
||||
@ -10,6 +17,7 @@
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da",
|
||||
"https://bcr.bazel.build/modules/asl/0.4.0/MODULE.bazel": "not found",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d",
|
||||
@ -39,11 +47,13 @@
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
|
||||
"https://bcr.bazel.build/modules/hedron_compile_commands/0.1.0/MODULE.bazel": "not found",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
|
||||
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
|
||||
@ -70,11 +80,12 @@
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.17/source.json": "4db99b3f55c90ab28d14552aa0632533e3e8e5e9aea0f5c24ac0014282c2a7c5",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c",
|
||||
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e",
|
||||
@ -88,10 +99,10 @@
|
||||
"https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.11.0/source.json": "302b52a39259a85aa06ca3addb9787864ca3e03b432a5f964ea68244397e7544",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.6.1/source.json": "f18d9ad3c4c54945bf422ad584fa6c5ca5b3116ff55a5b1bc77e5c1210be5960",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
|
||||
@ -121,8 +132,8 @@
|
||||
"https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.1.0/MODULE.bazel": "57e01abae22956eb96d891572490d20e07d983e0c065de0b2170cafe5053e788",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.1.0/source.json": "29f1fdfd23a40808c622f813bc93e29c3aae277333f03293f667e76159750a0f",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.3.0/source.json": "25932f917cd279c7baefa6cb1d3fa8750a7a29de522024449b19af6eab51f4a0",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95",
|
||||
"https://bcr.bazel.build/modules/sdl3_windows/3.2.6/MODULE.bazel": "not found",
|
||||
@ -137,51 +148,10 @@
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198",
|
||||
"https://git.stevenlr.com/460nm/bazel-registry.git/plain/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
|
||||
"https://git.stevenlr.com/460nm/bazel-registry.git/plain/modules/sdl3_windows/3.2.6/MODULE.bazel": "857507d99ce37f1a4cb331a7888cec8511f38b0bfd46adb55d1b70a9cbe4e86f",
|
||||
"https://git.stevenlr.com/460nm/bazel-registry.git/plain/modules/sdl3_windows/3.2.6/source.json": "5196961bbdfc230463ce7ea9049f7bab62b5ea7bccbfd376b85d07b2f909f98b"
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
|
||||
},
|
||||
"selectedYankedVersions": {},
|
||||
"moduleExtensions": {
|
||||
"@@platforms//host:extension.bzl%host_platform": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
|
||||
"usagesDigest": "SeQiIN/f8/Qt9vYQk7qcXp4I4wJeEC0RnQDiaaJ4tb8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"host_platform": {
|
||||
"repoRuleId": "@@platforms//host:extension.bzl%host_platform_repo",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": []
|
||||
}
|
||||
},
|
||||
"@@rules_java+//java:rules_java_deps.bzl%compatibility_proxy": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "84xJEZ1jnXXwo8BXMprvBm++rRt4jsTu9liBxz0ivps=",
|
||||
"usagesDigest": "jTQDdLDxsS43zuRmg1faAjIEPWdLAbDAowI1pInQSoo=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"compatibility_proxy": {
|
||||
"repoRuleId": "@@rules_java+//java:rules_java_deps.bzl%_compatibility_proxy_repo_rule",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_java+",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "sFhcgPbDQehmbD1EOXzX4H1q/CD5df8zwG4kp4jbvr8=",
|
||||
@ -245,6 +215,42 @@
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_python+//python/uv:uv.bzl%uv": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=",
|
||||
"usagesDigest": "vJ5RHUxAnV24M5swNGiAnkdxMx3Hp/iOLmNANTC5Xc8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"uv": {
|
||||
"repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo",
|
||||
"attributes": {
|
||||
"toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'",
|
||||
"toolchain_names": [
|
||||
"none"
|
||||
],
|
||||
"toolchain_implementations": {
|
||||
"none": "'@@rules_python+//python:none'"
|
||||
},
|
||||
"toolchain_compatible_with": {
|
||||
"none": [
|
||||
"@platforms//:incompatible"
|
||||
]
|
||||
},
|
||||
"toolchain_target_settings": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_python+",
|
||||
"platforms",
|
||||
"platforms"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ cc_binary(
|
||||
"@asl//asl/types:option",
|
||||
"@asl//asl/containers:buffer",
|
||||
"@sdl3_windows//:sdl3",
|
||||
"//hk21/vulkan_loader",
|
||||
"//hk21/vulkan/loader",
|
||||
"//hk21/vulkan/sync",
|
||||
],
|
||||
applicable_licenses = ["//:license"],
|
||||
)
|
||||
|
@ -4,14 +4,21 @@
|
||||
|
||||
#include "hk21/game/gpu.hpp"
|
||||
|
||||
#include <asl/base/numeric.hpp>
|
||||
#include <asl/containers/buffer.hpp>
|
||||
#include <asl/containers/intrusive_list.hpp>
|
||||
#include <asl/formatting/format.hpp>
|
||||
#include <asl/types/option.hpp>
|
||||
#include <asl/logging/logging.hpp>
|
||||
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
|
||||
#include "hk21/vulkan_loader/api.hpp"
|
||||
#include "hk21/vulkan/loader/loader.hpp"
|
||||
#include "hk21/vulkan/sync/sync.hpp"
|
||||
|
||||
// @Todo Make fences recyclable
|
||||
// @Todo Make command pool recyclable
|
||||
// @Todo Make frame structure recyclable
|
||||
|
||||
#define VK_ALLOCATOR nullptr
|
||||
|
||||
@ -192,6 +199,22 @@ static asl::status_or<PhysicalDeviceInfo> find_physical_device(VkInstance instan
|
||||
continue;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSynchronization2Features synchronization2_features{};
|
||||
synchronization2_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES;
|
||||
synchronization2_features.pNext = nullptr;
|
||||
|
||||
VkPhysicalDeviceFeatures2 features{};
|
||||
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
features.pNext = &synchronization2_features;
|
||||
|
||||
vkGetPhysicalDeviceFeatures2(physical_device, &features);
|
||||
|
||||
if (synchronization2_features.synchronization2 != VK_TRUE)
|
||||
{
|
||||
ASL_LOG_INFO("Device {}: synchronization2 not supported", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t queue_family_count{};
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
|
||||
queue_family_prps.resize_zero(queue_family_count);
|
||||
@ -230,9 +253,14 @@ static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device,
|
||||
.pQueuePriorities = &queue_priority,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceSynchronization2Features synchronization2_features{};
|
||||
synchronization2_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES;
|
||||
synchronization2_features.pNext = nullptr;
|
||||
synchronization2_features.synchronization2 = VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.pNext = &synchronization2_features,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queue_create_info,
|
||||
@ -258,6 +286,57 @@ static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device,
|
||||
return device;
|
||||
}
|
||||
|
||||
struct FrameResources : asl::intrusive_list_node<FrameResources>
|
||||
{
|
||||
VkFence complete_fence = VK_NULL_HANDLE;
|
||||
VkCommandPool command_pool = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
class DependencyInfoBuilder : public vulkan_sync::DependencyInfoBuilder
|
||||
{
|
||||
// @Todo Configure allocator
|
||||
|
||||
asl::buffer<VkImageMemoryBarrier2> m_image_barriers;
|
||||
asl::buffer<VkBufferMemoryBarrier2> m_buffer_barriers;
|
||||
|
||||
public:
|
||||
void add_image_barrier(const VkImageMemoryBarrier2& barrier) override
|
||||
{
|
||||
m_image_barriers.push(barrier);
|
||||
}
|
||||
|
||||
void add_buffer_barrier(const VkBufferMemoryBarrier2& barrier) override
|
||||
{
|
||||
m_buffer_barriers.push(barrier);
|
||||
}
|
||||
|
||||
void apply(VkCommandBuffer command_buffer)
|
||||
{
|
||||
if (m_image_barriers.is_empty() &&
|
||||
m_buffer_barriers.is_empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VkDependencyInfo dependency_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.pNext = nullptr,
|
||||
.dependencyFlags = 0,
|
||||
.memoryBarrierCount = 0,
|
||||
.pMemoryBarriers = nullptr,
|
||||
.bufferMemoryBarrierCount = static_cast<uint32_t>(m_buffer_barriers.size()),
|
||||
.pBufferMemoryBarriers = m_buffer_barriers.data(),
|
||||
.imageMemoryBarrierCount = static_cast<uint32_t>(m_image_barriers.size()),
|
||||
.pImageMemoryBarriers = m_image_barriers.data(),
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier2(command_buffer, &dependency_info);
|
||||
|
||||
m_image_barriers.clear();
|
||||
m_buffer_barriers.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class GpuImpl : public Gpu
|
||||
{
|
||||
bool m_destroyed{};
|
||||
@ -269,8 +348,22 @@ class GpuImpl : public Gpu
|
||||
VkDevice m_device;
|
||||
VkQueue m_queue;
|
||||
|
||||
struct Image
|
||||
{
|
||||
vulkan_sync::ImageState state;
|
||||
VkImage image{};
|
||||
};
|
||||
|
||||
asl::option<VkSwapchainKHR> m_swapchain;
|
||||
asl::buffer<VkImage> m_swapchain_images;
|
||||
asl::buffer<Image> m_swapchain_images;
|
||||
|
||||
VkSemaphore m_swapchain_image_acquire_semaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore m_queue_complete_semaphore = VK_NULL_HANDLE;
|
||||
|
||||
asl::GlobalHeap m_allocator; // @Todo Make this configurable
|
||||
asl::IntrusiveList<FrameResources> m_in_flight_frames;
|
||||
|
||||
DependencyInfoBuilder m_dependency_builder;
|
||||
|
||||
public:
|
||||
GpuImpl(
|
||||
@ -286,6 +379,8 @@ public:
|
||||
, m_queue_family_index{queue_family_index}
|
||||
, m_device{device}
|
||||
, m_queue{queue}
|
||||
, m_swapchain_image_acquire_semaphore{create_semaphore()}
|
||||
, m_queue_complete_semaphore{create_semaphore()}
|
||||
{
|
||||
}
|
||||
|
||||
@ -300,6 +395,13 @@ public:
|
||||
{
|
||||
ASL_ASSERT(!m_destroyed);
|
||||
m_destroyed = true;
|
||||
|
||||
vkDeviceWaitIdle(m_device);
|
||||
|
||||
recycle_resources();
|
||||
|
||||
destroy_semaphore(m_swapchain_image_acquire_semaphore);
|
||||
destroy_semaphore(m_queue_complete_semaphore);
|
||||
|
||||
if (m_swapchain.has_value())
|
||||
{
|
||||
@ -344,9 +446,9 @@ public:
|
||||
{
|
||||
if (f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
|
||||
(f.format == VK_FORMAT_B8G8R8_UNORM ||
|
||||
f.format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
f.format == VK_FORMAT_R8G8B8_UNORM ||
|
||||
f.format == VK_FORMAT_R8G8B8A8_UNORM))
|
||||
f.format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
f.format == VK_FORMAT_R8G8B8_UNORM ||
|
||||
f.format == VK_FORMAT_R8G8B8A8_UNORM))
|
||||
{
|
||||
format = f;
|
||||
break;
|
||||
@ -402,11 +504,24 @@ public:
|
||||
m_swapchain = swapchain;
|
||||
|
||||
vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, nullptr);
|
||||
m_swapchain_images.resize_zero(count);
|
||||
res = vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, m_swapchain_images.data());
|
||||
if (res != VK_SUCCESS)
|
||||
|
||||
{
|
||||
return asl::runtime_error("Couldn't retrieve Vulkan swapchain images: {}", res);
|
||||
m_swapchain_images.resize(count);
|
||||
|
||||
// @Todo Good candidate for temporary allocation
|
||||
asl::buffer<VkImage> images;
|
||||
images.resize_zero(count);
|
||||
|
||||
res = vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, images.data());
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
return asl::runtime_error("Couldn't retrieve Vulkan swapchain images: {}", res);
|
||||
}
|
||||
|
||||
for (int64_t i = 0; i < count; ++i)
|
||||
{
|
||||
m_swapchain_images[i].image = images[i];
|
||||
}
|
||||
}
|
||||
|
||||
ASL_LOG_INFO("Vulkan swapchain created ({}x{} with {} images)",
|
||||
@ -417,25 +532,60 @@ public:
|
||||
return asl::ok();
|
||||
}
|
||||
|
||||
asl::status frame_opt()
|
||||
VkSemaphore create_semaphore()
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphore_create_info{
|
||||
static constexpr VkSemaphoreCreateInfo semaphore_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkSemaphore acquire_semaphore{};
|
||||
VkSemaphore queue_semaphore{};
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &acquire_semaphore);
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &queue_semaphore);
|
||||
VkSemaphore semaphore{};
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &semaphore);
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
void destroy_semaphore(VkSemaphore semaphore)
|
||||
{
|
||||
vkDestroySemaphore(m_device, semaphore, VK_ALLOCATOR);
|
||||
}
|
||||
|
||||
VkFence create_fence()
|
||||
{
|
||||
static constexpr VkFenceCreateInfo fence_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkFence fence{};
|
||||
vkCreateFence(m_device, &fence_create_info, VK_ALLOCATOR, &fence);
|
||||
return fence;
|
||||
}
|
||||
|
||||
void destroy_fence(VkFence fence)
|
||||
{
|
||||
vkDestroyFence(m_device, fence, VK_ALLOCATOR);
|
||||
}
|
||||
|
||||
asl::status frame_opt()
|
||||
{
|
||||
uint32_t image_index{};
|
||||
VkResult res = vkAcquireNextImageKHR(m_device, m_swapchain.value(), 0xffff'ffff'ffff'ffffLLU, acquire_semaphore, VK_NULL_HANDLE, &image_index);
|
||||
|
||||
VkResult res = vkAcquireNextImageKHR(
|
||||
m_device,
|
||||
m_swapchain.value(),
|
||||
0xffff'ffff'ffff'ffffLLU,
|
||||
m_swapchain_image_acquire_semaphore,
|
||||
VK_NULL_HANDLE,
|
||||
&image_index);
|
||||
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
return asl::runtime_error("Couldn't acquire swapchain image: {}", res);
|
||||
}
|
||||
|
||||
auto& swapchain_image = m_swapchain_images[image_index];
|
||||
|
||||
VkCommandPoolCreateInfo command_pool_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
@ -479,26 +629,12 @@ public:
|
||||
return asl::runtime_error("Couldn't begin command buffer: {}", res);
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier1{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = m_swapchain_images[image_index],
|
||||
.subresourceRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier1);
|
||||
vulkan_sync::synchronize_resource(
|
||||
swapchain_image.image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
&swapchain_image.state,
|
||||
vulkan_sync::Usage::kImageClear,
|
||||
&m_dependency_builder);
|
||||
|
||||
VkClearColorValue clear_color{
|
||||
.float32 = { 0.0F, 0.137F, 0.4F, 1.0F },
|
||||
@ -507,33 +643,23 @@ public:
|
||||
VkImageSubresourceRange range{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
};
|
||||
|
||||
vkCmdClearColorImage(command_buffer, m_swapchain_images[image_index], VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range);
|
||||
m_dependency_builder.apply(command_buffer);
|
||||
vkCmdClearColorImage(command_buffer, swapchain_image.image, swapchain_image.state.current_layout, &clear_color, 1, &range);
|
||||
|
||||
VkImageMemoryBarrier barrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = m_swapchain_images[image_index],
|
||||
.subresourceRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vulkan_sync::synchronize_resource(
|
||||
swapchain_image.image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
&swapchain_image.state,
|
||||
vulkan_sync::Usage::kImagePresent,
|
||||
&m_dependency_builder);
|
||||
|
||||
m_dependency_builder.apply(command_buffer);
|
||||
|
||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier2);
|
||||
|
||||
res = vkEndCommandBuffer(command_buffer);
|
||||
if (res != VK_SUCCESS)
|
||||
@ -541,21 +667,46 @@ public:
|
||||
return asl::runtime_error("Couldn't end command buffer: {}", res);
|
||||
}
|
||||
|
||||
VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkFence fence = create_fence();
|
||||
|
||||
VkSubmitInfo submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
VkSemaphoreSubmitInfo semaphore_wait_submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &acquire_semaphore,
|
||||
.pWaitDstStageMask = &wait_dst_stage_mask,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer,
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = &queue_semaphore,
|
||||
.semaphore = m_swapchain_image_acquire_semaphore,
|
||||
.value = 0,
|
||||
.stageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT,
|
||||
.deviceIndex = 0,
|
||||
};
|
||||
|
||||
res = vkQueueSubmit(m_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
VkSemaphoreSubmitInfo semaphore_signal_submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.semaphore = m_queue_complete_semaphore,
|
||||
.value = 0,
|
||||
.stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
|
||||
.deviceIndex = 0,
|
||||
};
|
||||
|
||||
VkCommandBufferSubmitInfo command_buffer_submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandBuffer = command_buffer,
|
||||
.deviceMask = 0,
|
||||
};
|
||||
|
||||
VkSubmitInfo2 submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.waitSemaphoreInfoCount = 1,
|
||||
.pWaitSemaphoreInfos = &semaphore_wait_submit_info,
|
||||
.commandBufferInfoCount = 1,
|
||||
.pCommandBufferInfos = &command_buffer_submit_info,
|
||||
.signalSemaphoreInfoCount = 1,
|
||||
.pSignalSemaphoreInfos = &semaphore_signal_submit_info,
|
||||
};
|
||||
|
||||
res = vkQueueSubmit2(m_queue, 1, &submit_info, fence);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
return asl::runtime_error("Couldn't submit queue: {}", res);
|
||||
@ -565,7 +716,7 @@ public:
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &queue_semaphore,
|
||||
.pWaitSemaphores = &m_queue_complete_semaphore,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &m_swapchain.value(),
|
||||
.pImageIndices = &image_index,
|
||||
@ -578,20 +729,49 @@ public:
|
||||
return asl::runtime_error("Couldn't present queue: {}", res);
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(m_device);
|
||||
vkDestroySemaphore(m_device, acquire_semaphore, VK_ALLOCATOR);
|
||||
vkDestroySemaphore(m_device, queue_semaphore, VK_ALLOCATOR);
|
||||
vkDestroyCommandPool(m_device, command_pool, VK_ALLOCATOR);
|
||||
auto* frame_resources = asl::alloc_new<FrameResources>(m_allocator);
|
||||
frame_resources->command_pool = command_pool;
|
||||
frame_resources->complete_fence = fence;
|
||||
|
||||
m_in_flight_frames.push_front(frame_resources);
|
||||
|
||||
return asl::ok();
|
||||
}
|
||||
|
||||
void recycle_resources()
|
||||
{
|
||||
while (!m_in_flight_frames.is_empty())
|
||||
{
|
||||
auto* frame = m_in_flight_frames.back();
|
||||
auto status = vkGetFenceStatus(m_device, frame->complete_fence);
|
||||
|
||||
if (status == VK_NOT_READY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
{
|
||||
ASL_LOG_ERROR("Error on frame fence query: {}", status);
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_fence(frame->complete_fence);
|
||||
vkDestroyCommandPool(m_device, frame->command_pool, VK_ALLOCATOR);
|
||||
|
||||
m_in_flight_frames.pop_back();
|
||||
asl::alloc_delete(m_allocator, frame);
|
||||
}
|
||||
}
|
||||
|
||||
void frame() override
|
||||
{
|
||||
recycle_resources();
|
||||
|
||||
auto s = frame_opt();
|
||||
if (!s.ok())
|
||||
{
|
||||
ASL_LOG_ERROR("{}", s);
|
||||
ASL_LOG_ERROR("Frame error: {}", s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -22,7 +22,7 @@ int SDL_main(int /* argc */, char* /* argv */[])
|
||||
ASL_LOG_ERROR("Couldn't initialize GPU: {}", gpu_opt);
|
||||
return 1;
|
||||
}
|
||||
auto gpu = ASL_MOVE(gpu_opt).value();
|
||||
auto gpu = std::move(gpu_opt).value();
|
||||
|
||||
bool running = true;
|
||||
while (running)
|
||||
|
3
hk21/vulkan/BUILD.bazel
Normal file
3
hk21/vulkan/BUILD.bazel
Normal file
@ -0,0 +1,3 @@
|
||||
# Copyright 2025 Steven Le Rouzic
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
@ -3,9 +3,9 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cc_library(
|
||||
name = "vulkan_loader",
|
||||
name = "loader",
|
||||
hdrs = [
|
||||
"api.hpp",
|
||||
"loader.hpp",
|
||||
],
|
||||
srcs = [
|
||||
"loader.cpp",
|
@ -16,7 +16,8 @@
|
||||
FN(vkGetDeviceProcAddr) \
|
||||
FN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
|
||||
FN(vkGetPhysicalDeviceSurfaceFormatsKHR) \
|
||||
FN(vkGetPhysicalDeviceSurfacePresentModesKHR)
|
||||
FN(vkGetPhysicalDeviceSurfacePresentModesKHR) \
|
||||
FN(vkGetPhysicalDeviceFeatures2)
|
||||
|
||||
#define VULKAN_DEVICE_FNS \
|
||||
FN(vkDestroyDevice) \
|
||||
@ -35,8 +36,12 @@
|
||||
FN(vkFreeCommandBuffers) \
|
||||
FN(vkBeginCommandBuffer) \
|
||||
FN(vkEndCommandBuffer) \
|
||||
FN(vkQueueSubmit) \
|
||||
FN(vkQueueSubmit2) \
|
||||
FN(vkCreateSemaphore) \
|
||||
FN(vkDestroySemaphore) \
|
||||
FN(vkCmdPipelineBarrier) \
|
||||
FN(vkCmdClearColorImage)
|
||||
FN(vkCmdPipelineBarrier2) \
|
||||
FN(vkCmdClearColorImage) \
|
||||
FN(vkCreateFence) \
|
||||
FN(vkDestroyFence) \
|
||||
FN(vkGetFenceStatus)
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "hk21/vulkan_loader/api.hpp"
|
||||
#include "hk21/vulkan/loader/loader.hpp"
|
||||
|
||||
#define FN(NAME) PFN_##NAME NAME;
|
||||
VULKAN_GLOBAL_FNS
|
@ -7,12 +7,9 @@
|
||||
#include <asl/base/integers.hpp>
|
||||
#include <asl/types/status.hpp>
|
||||
|
||||
#define VK_NO_STDDEF_H
|
||||
#define VK_NO_STDINT_H
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include <vulkan.h>
|
||||
|
||||
#include "hk21/vulkan_loader/fns.hpp"
|
||||
#include "hk21/vulkan/loader/fns.hpp"
|
||||
|
||||
#define FN(NAME) extern PFN_##NAME NAME;
|
||||
VULKAN_GLOBAL_FNS
|
33
hk21/vulkan/sync/BUILD.bazel
Normal file
33
hk21/vulkan/sync/BUILD.bazel
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright 2025 Steven Le Rouzic
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cc_library(
|
||||
name = "sync",
|
||||
hdrs = [
|
||||
"sync.hpp",
|
||||
],
|
||||
srcs = [
|
||||
"sync.cpp",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/vulkan",
|
||||
"@asl//asl/base",
|
||||
"@asl//asl/types:option",
|
||||
"@asl//asl/types:span",
|
||||
],
|
||||
visibility = ["//:__subpackages__"],
|
||||
applicable_licenses = ["//:license"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "tests",
|
||||
srcs = [
|
||||
"sync_tests.cpp",
|
||||
],
|
||||
deps = [
|
||||
":sync",
|
||||
"@asl//asl/containers:buffer",
|
||||
"@asl//asl/testing",
|
||||
],
|
||||
)
|
252
hk21/vulkan/sync/sync.cpp
Normal file
252
hk21/vulkan/sync/sync.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
// Copyright 2025 Steven Le Rouzic
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "hk21/vulkan/sync/sync.hpp"
|
||||
|
||||
#include <asl/types/option.hpp>
|
||||
|
||||
// All of this is largely inspired by nicegraf's synchronization utility.
|
||||
// See https://github.com/nicebyte/nicegraf/blob/3a291433fdb4fd9cf38356f297ff1d851617f0f5/source/ngf-vk/impl.c#L2718
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum StageAccess : uint32_t
|
||||
{
|
||||
kClearStageTransferWrite = 0x0000'0001U,
|
||||
kFragmentStageShaderSampled = 0x0000'0002U,
|
||||
kVertexStageShaderSampled = 0x0000'0004U,
|
||||
kColorAttachmentWrite = 0x0000'0008U,
|
||||
};
|
||||
|
||||
constexpr VkAccessFlags kWriteAccessMask =
|
||||
VK_ACCESS_2_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_2_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_2_HOST_WRITE_BIT
|
||||
| VK_ACCESS_2_MEMORY_WRITE_BIT
|
||||
| VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
|
||||
|
||||
struct UsageInfo
|
||||
{
|
||||
uint32_t stage_access_mask{};
|
||||
VkAccessFlags2 access_flags{};
|
||||
VkPipelineStageFlags2 pipeline_stage_flags{};
|
||||
VkImageLayout image_layout{};
|
||||
};
|
||||
|
||||
const auto kUsageInfos = ([]() static {
|
||||
using namespace vulkan_sync;
|
||||
|
||||
static UsageInfo info[asl::to_underlying(Usage::kCount_)]{};
|
||||
|
||||
info[asl::to_underlying(Usage::kImageClear)] = UsageInfo{
|
||||
.stage_access_mask = StageAccess::kClearStageTransferWrite,
|
||||
.access_flags = VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
.pipeline_stage_flags = VK_PIPELINE_STAGE_2_CLEAR_BIT,
|
||||
.image_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
};
|
||||
|
||||
info[asl::to_underlying(Usage::kImagePresent)] = UsageInfo{
|
||||
.stage_access_mask = 0,
|
||||
.access_flags = VK_ACCESS_2_NONE,
|
||||
.pipeline_stage_flags = VK_PIPELINE_STAGE_2_NONE,
|
||||
.image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
};
|
||||
|
||||
info[asl::to_underlying(Usage::kImageSampledInFragmentShader)] = UsageInfo{
|
||||
.stage_access_mask = StageAccess::kFragmentStageShaderSampled,
|
||||
.access_flags = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
|
||||
.pipeline_stage_flags = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
|
||||
.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
|
||||
info[asl::to_underlying(Usage::kImageSampledInVertexShader)] = UsageInfo{
|
||||
.stage_access_mask = StageAccess::kVertexStageShaderSampled,
|
||||
.access_flags = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
|
||||
.pipeline_stage_flags = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT,
|
||||
.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
|
||||
info[asl::to_underlying(Usage::kImageColorWriteAttachment)] = UsageInfo{
|
||||
.stage_access_mask = StageAccess::kColorAttachmentWrite,
|
||||
.access_flags = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.pipeline_stage_flags = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.image_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
return asl::span(info);
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// We use an image barrier as a common structure for image and buffer barriers.
|
||||
// The only differences are the resource, the subresource range, and the image layouts.
|
||||
// We just discard whatever we don't need and fill the more specific fields outside.
|
||||
asl::option<VkImageMemoryBarrier2> synchronize_resource_(
|
||||
vulkan_sync::ResourceState* state,
|
||||
VkImageLayout* state_layout,
|
||||
vulkan_sync::Usage new_usage)
|
||||
{
|
||||
const UsageInfo& usage_info = kUsageInfos[asl::to_underlying(new_usage)];
|
||||
|
||||
const bool is_read_only_access = (usage_info.access_flags & kWriteAccessMask) == 0U;
|
||||
|
||||
const bool needs_layout_transition = *state_layout != usage_info.image_layout;
|
||||
|
||||
const bool needs_write = needs_layout_transition || !is_read_only_access;
|
||||
|
||||
VkImageMemoryBarrier2 barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = 0,
|
||||
.srcAccessMask = 0,
|
||||
.dstStageMask = 0,
|
||||
.dstAccessMask = 0,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = VK_NULL_HANDLE,
|
||||
.subresourceRange = {},
|
||||
};
|
||||
|
||||
if (needs_write)
|
||||
{
|
||||
barrier.srcStageMask |= asl::exchange(state->active_readers_pipeline_stage_mask, VK_PIPELINE_STAGE_2_NONE);
|
||||
barrier.srcAccessMask |= asl::exchange(state->active_readers_access_mask, VK_ACCESS_2_NONE);
|
||||
state->has_seen_last_write = 0;
|
||||
|
||||
// If there was to read since last write, but there was a write,
|
||||
// synchronize with last write instead.
|
||||
if (barrier.srcStageMask == VK_PIPELINE_STAGE_2_NONE &&
|
||||
state->last_writer_pipeline_stage_mask != VK_PIPELINE_STAGE_2_NONE)
|
||||
{
|
||||
barrier.srcStageMask |= state->last_writer_pipeline_stage_mask;
|
||||
barrier.srcAccessMask |= state->last_writer_access_mask;
|
||||
}
|
||||
|
||||
// Last write is now the new usage.
|
||||
state->last_writer_pipeline_stage_mask = usage_info.pipeline_stage_flags;
|
||||
state->last_writer_access_mask = usage_info.access_flags;
|
||||
|
||||
// If this is a read-only that is considered a write (layout transition)
|
||||
// we also record the reader info, because it acts as if this read has been
|
||||
// synchronized.
|
||||
if (is_read_only_access)
|
||||
{
|
||||
state->has_seen_last_write |= usage_info.stage_access_mask;
|
||||
state->active_readers_access_mask |= usage_info.access_flags;
|
||||
state->active_readers_pipeline_stage_mask |= usage_info.pipeline_stage_flags;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there was a previous write we need to synchronize with, and this
|
||||
// access has not been synchronized with it yet, synchronize.
|
||||
if (state->last_writer_pipeline_stage_mask != VK_PIPELINE_STAGE_2_NONE
|
||||
&& (state->has_seen_last_write & usage_info.stage_access_mask) != usage_info.stage_access_mask)
|
||||
{
|
||||
barrier.srcStageMask |= state->last_writer_pipeline_stage_mask;
|
||||
barrier.srcAccessMask |= state->last_writer_access_mask;
|
||||
}
|
||||
|
||||
// Record this reader info.
|
||||
state->has_seen_last_write |= usage_info.stage_access_mask;
|
||||
state->active_readers_access_mask |= usage_info.access_flags;
|
||||
state->active_readers_pipeline_stage_mask |= usage_info.pipeline_stage_flags;
|
||||
}
|
||||
|
||||
// If the barrier has been filled or we need a layout transition, emit a barrier.
|
||||
if (barrier.srcStageMask != VK_PIPELINE_STAGE_2_NONE || needs_layout_transition)
|
||||
{
|
||||
barrier.dstStageMask |= usage_info.pipeline_stage_flags;
|
||||
barrier.dstAccessMask |= usage_info.access_flags;
|
||||
|
||||
if (barrier.dstStageMask == VK_PIPELINE_STAGE_2_NONE)
|
||||
{
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
|
||||
if (barrier.srcStageMask == VK_PIPELINE_STAGE_2_NONE)
|
||||
{
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
|
||||
if (needs_layout_transition)
|
||||
{
|
||||
barrier.oldLayout = asl::exchange(*state_layout, usage_info.image_layout);
|
||||
barrier.newLayout = usage_info.image_layout;
|
||||
}
|
||||
|
||||
return barrier;
|
||||
}
|
||||
|
||||
return asl::nullopt;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vulkan_sync
|
||||
{
|
||||
|
||||
void synchronize_resource(
|
||||
VkImage image, VkImageAspectFlags aspects,
|
||||
ImageState* state, Usage new_usage, DependencyInfoBuilder* builder)
|
||||
{
|
||||
const UsageInfo& usage_info = kUsageInfos[asl::to_underlying(new_usage)];
|
||||
ASL_ASSERT(usage_info.image_layout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
auto barrier_opt = synchronize_resource_(state, &state->current_layout, new_usage);
|
||||
if (barrier_opt.has_value())
|
||||
{
|
||||
auto& barrier = barrier_opt.value();
|
||||
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange = {
|
||||
.aspectMask = aspects,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
};
|
||||
|
||||
builder->add_image_barrier(barrier);
|
||||
}
|
||||
}
|
||||
|
||||
void synchronize_resource(
|
||||
VkBuffer buffer, BufferState* state,
|
||||
Usage new_usage, DependencyInfoBuilder* builder)
|
||||
{
|
||||
const UsageInfo& usage_info = kUsageInfos[asl::to_underlying(new_usage)];
|
||||
ASL_ASSERT(usage_info.image_layout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
VkImageLayout dummy_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
auto barrier_opt = synchronize_resource_(state, &dummy_layout, new_usage);
|
||||
if (barrier_opt.has_value())
|
||||
{
|
||||
const auto& image_barrier = barrier_opt.value();
|
||||
|
||||
VkBufferMemoryBarrier2 barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = image_barrier.srcStageMask,
|
||||
.srcAccessMask = image_barrier.srcAccessMask,
|
||||
.dstStageMask = image_barrier.dstStageMask,
|
||||
.dstAccessMask = image_barrier.dstAccessMask,
|
||||
.srcQueueFamilyIndex = image_barrier.srcQueueFamilyIndex,
|
||||
.dstQueueFamilyIndex = image_barrier.dstQueueFamilyIndex,
|
||||
.buffer = buffer,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
};
|
||||
|
||||
builder->add_buffer_barrier(barrier);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vulkan_sync
|
||||
|
64
hk21/vulkan/sync/sync.hpp
Normal file
64
hk21/vulkan/sync/sync.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2025 Steven Le Rouzic
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <asl/base/integers.hpp>
|
||||
#include <asl/base/utility.hpp>
|
||||
#include <asl/types/span.hpp>
|
||||
#include <vulkan.h>
|
||||
|
||||
namespace vulkan_sync
|
||||
{
|
||||
|
||||
class DependencyInfoBuilder
|
||||
{
|
||||
public:
|
||||
DependencyInfoBuilder() = default;
|
||||
ASL_DEFAULT_COPY_MOVE(DependencyInfoBuilder);
|
||||
virtual ~DependencyInfoBuilder() = default;
|
||||
|
||||
virtual void add_image_barrier(const VkImageMemoryBarrier2&) = 0;
|
||||
virtual void add_buffer_barrier(const VkBufferMemoryBarrier2&) = 0;
|
||||
};
|
||||
|
||||
struct ResourceState
|
||||
{
|
||||
VkAccessFlags2 last_writer_access_mask{};
|
||||
VkPipelineStageFlags2 last_writer_pipeline_stage_mask{};
|
||||
|
||||
VkAccessFlags2 active_readers_access_mask{};
|
||||
VkPipelineStageFlags2 active_readers_pipeline_stage_mask{};
|
||||
|
||||
// Which StageAccess-es have seen the previous write.
|
||||
uint32_t has_seen_last_write{};
|
||||
};
|
||||
|
||||
struct BufferState : public ResourceState {};
|
||||
|
||||
struct ImageState : public ResourceState
|
||||
{
|
||||
VkImageLayout current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
};
|
||||
|
||||
enum class Usage : uint32_t
|
||||
{
|
||||
kImageClear,
|
||||
kImagePresent,
|
||||
kImageSampledInFragmentShader,
|
||||
kImageSampledInVertexShader,
|
||||
kImageColorWriteAttachment,
|
||||
|
||||
kCount_,
|
||||
};
|
||||
|
||||
void synchronize_resource(
|
||||
VkImage, VkImageAspectFlags,
|
||||
ImageState*, Usage new_usage, DependencyInfoBuilder*);
|
||||
|
||||
void synchronize_resource(
|
||||
VkBuffer, BufferState*,
|
||||
Usage new_usage, DependencyInfoBuilder*);
|
||||
|
||||
} // namespace vulkan_sync
|
162
hk21/vulkan/sync/sync_tests.cpp
Normal file
162
hk21/vulkan/sync/sync_tests.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2025 Steven Le Rouzic
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "hk21/vulkan/sync/sync.hpp"
|
||||
|
||||
#include <asl/containers/buffer.hpp>
|
||||
#include <asl/testing/testing.hpp>
|
||||
|
||||
class DependencyInfoBuilder : public vulkan_sync::DependencyInfoBuilder
|
||||
{
|
||||
asl::buffer<VkImageMemoryBarrier2> m_image_barriers;
|
||||
asl::buffer<VkBufferMemoryBarrier2> m_buffer_barriers;
|
||||
|
||||
public:
|
||||
void add_image_barrier(const VkImageMemoryBarrier2& barrier) override
|
||||
{
|
||||
m_image_barriers.push(barrier);
|
||||
}
|
||||
|
||||
void add_buffer_barrier(const VkBufferMemoryBarrier2& barrier) override
|
||||
{
|
||||
m_buffer_barriers.push(barrier);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_image_barriers.clear();
|
||||
m_buffer_barriers.clear();
|
||||
}
|
||||
|
||||
asl::span<const VkImageMemoryBarrier2> image_barriers() const
|
||||
{
|
||||
return m_image_barriers;
|
||||
}
|
||||
|
||||
asl::span<const VkBufferMemoryBarrier2> buffer_barriers() const
|
||||
{
|
||||
return m_buffer_barriers;
|
||||
}
|
||||
};
|
||||
|
||||
ASL_TEST(clear_and_present)
|
||||
{
|
||||
DependencyInfoBuilder builder;
|
||||
vulkan_sync::ImageState state{};
|
||||
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageClear, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
auto barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_NONE);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageClear, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImagePresent, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_NONE);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageClear, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_NONE);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
|
||||
ASL_TEST(clear_and_draw)
|
||||
{
|
||||
DependencyInfoBuilder builder;
|
||||
vulkan_sync::ImageState state{};
|
||||
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageColorWriteAttachment, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
auto barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_NONE);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageSampledInVertexShader, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_SHADER_SAMPLED_READ_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageSampledInFragmentShader, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT);
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_SHADER_SAMPLED_READ_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_SHADER_SAMPLED_READ_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageSampledInVertexShader, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 0);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
builder.reset();
|
||||
synchronize_resource(VK_NULL_HANDLE, {}, &state, vulkan_sync::Usage::kImageClear, &builder);
|
||||
ASL_TEST_ASSERT(builder.buffer_barriers().size() == 0);
|
||||
ASL_TEST_ASSERT(builder.image_barriers().size() == 1);
|
||||
barrier = builder.image_barriers()[0];
|
||||
ASL_TEST_EXPECT(barrier.srcStageMask == (VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT));
|
||||
ASL_TEST_EXPECT(barrier.srcAccessMask == VK_ACCESS_2_SHADER_SAMPLED_READ_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstStageMask == VK_PIPELINE_STAGE_2_CLEAR_BIT);
|
||||
ASL_TEST_EXPECT(barrier.dstAccessMask == VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
ASL_TEST_EXPECT(barrier.oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
ASL_TEST_EXPECT(barrier.newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
ASL_TEST_EXPECT(state.current_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
|
5
vendor/vulkan/BUILD.bazel
vendored
5
vendor/vulkan/BUILD.bazel
vendored
@ -21,6 +21,11 @@ cc_library(
|
||||
"vulkan.h",
|
||||
"vulkan_core.h",
|
||||
],
|
||||
defines = [
|
||||
"VK_NO_STDDER_H",
|
||||
"VK_NO_STDINT_H",
|
||||
"VK_NO_PROTOTYPES",
|
||||
],
|
||||
includes = [
|
||||
".",
|
||||
],
|
||||
|
Reference in New Issue
Block a user