diff options
author | Paul Thomson <paulthomson@google.com> | 2022-02-08 14:31:07 +0000 |
---|---|---|
committer | Paul Thomson <paulthomson@google.com> | 2022-02-08 14:31:07 +0000 |
commit | 3f8fbfe46bdb1dd1526687a84c644c1b2846a636 (patch) | |
tree | 7bf7238d34d1cdf3671a43fe4147a53606453504 | |
parent | f3b1d8fd9a3dfb99df5b8ba7900b3493ee0329a8 (diff) | |
parent | 615ab4863f7d2e31d3037d0c6a0f641fd6fc0d07 (diff) | |
download | amber-3f8fbfe46bdb1dd1526687a84c644c1b2846a636.tar.gz |
Merge commit '615ab4863f7d2e31d3037d0c6a0f641fd6fc0d07' into mastert_frc_odp_330442040t_frc_odp_330442000t_frc_con_330443020t_frc_cbr_330443000t_frc_ase_330444010t_frc_art_330443060android-13.0.0_r83android-13.0.0_r82android-13.0.0_r81android-13.0.0_r80android-13.0.0_r79android-13.0.0_r78android-13.0.0_r77android-13.0.0_r76android-13.0.0_r75android-13.0.0_r74android-13.0.0_r73android-13.0.0_r72android-13.0.0_r71android-13.0.0_r70android-13.0.0_r69android-13.0.0_r68android-13.0.0_r67android-13.0.0_r66android-13.0.0_r65android-13.0.0_r64android-13.0.0_r63android-13.0.0_r62android-13.0.0_r61android-13.0.0_r60android-13.0.0_r59android-13.0.0_r58android-13.0.0_r57android-13.0.0_r56android-13.0.0_r55android-13.0.0_r54android-13.0.0_r53android-13.0.0_r52android-13.0.0_r51android-13.0.0_r50android-13.0.0_r49android-13.0.0_r48android-13.0.0_r47android-13.0.0_r46android-13.0.0_r45android-13.0.0_r44android-13.0.0_r43android-13.0.0_r42android-13.0.0_r41android-13.0.0_r40android-13.0.0_r39android-13.0.0_r38android-13.0.0_r37android-13.0.0_r36android-13.0.0_r35android-13.0.0_r34android-13.0.0_r33android-13.0.0_r32android-13.0.0_r30android-13.0.0_r29android-13.0.0_r28android-13.0.0_r27android-13.0.0_r24android-13.0.0_r23android-13.0.0_r22android-13.0.0_r21android-13.0.0_r20android-13.0.0_r19android-13.0.0_r18android-13.0.0_r17android-13.0.0_r16aml_uwb_331910010aml_uwb_331820070aml_uwb_331613010aml_uwb_331611010aml_uwb_331410010aml_uwb_331310030aml_uwb_331115000aml_uwb_331015040aml_uwb_330810010aml_tz4_332714070aml_tz4_332714050aml_tz4_332714010aml_tz4_331910000aml_tz4_331314030aml_tz4_331314020aml_tz4_331314010aml_tz4_331012050aml_tz4_331012040aml_tz4_331012000aml_go_wif_330911000aml_go_uwb_330912000aml_go_tz4_330912000aml_go_tet_330914010aml_go_swc_330913000aml_go_sta_330911000aml_go_sdk_330810000aml_go_sch_330911000aml_go_res_330912000aml_go_per_330912000aml_go_odp_330913000aml_go_odp_330912000aml_go_neu_330912000aml_go_net_330913000aml_go_mpr_330912000aml_go_ase_330913000aml_go_ads_330915100aml_go_ads_330915000aml_go_ads_330913000aml_go_adb_330913000aml_ase_331311020aml_ase_331112000aml_ase_331011020aml_ads_331920180aml_ads_331814200aml_ads_331710270aml_ads_331611190aml_ads_331511020aml_ads_331418080aml_ads_331131000android13-qpr3-s9-releaseandroid13-qpr3-s8-releaseandroid13-qpr3-s7-releaseandroid13-qpr3-s6-releaseandroid13-qpr3-s5-releaseandroid13-qpr3-s4-releaseandroid13-qpr3-s3-releaseandroid13-qpr3-s2-releaseandroid13-qpr3-s14-releaseandroid13-qpr3-s13-releaseandroid13-qpr3-s12-releaseandroid13-qpr3-s11-releaseandroid13-qpr3-s10-releaseandroid13-qpr3-s1-releaseandroid13-qpr3-releaseandroid13-qpr3-c-s8-releaseandroid13-qpr3-c-s7-releaseandroid13-qpr3-c-s6-releaseandroid13-qpr3-c-s5-releaseandroid13-qpr3-c-s4-releaseandroid13-qpr3-c-s3-releaseandroid13-qpr3-c-s2-releaseandroid13-qpr3-c-s12-releaseandroid13-qpr3-c-s11-releaseandroid13-qpr3-c-s10-releaseandroid13-qpr3-c-s1-releaseandroid13-qpr2-s9-releaseandroid13-qpr2-s8-releaseandroid13-qpr2-s7-releaseandroid13-qpr2-s6-releaseandroid13-qpr2-s5-releaseandroid13-qpr2-s3-releaseandroid13-qpr2-s2-releaseandroid13-qpr2-s12-releaseandroid13-qpr2-s11-releaseandroid13-qpr2-s10-releaseandroid13-qpr2-s1-releaseandroid13-qpr2-releaseandroid13-qpr2-b-s1-releaseandroid13-qpr1-s8-releaseandroid13-qpr1-s7-releaseandroid13-qpr1-s6-releaseandroid13-qpr1-s5-releaseandroid13-qpr1-s4-releaseandroid13-qpr1-s3-releaseandroid13-qpr1-s2-releaseandroid13-qpr1-s1-releaseandroid13-qpr1-releaseandroid13-mainline-uwb-releaseandroid13-mainline-tzdata4-releaseandroid13-mainline-go-wifi-releaseandroid13-mainline-go-uwb-releaseandroid13-mainline-go-tzdata4-releaseandroid13-mainline-go-tethering-releaseandroid13-mainline-go-sdkext-releaseandroid13-mainline-go-scheduling-releaseandroid13-mainline-go-resolv-releaseandroid13-mainline-go-permission-releaseandroid13-mainline-go-os-statsd-releaseandroid13-mainline-go-odp-releaseandroid13-mainline-go-neuralnetworks-releaseandroid13-mainline-go-networking-releaseandroid13-mainline-go-mediaprovider-releaseandroid13-mainline-go-media-swcodec-releaseandroid13-mainline-go-appsearch-releaseandroid13-mainline-go-adservices-releaseandroid13-mainline-go-adbd-releaseandroid13-mainline-appsearch-releaseandroid13-mainline-adservices-releaseandroid13-frc-odp-releaseandroid13-frc-conscrypt-releaseandroid13-frc-cellbroadcast-releaseandroid13-frc-art-releaseandroid13-devandroid13-d4-s2-releaseandroid13-d4-s1-releaseandroid13-d4-releaseandroid13-d3-s1-releaseandroid13-d2-releaseaml_tz4_332714010
Conflicts:
samples/Android.mk
Bug: b/201652781
Change-Id: Ia48f5389d9cde2b0730767e215d86e28cced7da6
68 files changed, 1901 insertions, 395 deletions
@@ -17,6 +17,7 @@ third_party/swiftshader third_party/vulkan-headers third_party/vulkan-loader third_party/vulkan-validationlayers/ +third_party/robin-hood-hashing .vs *.pyc @@ -25,5 +26,5 @@ third_party/vulkan-validationlayers/ [._]*.s[a-w][a-z] # C-Lion -.idea -cmake-build-debug +.idea/ +cmake-build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f65d5f..c064649 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,6 @@ endif() function(amber_default_compile_options TARGET) if (${COMPILER_IS_LIKE_GNU}) target_compile_options(${TARGET} PRIVATE - -std=c++11 -fno-exceptions -fvisibility=hidden -Wall @@ -230,7 +229,6 @@ function(amber_default_compile_options TARGET) endif() if (MSVC) - # Specify /EHs for exception handling. target_compile_options(${TARGET} PRIVATE /bigobj /EHsc @@ -266,6 +264,6 @@ endfunction() add_subdirectory(third_party) add_subdirectory(src) -if (${AMBER_ENABLE_SAMPLES} AND NOT ANDROID) +if (${AMBER_ENABLE_SAMPLES}) add_subdirectory(samples) endif() @@ -8,23 +8,25 @@ vars = { 'microsoft_git': 'https://github.com/Microsoft', 'nlohmann_git': 'https://github.com/nlohmann', 'swiftshader_git': 'https://swiftshader.googlesource.com', + 'martinus_git': 'https://github.com/martinus', - 'clspv_llvm_revision': '7e30989dabce9ddbca0cbad7a8f25fb4e756d334', - 'clspv_revision': 'e0406e7053d1bb46b4bbeb57f0f2bbfca32f5612', - 'cppdap_revision': '1fd23dda91e01550be1a421de307e6fedb2035a9', + 'clspv_llvm_revision': 'b70366c9c430e1eadd59d5a1dfbb9c4d84f83de5', + 'clspv_revision': 'f99809bdab1710846633b4ec24f5448263e75da7', + 'cppdap_revision': '88e89520148b2f95e17ca9348587a28215ffc921', 'cpplint_revision': '26470f9ccb354ff2f6d098f831271a1833701b28', - 'dxc_revision': '489c2e4d32417cd6693db5673ab071d82e1f5974', - 'glslang_revision': '7f6559d2802d0653541060f0909e33d137b9c8ba', - 'googletest_revision': '0555b0eacbc56df1fd762c6aa87bb84be9e4ce7e', - 'json_revision': '350ff4f7ced7c4117eae2fb93df02823c8021fcb', - 'lodepng_revision': '7fdcc96a5e5864eee72911c3ca79b1d9f0d12292', - 'shaderc_revision': '88f9156d7f6a2a30baed1ace196faa3bc5eccc05', - 'spirv_headers_revision': '5ab5c96198f30804a6a29961b8905f292a8ae600', - 'spirv_tools_revision': '1f2fcddd3963b9c29bf360daf7656c5977c2aadd', - 'swiftshader_revision': '04515da400d5fbc22d852af1369c4d46bd54991e', - 'vulkan_headers_revision': '11c6670b4a4f766ed4f1e777d1b3c3dc082dfa5f', - 'vulkan_loader_revision': 'be6ccb9ecaf77dfef59246a1e8502e99c8e1a511', - 'vulkan_validationlayers_revision': '0cb8cc8cfcb2b86a767c9516ac2d62edb4e38ebe', + 'dxc_revision': 'c45db48d565a9edc14b025e43b90e62264d06eea', + 'glslang_revision': '81cc10a498b25a90147cccd6e8939493c1e9e20e', + 'googletest_revision': '16f637fbf4ffc3f7a01fa4eceb7906634565242f', + 'json_revision': '4f8fba14066156b73f1189a2b8bd568bde5284c5', + 'lodepng_revision': '5601b8272a6850b7c5d693dd0c0e16da50be8d8d', + 'shaderc_revision': 'e72186b66bb90ed06aaf15cbdc9a053581a0616b', + 'spirv_headers_revision': 'b42ba6d92faf6b4938e6f22ddd186dbdacc98d78', + 'spirv_tools_revision': 'a73e724359a274d7cf4f4248eba5be1e7764fbfd', + 'swiftshader_revision': 'bca23447ad4667a7b79973569ab5d8d905d211ac', + 'vulkan_headers_revision': '1dace16d8044758d32736eb59802d171970e9448', + 'vulkan_loader_revision': '8aad559a09388ceb5b968af64a2b965d3886e5a0', + 'vulkan_validationlayers_revision': 'a6c1ddca49331d8addde052554487180ee8aec13', + 'robin_hood_hashing_revision': '24b3f50f9532153edc23b29ae277dcccfd75a462', } deps = { @@ -75,4 +77,7 @@ deps = { 'third_party/vulkan-loader': Var('khronos_git') + '/Vulkan-Loader.git@' + Var('vulkan_loader_revision'), + + 'third_party/robin-hood-hashing': Var('martinus_git') + '/robin-hood-hashing.git@' + + Var('robin_hood_hashing_revision'), } diff --git a/android_gradle/app/build.gradle b/android_gradle/app/build.gradle index 40c4c54..b756f6b 100644 --- a/android_gradle/app/build.gradle +++ b/android_gradle/app/build.gradle @@ -1,26 +1,37 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' +} android { - compileSdkVersion 29 - buildToolsVersion "29.0.2" + compileSdk 30 + buildToolsVersion "30.0.2" + ndkVersion "21.4.7075529" defaultConfig { applicationId "com.google.amber" minSdkVersion 24 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + externalNativeBuild { + cmake { + arguments "-DAMBER_USE_LOCAL_VULKAN=1" + targets "amber_ndk" + } + } } - sourceSets { - androidTest.manifest.srcFile "src/androidTest/AndroidManifest.xml" + externalNativeBuild { + cmake { + path "../../CMakeLists.txt" + } } - dependencies { - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test:rules:1.1.0' + sourceSets { + androidTest.manifest.srcFile "src/androidTest/AndroidManifest.xml" } buildTypes { @@ -29,6 +40,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt') } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { @@ -41,9 +56,10 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } diff --git a/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java b/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java index 4864843..ad92154 100644 --- a/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java +++ b/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java @@ -54,7 +54,7 @@ public class AmberLauncher { String stdout_file = args.getString("stdout", new File(outputDir, "amber_stdout.txt").toString()); String stderr_file = args.getString("stderr", new File(outputDir, "amber_stderr.txt").toString()); - int res = Amber.androidMain(args_list.toArray(new String[0]), stdout_file, stderr_file); + int res = Amber.androidHelper(args_list.toArray(new String[0]), stdout_file, stderr_file); // If the process crashes during the above call or we call System.exit below, the output // from `adb shell am instrument ...` will be: diff --git a/android_gradle/app/src/main/AndroidManifest.xml b/android_gradle/app/src/main/AndroidManifest.xml index 0ab9856..c74c390 100644 --- a/android_gradle/app/src/main/AndroidManifest.xml +++ b/android_gradle/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ <application android:allowBackup="true" + android:fullBackupOnly="true" android:label="Amber" android:supportsRtl="true"> <meta-data diff --git a/android_gradle/app/src/main/java/com/google/amber/Amber.java b/android_gradle/app/src/main/java/com/google/amber/Amber.java index 8319ccf..008c528 100644 --- a/android_gradle/app/src/main/java/com/google/amber/Amber.java +++ b/android_gradle/app/src/main/java/com/google/amber/Amber.java @@ -19,5 +19,5 @@ public class Amber { System.loadLibrary("amber_ndk"); } - public static native int androidMain(String[] args, String stdout_file, String stderr_file); + public static native int androidHelper(String[] args, String stdout_file, String stderr_file); } diff --git a/android_gradle/build.gradle b/android_gradle/build.gradle index 82c93bf..d340082 100644 --- a/android_gradle/build.gradle +++ b/android_gradle/build.gradle @@ -4,25 +4,16 @@ buildscript { repositories { google() - jcenter() - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0-alpha04' + classpath 'com.android.tools.build:gradle:7.0.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } -allprojects { - repositories { - google() - jcenter() - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } - } -} - task clean(type: Delete) { delete rootProject.buildDir } diff --git a/android_gradle/gradle.properties b/android_gradle/gradle.properties index 199d16e..4941ecd 100644 --- a/android_gradle/gradle.properties +++ b/android_gradle/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/android_gradle/gradle/wrapper/gradle-wrapper.jar b/android_gradle/gradle/wrapper/gradle-wrapper.jar Binary files differindex f6b961f..e708b1c 100644 --- a/android_gradle/gradle/wrapper/gradle-wrapper.jar +++ b/android_gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/android_gradle/gradle/wrapper/gradle-wrapper.properties b/android_gradle/gradle/wrapper/gradle-wrapper.properties index 421d5b6..e81b594 100644 --- a/android_gradle/gradle/wrapper/gradle-wrapper.properties +++ b/android_gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 09 14:37:37 GMT 2019 +#Sat Sep 25 16:43:12 BST 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-rc-1-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/android_gradle/settings.gradle b/android_gradle/settings.gradle index 9a979bb..2c4357f 100644 --- a/android_gradle/settings.gradle +++ b/android_gradle/settings.gradle @@ -1,2 +1,9 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} rootProject.name='Amber' include ':app' diff --git a/docs/amber_script.md b/docs/amber_script.md index 295cdc7..7c78d82 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -48,6 +48,20 @@ with: * `Storage16BitFeatures.storageInputOutput16` * `SubgroupSizeControl.subgroupSizeControl` * `SubgroupSizeControl.computeFullSubgroups` + * `SubgroupSupportedOperations.basic` + * `SubgroupSupportedOperations.vote` + * `SubgroupSupportedOperations.arithmetic` + * `SubgroupSupportedOperations.ballot` + * `SubgroupSupportedOperations.shuffle` + * `SubgroupSupportedOperations.shuffleRelative` + * `SubgroupSupportedOperations.clustered` + * `SubgroupSupportedOperations.quad` + * `SubgroupSupportedStages.vertex` + * `SubgroupSupportedStages.tessellationControl` + * `SubgroupSupportedStages.tessellationEvaluation` + * `SubgroupSupportedStages.geometry` + * `SubgroupSupportedStages.fragment` + * `SubgroupSupportedStages.compute` Extensions can be enabled with the `DEVICE_EXTENSION` and `INSTANCE_EXTENSION` @@ -427,6 +441,11 @@ The following commands are all specified within the `PIPELINE` command. POLYGON_MODE {mode} ``` +```groovy + # Set the number of patch control points used by tessellation. The default value is 3. + PATCH_CONTROL_POINTS {control_points} +``` + #### Compare operations * `never` * `less` @@ -478,6 +497,96 @@ The following commands are all specified within the `PIPELINE` command. END ``` +#### Blend factors +* `zero` +* `one` +* `src_color` +* `one_minus_src_color` +* `dst_color` +* `one_minus_dst_color` +* `src_alpha` +* `one_minus_src_alpha` +* `dst_alpha` +* `one_minus_dst_alpha` +* `constant_color` +* `one_minus_constant_color` +* `constant_alpha` +* `one_minus_constant_alpha` +* `src_alpha_saturate` +* `src1_color` +* `one_minus_src1_color` +* `src1_alpha` +* `one_minus_src1_alpha` + +#### Blend operations +* `add` +* `substract` +* `reverse_substract` +* `min` +* `max` + +The following operations also require VK_EXT_blend_operation_advanced +when using a Vulkan backend. +* `zero` +* `src` +* `dst` +* `src_over` +* `dst_over` +* `src_in` +* `dst_in` +* `src_out` +* `dst_out` +* `src_atop` +* `dst_atop` +* `xor` +* `multiply` +* `screen` +* `overlay` +* `darken` +* `lighten` +* `color_dodge` +* `color_burn` +* `hard_light` +* `soft_light` +* `difference` +* `exclusion` +* `invert` +* `invert_rgb` +* `linear_dodge` +* `linear_burn` +* `vivid_light` +* `linear_light` +* `pin_light` +* `hard_mix` +* `hsl_hue` +* `hsl_saturation` +* `hsl_color` +* `hsl_luminosity` +* `plus` +* `plus_clamped` +* `plus_clamped_alpha` +* `plus_darker` +* `minus` +* `minus_clamped` +* `contrast` +* `invert_org` +* `red` +* `green` +* `blue` + +```groovy + # Enable alpha blending and set blend factors and operations. Available + # blend factors and operations are listed above. + BLEND + SRC_COLOR_FACTOR {src_color_factor} + DST_COLOR_FACTOR {dst_color_factor} + COLOR_OP {color_op} + SRC_ALPHA_FACTOR {src_alpha_factor} + DST_ALPHA_FACTOR {dst_alpha_factor} + ALPHA_OP {alpha_op} + END +``` + ```groovy # Set the size of the render buffers. |width| and |height| are integers and # default to 250x250. @@ -536,6 +645,11 @@ contain image attachment content, depth/stencil content, uniform buffers, etc. # pipelines. BIND BUFFER {buffer_name} AS depth_stencil + # Attach |buffer_name| as a multisample resolve target. The order of resolve + # target images match with the order of color attachments that have more than + # one sample. + BIND BUFFER {buffer_name} AS resolve + # Attach |buffer_name| as the push_constant buffer. There can be only one # push constant buffer attached to a pipeline. BIND BUFFER {buffer_name} AS push_constant diff --git a/docs/debugger.md b/docs/debugger.md index 6c3208b..dc887d0 100644 --- a/docs/debugger.md +++ b/docs/debugger.md @@ -3,9 +3,7 @@ This document describes Amber's shader debugger testing framework, which allows developers to write tests for Vulkan drivers that expose shader debugging functionality via the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/). --- -**Work In Progress** - -Note that shader debugging is very much work-in-progress: +**Caveats** * Vulkan shader debugging currently does not have a formalized specification. A shader debugger implementation is being developed in [SwiftShader](https://swiftshader.googlesource.com/SwiftShader/), which one day may become a reference implementation for a formal specifiction. * Currently SwiftShader is the only Vulkan driver to implement a [DAP based shader debugger](https://swiftshader.googlesource.com/SwiftShader/+/refs/heads/master/docs/VulkanShaderDebugging.md). This implementation is also work-in-progress, and may significantly change. @@ -189,4 +187,4 @@ The `amber::Engine::Debugger` interface can be obtained from the `amber::Engine` * If the `amber::Command` holds a `amber::debug::Script`, then this script is executed on the `amber::Engine::Debugger` using the `amber::debug::Script::Run(amber::debug::Events *)` method, before the Vulkan command is executed. * The command is then executed with `amber::Executor::ExecuteCommand()` * Once the command has completed, all debugger threads are synchronized and debugger test results are collected with a call to `amber::Engine::Debugger::Flush()`. -* This process is repeated for all commands in the script.
\ No newline at end of file +* This process is repeated for all commands in the script. diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 3fa1882..1e91c4d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -74,3 +74,11 @@ target_include_directories(image_diff PRIVATE "${CMAKE_BINARY_DIR}") target_link_libraries(image_diff libamber "lodepng") amber_default_compile_options(image_diff) set_target_properties(image_diff PROPERTIES OUTPUT_NAME "image_diff") + +if (ANDROID) + add_library(amber_ndk SHARED android_helper.cc ${AMBER_SOURCES}) + target_include_directories(amber_ndk PRIVATE "${CMAKE_BINARY_DIR}") + target_link_libraries(amber_ndk libamber ${AMBER_EXTRA_LIBS}) + amber_default_compile_options(amber_ndk) + target_compile_definitions(amber_ndk PRIVATE AMBER_ANDROID_MAIN=1) +endif() diff --git a/samples/amber.cc b/samples/amber.cc index d037ba4..5973dba 100644 --- a/samples/amber.cc +++ b/samples/amber.cc @@ -447,7 +447,15 @@ std::string disassemble(const std::string& env, } // namespace +#ifdef AMBER_ANDROID_MAIN +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" +int android_main(int argc, const char** argv) { +#pragma clang diagnostic pop +#else int main(int argc, const char** argv) { +#endif std::vector<std::string> args(argv, argv + argc); Options options; SampleDelegate delegate; diff --git a/samples/android_main.cc b/samples/android_helper.cc index b24a9bb..7da69ad 100644 --- a/samples/android_main.cc +++ b/samples/android_helper.cc @@ -18,16 +18,20 @@ #include <string> #include <vector> -extern int main(int argc, const char** argv); +extern int android_main(int argc, const char** argv); -extern "C" JNIEXPORT JNICALL int Java_com_google_amber_Amber_androidMain( +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" + +extern "C" JNIEXPORT JNICALL int Java_com_google_amber_Amber_androidHelper( JNIEnv* env, jobject, jobjectArray args, jstring stdoutFile, jstring stderrFile) { - const char* stdout_file_cstr = env->GetStringUTFChars(stdoutFile, NULL); - const char* stderr_file_cstr = env->GetStringUTFChars(stderrFile, NULL); + const char* stdout_file_cstr = env->GetStringUTFChars(stdoutFile, nullptr); + const char* stderr_file_cstr = env->GetStringUTFChars(stderrFile, nullptr); // Redirect std output to a file freopen(stdout_file_cstr, "w", stdout); @@ -43,7 +47,7 @@ extern "C" JNIEXPORT JNICALL int Java_com_google_amber_Amber_androidMain( for (jsize i = 0; i < arg_count; i++) { jstring js = static_cast<jstring>(env->GetObjectArrayElement(args, i)); - const char* arg_cstr = env->GetStringUTFChars(js, NULL); + const char* arg_cstr = env->GetStringUTFChars(js, nullptr); argv_string.push_back(arg_cstr); env->ReleaseStringUTFChars(js, arg_cstr); } @@ -53,5 +57,7 @@ extern "C" JNIEXPORT JNICALL int Java_com_google_amber_Amber_androidMain( for (const std::string& arg : argv_string) argv.push_back(arg.c_str()); - return main(argv.size(), argv.data()); + return android_main(static_cast<int>(argv.size()), argv.data()); } + +#pragma clang diagnostic pop diff --git a/samples/config_helper_vulkan.cc b/samples/config_helper_vulkan.cc index 68114ab..6a82a4a 100644 --- a/samples/config_helper_vulkan.cc +++ b/samples/config_helper_vulkan.cc @@ -758,25 +758,60 @@ amber::Result ConfigHelperVulkan::CheckVulkanPhysicalDeviceRequirements( const VkPhysicalDevice physical_device, const std::vector<std::string>& required_features, const std::vector<std::string>& required_extensions) { + available_device_extensions_ = GetAvailableDeviceExtensions(physical_device); + if (!AreAllExtensionsSupported(available_device_extensions_, + required_extensions)) { + return amber::Result("Device does not support all required extensions"); + } + for (const auto& ext : available_device_extensions_) { + if (ext == "VK_KHR_shader_float16_int8") + supports_shader_float16_int8_ = true; + else if (ext == "VK_KHR_8bit_storage") + supports_shader_8bit_storage_ = true; + else if (ext == "VK_KHR_16bit_storage") + supports_shader_16bit_storage_ = true; + else if (ext == "VK_EXT_subgroup_size_control") + supports_subgroup_size_control_ = true; + } + VkPhysicalDeviceFeatures required_vulkan_features = VkPhysicalDeviceFeatures(); if (supports_get_physical_device_properties2_) { - VkPhysicalDeviceSubgroupSizeControlFeaturesEXT size_control = - VkPhysicalDeviceSubgroupSizeControlFeaturesEXT(); - size_control.sType = + VkPhysicalDeviceSubgroupSizeControlFeaturesEXT + subgroup_size_control_features = {}; + VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers_features = {}; + VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features = {}; + VkPhysicalDevice8BitStorageFeaturesKHR storage_8bit_features = {}; + VkPhysicalDevice16BitStorageFeaturesKHR storage_16bit_features = {}; + + subgroup_size_control_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT; - size_control.pNext = nullptr; + subgroup_size_control_features.pNext = nullptr; - VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs = - VkPhysicalDeviceVariablePointerFeaturesKHR(); - var_ptrs.sType = + // Add subgroup size control struct into the chain only if + // VK_EXT_subgroup_size_control is supported. + variable_pointers_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR; - var_ptrs.pNext = &size_control; + variable_pointers_features.pNext = supports_subgroup_size_control_ + ? &subgroup_size_control_features + : nullptr; + + float16_int8_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; + float16_int8_features.pNext = &variable_pointers_features; + + storage_8bit_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR; + storage_8bit_features.pNext = &float16_int8_features; + + storage_16bit_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; + storage_16bit_features.pNext = &storage_8bit_features; VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR(); features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; - features2.pNext = &var_ptrs; + features2.pNext = &storage_16bit_features; auto vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>( @@ -794,13 +829,34 @@ amber::Result ConfigHelperVulkan::CheckVulkanPhysicalDeviceRequirements( } if ((feature == kVariablePointers && - var_ptrs.variablePointers == VK_FALSE) || + variable_pointers_features.variablePointers == VK_FALSE) || (feature == kVariablePointersStorageBuffer && - var_ptrs.variablePointersStorageBuffer == VK_FALSE) || + variable_pointers_features.variablePointersStorageBuffer == + VK_FALSE) || (feature == kSubgroupSizeControl && - size_control.subgroupSizeControl == VK_FALSE) || + subgroup_size_control_features.subgroupSizeControl == VK_FALSE) || (feature == kComputeFullSubgroups && - size_control.computeFullSubgroups == VK_FALSE)) { + subgroup_size_control_features.computeFullSubgroups == VK_FALSE) || + (feature == kFloat16Int8_Float16 && + float16_int8_features.shaderFloat16 == VK_FALSE) || + (feature == kFloat16Int8_Int8 && + float16_int8_features.shaderInt8 == VK_FALSE) || + (feature == k8BitStorage_Storage && + storage_8bit_features.storageBuffer8BitAccess == VK_FALSE) || + (feature == k8BitStorage_UniformAndStorage && + storage_8bit_features.uniformAndStorageBuffer8BitAccess == + VK_FALSE) || + (feature == k8BitStorage_PushConstant && + storage_8bit_features.storagePushConstant8 == VK_FALSE) || + (feature == k16BitStorage_Storage && + storage_16bit_features.storageBuffer16BitAccess == VK_FALSE) || + (feature == k16BitStorage_InputOutput && + storage_16bit_features.storageInputOutput16 == VK_FALSE) || + (feature == k16BitStorage_PushConstant && + storage_16bit_features.storagePushConstant16 == VK_FALSE) || + (feature == k16BitStorage_UniformAndStorage && + storage_16bit_features.uniformAndStorageBuffer16BitAccess == + VK_FALSE)) { return amber::Result("Device does not support all required features"); } } @@ -823,22 +879,6 @@ amber::Result ConfigHelperVulkan::CheckVulkanPhysicalDeviceRequirements( return amber::Result("Device does not support all required features"); } - available_device_extensions_ = GetAvailableDeviceExtensions(physical_device); - if (!AreAllExtensionsSupported(available_device_extensions_, - required_extensions)) { - return amber::Result("Device does not support all required extensions"); - } - for (const auto& ext : available_device_extensions_) { - if (ext == "VK_KHR_shader_float16_int8") - supports_shader_float16_int8_ = true; - else if (ext == "VK_KHR_8bit_storage") - supports_shader_8bit_storage_ = true; - else if (ext == "VK_KHR_16bit_storage") - supports_shader_16bit_storage_ = true; - else if (ext == "VK_EXT_subgroup_size_control") - supports_subgroup_size_control_ = true; - } - vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_device); if (vulkan_queue_family_index_ == std::numeric_limits<uint32_t>::max()) { return amber::Result("Device does not support required queue flags"); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 901681f..e51d1b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,6 +124,10 @@ endif() if (${Vulkan_FOUND}) target_link_libraries(libamber libamberenginevulkan) target_include_directories(libamber PRIVATE "${VulkanHeaders_INCLUDE_DIR}") + + if (${VULKAN_CTS_HEADER} AND DEFINED AMBER_CTS_INL_DIR) + target_include_directories(libamber PRIVATE "${AMBER_CTS_INL_DIR}") + endif() endif() if (${Dawn_FOUND}) target_link_libraries(libamber libamberenginedawn) @@ -156,6 +160,7 @@ if (${AMBER_ENABLE_TESTS}) amberscript/parser_shader_opt_test.cc amberscript/parser_shader_test.cc amberscript/parser_stencil_test.cc + amberscript/parser_blend_test.cc amberscript/parser_struct_test.cc amberscript/parser_subgroup_size_control_test.cc amberscript/parser_test.cc diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 809baa1..d3e0eb6 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -622,6 +622,10 @@ Result Parser::ParsePipelineBody(const std::string& cmd_name, r = ParsePipelineStencil(pipeline.get()); } else if (tok == "SUBGROUP") { r = ParsePipelineSubgroup(pipeline.get()); + } else if (tok == "PATCH_CONTROL_POINTS") { + r = ParsePipelinePatchControlPoints(pipeline.get()); + } else if (tok == "BLEND") { + r = ParsePipelineBlend(pipeline.get()); } else { r = Result("unknown token in pipeline block: " + tok); } @@ -931,6 +935,20 @@ Result Parser::ParsePipelineSubgroup(Pipeline* pipeline) { return ValidateEndOfStatement("SUBGROUP command"); } +Result Parser::ParsePipelinePatchControlPoints(Pipeline* pipeline) { + auto token = tokenizer_->NextToken(); + if (token->IsEOL() || token->IsEOS()) + return Result( + "missing number of control points in PATCH_CONTROL_POINTS command"); + + if (!token->IsInteger()) + return Result("expecting integer for the number of control points"); + + pipeline->GetPipelineData()->SetPatchControlPoints(token->AsUint32()); + + return ValidateEndOfStatement("PATCH_CONTROL_POINTS command"); +} + Result Parser::ParsePipelineFramebufferSize(Pipeline* pipeline) { auto token = tokenizer_->NextToken(); if (token->IsEOL() || token->IsEOS()) @@ -1046,6 +1064,8 @@ Result Parser::ToBufferType(const std::string& name, BufferType* type) { *type = BufferType::kUniformTexelBuffer; else if (name == "storage_texel_buffer") *type = BufferType::kStorageTexelBuffer; + else if (name == "resolve") + *type = BufferType::kResolve; else return Result("unknown buffer_type: " + name); @@ -1160,6 +1180,8 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) { for (auto& buf : buffers) buf->SetSampler(sampler); + } else if (buffer_type == BufferType::kResolve) { + r = pipeline->AddResolveTarget(buffer); } } @@ -1843,6 +1865,98 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { return ValidateEndOfStatement("STENCIL command"); } +Result Parser::ParsePipelineBlend(Pipeline* pipeline) { + pipeline->GetPipelineData()->SetEnableBlend(true); + + while (true) { + auto token = tokenizer_->NextToken(); + if (token->IsEOL()) + continue; + if (token->IsEOS()) + return Result("BLEND missing END command"); + if (!token->IsIdentifier()) + return Result("BLEND options must be identifiers"); + if (token->AsString() == "END") + break; + + if (token->AsString() == "SRC_COLOR_FACTOR") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for SRC_COLOR_FACTOR"); + + const auto factor = NameToBlendFactor(token->AsString()); + if (factor == BlendFactor::kUnknown) + return Result("BLEND invalid value for SRC_COLOR_FACTOR: " + + token->AsString()); + pipeline->GetPipelineData()->SetSrcColorBlendFactor( + NameToBlendFactor(token->AsString())); + } else if (token->AsString() == "DST_COLOR_FACTOR") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for DST_COLOR_FACTOR"); + + const auto factor = NameToBlendFactor(token->AsString()); + if (factor == BlendFactor::kUnknown) + return Result("BLEND invalid value for DST_COLOR_FACTOR: " + + token->AsString()); + pipeline->GetPipelineData()->SetDstColorBlendFactor( + NameToBlendFactor(token->AsString())); + } else if (token->AsString() == "SRC_ALPHA_FACTOR") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for SRC_ALPHA_FACTOR"); + + const auto factor = NameToBlendFactor(token->AsString()); + if (factor == BlendFactor::kUnknown) + return Result("BLEND invalid value for SRC_ALPHA_FACTOR: " + + token->AsString()); + pipeline->GetPipelineData()->SetSrcAlphaBlendFactor( + NameToBlendFactor(token->AsString())); + } else if (token->AsString() == "DST_ALPHA_FACTOR") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for DST_ALPHA_FACTOR"); + + const auto factor = NameToBlendFactor(token->AsString()); + if (factor == BlendFactor::kUnknown) + return Result("BLEND invalid value for DST_ALPHA_FACTOR: " + + token->AsString()); + pipeline->GetPipelineData()->SetDstAlphaBlendFactor( + NameToBlendFactor(token->AsString())); + } else if (token->AsString() == "COLOR_OP") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for COLOR_OP"); + + const auto op = NameToBlendOp(token->AsString()); + if (op == BlendOp::kUnknown) + return Result("BLEND invalid value for COLOR_OP: " + token->AsString()); + pipeline->GetPipelineData()->SetColorBlendOp( + NameToBlendOp(token->AsString())); + } else if (token->AsString() == "ALPHA_OP") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("BLEND invalid value for ALPHA_OP"); + + const auto op = NameToBlendOp(token->AsString()); + if (op == BlendOp::kUnknown) + return Result("BLEND invalid value for ALPHA_OP: " + token->AsString()); + pipeline->GetPipelineData()->SetAlphaBlendOp( + NameToBlendOp(token->AsString())); + } else { + return Result("BLEND invalid value for BLEND: " + token->AsString()); + } + } + + return ValidateEndOfStatement("BLEND command"); +} + Result Parser::ParseStruct() { auto token = tokenizer_->NextToken(); if (!token->IsIdentifier()) diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h index 6fb25ce..25d3493 100644 --- a/src/amberscript/parser.h +++ b/src/amberscript/parser.h @@ -64,6 +64,7 @@ class Parser : public amber::Parser { Result ParsePipelineShaderOptimizations(Pipeline*); Result ParsePipelineShaderCompileOptions(Pipeline*); Result ParsePipelineSubgroup(Pipeline* pipeline); + Result ParsePipelinePatchControlPoints(Pipeline* pipeline); Result ParsePipelineFramebufferSize(Pipeline*); Result ParsePipelineViewport(Pipeline*); Result ParsePipelineBind(Pipeline*); @@ -73,6 +74,7 @@ class Parser : public amber::Parser { Result ParsePipelinePolygonMode(Pipeline*); Result ParsePipelineDepth(Pipeline* pipeline); Result ParsePipelineStencil(Pipeline* pipeline); + Result ParsePipelineBlend(Pipeline* pipeline); Result ParseRun(); Result ParseDebug(); Result ParseDebugThread(debug::Events*, Pipeline* pipeline); diff --git a/src/amberscript/parser_bind_test.cc b/src/amberscript/parser_bind_test.cc index a39b69e..8aac5e5 100644 --- a/src/amberscript/parser_bind_test.cc +++ b/src/amberscript/parser_bind_test.cc @@ -3508,5 +3508,132 @@ END r.Error()); } +TEST_F(AmberScriptParserTest, BindResolveTarget) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER my_fb_ms AS color LOCATION 0 + BIND BUFFER my_fb AS resolve +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& resolve_targets = pipeline->GetResolveTargets(); + ASSERT_EQ(1U, resolve_targets.size()); + + const auto& buf_info = resolve_targets[0]; + ASSERT_TRUE(buf_info.buffer != nullptr); + EXPECT_EQ(64u * 64u, buf_info.buffer->ElementCount()); + EXPECT_EQ(64u * 64u * 4u, buf_info.buffer->ValueCount()); + EXPECT_EQ(64u * 64u * 4u * sizeof(float), buf_info.buffer->GetSizeInBytes()); +} + +TEST_F(AmberScriptParserTest, BindResolveTargetMissingBuffer) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + BIND BUFFER AS resolve +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("12: unknown buffer: AS", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindResolveTargetNonDeclaredBuffer) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 + +PIPELINE graphics my_pipeline +ATTACH my_shader +ATTACH my_fragment + +FRAMEBUFFER_SIZE 64 64 +BIND BUFFER my_fb_ms AS color LOCATION 0 +BIND BUFFER my_fb AS resolve +END)"; + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("14: unknown buffer: my_fb", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindMultipleResolveTargets) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms0 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb_ms1 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb_ms2 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb0 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT +IMAGE my_fb1 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT +IMAGE my_fb2 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER my_fb_ms0 AS color LOCATION 0 + BIND BUFFER my_fb_ms1 AS color LOCATION 1 + BIND BUFFER my_fb_ms2 AS color LOCATION 2 + BIND BUFFER my_fb0 AS resolve + BIND BUFFER my_fb1 AS resolve + BIND BUFFER my_fb2 AS resolve +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + const auto* pipeline = pipelines[0].get(); + const auto& resolve_targets = pipeline->GetResolveTargets(); + ASSERT_EQ(3U, resolve_targets.size()); + + for (const auto& buf_info : resolve_targets) { + ASSERT_TRUE(buf_info.buffer != nullptr); + EXPECT_EQ(64u * 64u, buf_info.buffer->ElementCount()); + EXPECT_EQ(64u * 64u * 4u, buf_info.buffer->ValueCount()); + EXPECT_EQ(64u * 64u * 4u * sizeof(float), + buf_info.buffer->GetSizeInBytes()); + } +} + } // namespace amberscript } // namespace amber diff --git a/src/amberscript/parser_blend_test.cc b/src/amberscript/parser_blend_test.cc new file mode 100644 index 0000000..013ccbd --- /dev/null +++ b/src/amberscript/parser_blend_test.cc @@ -0,0 +1,140 @@ +// Copyright 2021 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or parseried. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "src/amberscript/parser.h" + +namespace amber { +namespace amberscript { + +using AmberScriptParserTest = testing::Test; + +TEST_F(AmberScriptParserTest, BlendAllValues) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + + BLEND + SRC_COLOR_FACTOR src_alpha + DST_COLOR_FACTOR one_minus_src_alpha + COLOR_OP add + SRC_ALPHA_FACTOR one + DST_ALPHA_FACTOR zero + ALPHA_OP max + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + auto* pipeline = pipelines[0].get(); + + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableBlend()); + ASSERT_EQ(BlendFactor::kSrcAlpha, + pipeline->GetPipelineData()->GetSrcColorBlendFactor()); + ASSERT_EQ(BlendFactor::kOneMinusSrcAlpha, + pipeline->GetPipelineData()->GetDstColorBlendFactor()); + ASSERT_EQ(BlendOp::kAdd, + pipeline->GetPipelineData()->GetColorBlendOp()); + + ASSERT_EQ(BlendFactor::kOne, + pipeline->GetPipelineData()->GetSrcAlphaBlendFactor()); + ASSERT_EQ(BlendFactor::kZero, + pipeline->GetPipelineData()->GetDstAlphaBlendFactor()); + ASSERT_EQ(BlendOp::kMax, + pipeline->GetPipelineData()->GetAlphaBlendOp()); +} + +TEST_F(AmberScriptParserTest, BlendDefaultValues) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + + BLEND + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + auto* pipeline = pipelines[0].get(); + + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableBlend()); + ASSERT_EQ(BlendFactor::kOne, + pipeline->GetPipelineData()->GetSrcColorBlendFactor()); + ASSERT_EQ(BlendFactor::kZero, + pipeline->GetPipelineData()->GetDstColorBlendFactor()); + ASSERT_EQ(BlendOp::kAdd, + pipeline->GetPipelineData()->GetColorBlendOp()); + + ASSERT_EQ(BlendFactor::kOne, + pipeline->GetPipelineData()->GetSrcAlphaBlendFactor()); + ASSERT_EQ(BlendFactor::kZero, + pipeline->GetPipelineData()->GetDstAlphaBlendFactor()); + ASSERT_EQ(BlendOp::kAdd, + pipeline->GetPipelineData()->GetAlphaBlendOp()); +} + +TEST_F(AmberScriptParserTest, BlendInvalidColorFactor) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + + BLEND + SRC_COLOR_FACTOR foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("14: BLEND invalid value for SRC_COLOR_FACTOR: foo", r.Error()); +} + +} // namespace amberscript +} // namespace amber diff --git a/src/amberscript/parser_pipeline_test.cc b/src/amberscript/parser_pipeline_test.cc index 2b56e2e..4707dd9 100644 --- a/src/amberscript/parser_pipeline_test.cc +++ b/src/amberscript/parser_pipeline_test.cc @@ -61,6 +61,8 @@ END EXPECT_EQ(kShaderTypeFragment, shaders[1].GetShader()->GetType()); EXPECT_EQ(static_cast<uint32_t>(0), shaders[1].GetShaderOptimizations().size()); + + EXPECT_EQ(pipelines[0]->GetPipelineData()->GetPatchControlPoints(), 3u); } TEST_F(AmberScriptParserTest, PipelineMissingEnd) { @@ -541,5 +543,85 @@ END EXPECT_EQ(4u, s2[0].GetSpecialization().at(3)); } +TEST_F(AmberScriptParserTest, PipelinePatchControlPoints) { + std::string in = R"( +DEVICE_FEATURE tessellationShader + +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END + +SHADER tessellation_control my_tesc GLSL +# GLSL Shader +END + +SHADER tessellation_evaluation my_tese GLSL +# GLSL Shader +END + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_tesc + ATTACH my_tese + ATTACH my_fragment + + PATCH_CONTROL_POINTS 4 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + EXPECT_EQ(pipelines[0]->GetPipelineData()->GetPatchControlPoints(), 4u); +} + +TEST_F(AmberScriptParserTest, PipelineDerivePatchControlPoints) { + std::string in = R"( +DEVICE_FEATURE tessellationShader + +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END + +SHADER tessellation_control my_tesc GLSL +# GLSL Shader +END + +SHADER tessellation_evaluation my_tese GLSL +# GLSL Shader +END + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_tesc + ATTACH my_tese + ATTACH my_fragment + + PATCH_CONTROL_POINTS 4 +END + +DERIVE_PIPELINE child_pipeline FROM my_pipeline +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(2U, pipelines.size()); + + EXPECT_EQ(pipelines[0]->GetPipelineData()->GetPatchControlPoints(), 4u); + EXPECT_EQ(pipelines[1]->GetPipelineData()->GetPatchControlPoints(), 4u); +} + } // namespace amberscript } // namespace amber diff --git a/src/buffer.h b/src/buffer.h index 18f7fed..90f3b01 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -62,7 +62,9 @@ enum class BufferType : int8_t { /// A uniform texel buffer. kUniformTexelBuffer, /// A storage texel buffer. - kStorageTexelBuffer + kStorageTexelBuffer, + /// A resolve target. + kResolve }; enum class InputRate : int8_t { diff --git a/src/command_data.cc b/src/command_data.cc index 80083e1..c0b7612 100644 --- a/src/command_data.cc +++ b/src/command_data.cc @@ -54,4 +54,154 @@ Topology NameToTopology(const std::string& name) { return Topology::kUnknown; } +BlendFactor NameToBlendFactor(const std::string& name) { + if (name == "zero") + return BlendFactor::kZero; + else if (name == "one") + return BlendFactor::kOne; + else if (name == "src_color") + return BlendFactor::kSrcColor; + else if (name == "one_minus_src_color") + return BlendFactor::kOneMinusSrcColor; + else if (name == "dst_color") + return BlendFactor::kDstColor; + else if (name == "one_minus_dst_color") + return BlendFactor::kOneMinusDstColor; + else if (name == "src_alpha") + return BlendFactor::kSrcAlpha; + else if (name == "one_minus_src_alpha") + return BlendFactor::kOneMinusSrcAlpha; + else if (name == "dst_alpha") + return BlendFactor::kDstAlpha; + else if (name == "one_minus_dst_alpha") + return BlendFactor::kOneMinusDstAlpha; + else if (name == "constant_color") + return BlendFactor::kConstantColor; + else if (name == "one_minus_constant_color") + return BlendFactor::kOneMinusConstantColor; + else if (name == "costant_alpha") + return BlendFactor::kConstantAlpha; + else if (name == "one_minus_constant_alpha") + return BlendFactor::kOneMinusConstantAlpha; + else if (name == "src_alpha_saturate") + return BlendFactor::kSrcAlphaSaturate; + else if (name == "src1_color") + return BlendFactor::kSrc1Color; + else if (name == "one_minus_src1_color") + return BlendFactor::kOneMinusSrc1Color; + else if (name == "src1_alpha") + return BlendFactor::kSrc1Alpha; + else if (name == "one_minus_src1_alpha") + return BlendFactor::kOneMinusSrc1Alpha; + else + return BlendFactor::kUnknown; +} + +BlendOp NameToBlendOp(const std::string& name) { + if (name == "add") + return BlendOp::kAdd; + else if (name == "substract") + return BlendOp::kSubtract; + else if (name == "reverse_substract") + return BlendOp::kReverseSubtract; + else if (name == "min") + return BlendOp::kMin; + else if (name == "max") + return BlendOp::kMax; + else if (name == "zero") + return BlendOp::kZero; + else if (name == "src") + return BlendOp::kSrc; + else if (name == "dst") + return BlendOp::kDst; + else if (name == "src_over") + return BlendOp::kSrcOver; + else if (name == "dst_over") + return BlendOp::kDstOver; + else if (name == "src_in") + return BlendOp::kSrcIn; + else if (name == "dst_in") + return BlendOp::kDstIn; + else if (name == "src_out") + return BlendOp::kSrcOut; + else if (name == "dst_out") + return BlendOp::kDstOut; + else if (name == "src_atop") + return BlendOp::kSrcAtop; + else if (name == "dst_atop") + return BlendOp::kDstAtop; + else if (name == "xor") + return BlendOp::kXor; + else if (name == "multiply") + return BlendOp::kMultiply; + else if (name == "screen") + return BlendOp::kScreen; + else if (name == "overlay") + return BlendOp::kOverlay; + else if (name == "darken") + return BlendOp::kDarken; + else if (name == "lighten") + return BlendOp::kLighten; + else if (name == "color_dodge") + return BlendOp::kColorDodge; + else if (name == "color_burn") + return BlendOp::kColorBurn; + else if (name == "hard_light") + return BlendOp::kHardLight; + else if (name == "soft_light") + return BlendOp::kSoftLight; + else if (name == "difference") + return BlendOp::kDifference; + else if (name == "exclusion") + return BlendOp::kExclusion; + else if (name == "invert") + return BlendOp::kInvert; + else if (name == "invert_rgb") + return BlendOp::kInvertRGB; + else if (name == "linear_dodge") + return BlendOp::kLinearDodge; + else if (name == "linear_burn") + return BlendOp::kLinearBurn; + else if (name == "vivid_light") + return BlendOp::kVividLight; + else if (name == "linear_light") + return BlendOp::kLinearLight; + else if (name == "pin_light") + return BlendOp::kPinLight; + else if (name == "hard_mix") + return BlendOp::kHardMix; + else if (name == "hsl_hue") + return BlendOp::kHslHue; + else if (name == "hsl_saturation") + return BlendOp::kHslSaturation; + else if (name == "hsl_color") + return BlendOp::kHslColor; + else if (name == "hsl_luminosity") + return BlendOp::kHslLuminosity; + else if (name == "plus") + return BlendOp::kPlus; + else if (name == "plus_clamped") + return BlendOp::kPlusClamped; + else if (name == "plus_clamped_alpha") + return BlendOp::kPlusClampedAlpha; + else if (name == "plus_darker") + return BlendOp::kPlusDarker; + else if (name == "minus") + return BlendOp::kMinus; + else if (name == "minus_clamped") + return BlendOp::kMinusClamped; + else if (name == "contrast") + return BlendOp::kContrast; + else if (name == "invert_ovg") + return BlendOp::kInvertOvg; + else if (name == "red") + return BlendOp::kRed; + else if (name == "green") + return BlendOp::kGreen; + else if (name == "blue") + return BlendOp::kBlue; + else + return BlendOp::kUnknown; +} + } // namespace amber diff --git a/src/command_data.h b/src/command_data.h index 98ec405..f7e82a2 100644 --- a/src/command_data.h +++ b/src/command_data.h @@ -104,7 +104,8 @@ enum class LogicOp : uint8_t { }; enum class BlendOp : uint8_t { - kAdd = 0, + kUnknown = 0, + kAdd, kSubtract, kReverseSubtract, kMin, @@ -158,7 +159,8 @@ enum class BlendOp : uint8_t { }; enum class BlendFactor : uint8_t { - kZero = 0, + kUnknown = 0, + kZero, kOne, kSrcColor, kOneMinusSrcColor, @@ -180,6 +182,8 @@ enum class BlendFactor : uint8_t { }; Topology NameToTopology(const std::string& name); +BlendFactor NameToBlendFactor(const std::string& name); +BlendOp NameToBlendOp(const std::string& name); } // namespace amber diff --git a/src/pipeline.cc b/src/pipeline.cc index 9b73041..ae3bf0a 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -389,6 +389,18 @@ Result Pipeline::AddColorAttachment(Buffer* buf, return {}; } +Result Pipeline::AddResolveTarget(Buffer* buf) { + resolve_targets_.push_back(BufferInfo{buf}); + + auto& info = resolve_targets_.back(); + info.type = BufferType::kResolve; + buf->SetWidth(fb_width_); + buf->SetHeight(fb_height_); + buf->SetElementCount(fb_width_ * fb_height_); + + return {}; +} + Result Pipeline::GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const { for (const auto& info : color_attachments_) { diff --git a/src/pipeline.h b/src/pipeline.h index 7a80ad4..9010c59 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -303,6 +303,14 @@ class Pipeline { /// something goes wrong. Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; + /// Returns a list of all resolve targets in this pipeline. + const std::vector<BufferInfo>& GetResolveTargets() const { + return resolve_targets_; + } + + /// Adds |buf| as a multisample resolve target in the pipeline. + Result AddResolveTarget(Buffer* buf); + /// Sets |buf| as the depth/stencil buffer for this pipeline. Result SetDepthStencilBuffer(Buffer* buf); /// Returns information on the depth/stencil buffer bound to the pipeline. If @@ -436,6 +444,7 @@ class Pipeline { std::string name_; std::vector<ShaderInfo> shaders_; std::vector<BufferInfo> color_attachments_; + std::vector<BufferInfo> resolve_targets_; std::vector<BufferInfo> vertex_buffers_; std::vector<BufferInfo> buffers_; std::vector<std::unique_ptr<type::Type>> types_; diff --git a/src/pipeline_data.h b/src/pipeline_data.h index 9a3b4d1..c763f37 100644 --- a/src/pipeline_data.h +++ b/src/pipeline_data.h @@ -178,6 +178,11 @@ class PipelineData { bool HasViewportData() const { return has_viewport_data; } const Viewport& GetViewport() const { return vp; } + void SetPatchControlPoints(uint32_t control_points) { + patch_control_points_ = control_points; + } + uint32_t GetPatchControlPoints() const { return patch_control_points_; } + private: StencilOp front_fail_op_ = StencilOp::kKeep; StencilOp front_pass_op_ = StencilOp::kKeep; @@ -233,6 +238,8 @@ class PipelineData { bool has_viewport_data = false; Viewport vp; + + uint32_t patch_control_points_ = 3u; }; } // namespace amber diff --git a/src/script.cc b/src/script.cc index 7d7483f..8da8f11 100644 --- a/src/script.cc +++ b/src/script.cc @@ -114,7 +114,21 @@ bool Script::IsKnownFeature(const std::string& name) const { name == "Storage16BitFeatures.storagePushConstant16" || name == "Storage16BitFeatures.storageInputOutput16" || name == "SubgroupSizeControl.subgroupSizeControl" || - name == "SubgroupSizeControl.computeFullSubgroups"; + name == "SubgroupSizeControl.computeFullSubgroups" || + name == "SubgroupSupportedOperations.basic" || + name == "SubgroupSupportedOperations.vote" || + name == "SubgroupSupportedOperations.arithmetic" || + name == "SubgroupSupportedOperations.ballot" || + name == "SubgroupSupportedOperations.shuffle" || + name == "SubgroupSupportedOperations.shuffleRelative" || + name == "SubgroupSupportedOperations.clustered" || + name == "SubgroupSupportedOperations.quad" || + name == "SubgroupSupportedStages.vertex" || + name == "SubgroupSupportedStages.tessellationControl" || + name == "SubgroupSupportedStages.tessellationEvaluation" || + name == "SubgroupSupportedStages.geometry" || + name == "SubgroupSupportedStages.fragment" || + name == "SubgroupSupportedStages.compute"; } type::Type* Script::ParseType(const std::string& str) { diff --git a/src/vulkan/CMakeLists.txt b/src/vulkan/CMakeLists.txt index b633c71..37bdd1f 100644 --- a/src/vulkan/CMakeLists.txt +++ b/src/vulkan/CMakeLists.txt @@ -43,6 +43,13 @@ target_include_directories(libamberenginevulkan PRIVATE "${CMAKE_BINARY_DIR}") # Add the Vulkan include directory to the list of include paths. target_include_directories(libamberenginevulkan PRIVATE "${VulkanHeaders_INCLUDE_DIR}") +# When building with dEQP Vulkan CTS the inl files needs to be included and a dependency +# must be added to the target `deqp-vk-inl` that generates the inl files. +if (${VULKAN_CTS_HEADER} AND DEFINED AMBER_CTS_INL_DIR) + target_include_directories(libamberenginevulkan PRIVATE "${AMBER_CTS_INL_DIR}") + add_dependencies(libamberenginevulkan deqp-vk-inl) +endif() + set_target_properties(libamberenginevulkan PROPERTIES OUTPUT_NAME "amberenginevulkan" ) @@ -52,7 +59,7 @@ endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") # vulkan/vulkan.h defines VK_NULL_HANDLE as 0u and that also serves as a null pointer. - # Disable Clang's warning that will alwaays fire on that. This is required to build + # Disable Clang's warning that will always fire on that. This is required to build # with XCode 10. target_compile_options(libamberenginevulkan PRIVATE -Wno-zero-as-null-pointer-constant) endif() diff --git a/src/vulkan/buffer_backed_descriptor.cc b/src/vulkan/buffer_backed_descriptor.cc index d1b1aed..a2e874d 100644 --- a/src/vulkan/buffer_backed_descriptor.cc +++ b/src/vulkan/buffer_backed_descriptor.cc @@ -26,79 +26,65 @@ BufferBackedDescriptor::BufferBackedDescriptor(Buffer* buffer, DescriptorType type, Device* device, uint32_t desc_set, - uint32_t binding) - : Descriptor(type, device, desc_set, binding) { + uint32_t binding, + Pipeline* pipeline) + : Descriptor(type, device, desc_set, binding), pipeline_(pipeline) { AddAmberBuffer(buffer); } BufferBackedDescriptor::~BufferBackedDescriptor() = default; -Result BufferBackedDescriptor::RecordCopyDataToResourceIfNeeded( - CommandBuffer* command) { - for (const auto& resource : GetResources()) { - if (!resource.first->ValuePtr()->empty()) { - resource.second->UpdateMemoryWithRawData(*resource.first->ValuePtr()); - // If the resource is read-only, keep the buffer data; Amber won't copy - // read-only resources back into the host buffers, so it makes sense to - // leave the buffer intact. - if (!IsReadOnly()) - resource.first->ValuePtr()->clear(); - } - - resource.second->CopyToDevice(command); - } +Result BufferBackedDescriptor::RecordCopyBufferDataToTransferResourceIfNeeded( + CommandBuffer* command_buffer, + Buffer* buffer, + Resource* transfer_resource) { + transfer_resource->UpdateMemoryWithRawData(*buffer->ValuePtr()); + // If the resource is read-only, keep the buffer data; Amber won't copy + // read-only resources back into the host buffers, so it makes sense to + // leave the buffer intact. + if (!transfer_resource->IsReadOnly()) + buffer->ValuePtr()->clear(); + + transfer_resource->CopyToDevice(command_buffer); return {}; } -Result BufferBackedDescriptor::RecordCopyDataToHost(CommandBuffer* command) { - if (!IsReadOnly()) { - if (GetResources().empty()) { - return Result( - "Vulkan: BufferBackedDescriptor::RecordCopyDataToHost() no transfer " - "resources"); - } - - for (const auto& r : GetResources()) - r.second->CopyToHost(command); +Result BufferBackedDescriptor::RecordCopyTransferResourceToHost( + CommandBuffer* command_buffer, + Resource* transfer_resource) { + if (!transfer_resource->IsReadOnly()) { + transfer_resource->CopyToHost(command_buffer); } return {}; } -Result BufferBackedDescriptor::MoveResourceToBufferOutput() { - // No need to copy results of read only resources. - if (IsReadOnly()) +Result BufferBackedDescriptor::MoveTransferResourceToBufferOutput( + Resource* transfer_resource, + Buffer* buffer) { + // No need to move read only resources to an output buffer. + if (transfer_resource->IsReadOnly()) { return {}; + } - auto resources = GetResources(); - - if (resources.empty()) { + void* resource_memory_ptr = transfer_resource->HostAccessibleMemoryPtr(); + if (!resource_memory_ptr) { return Result( - "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() no " - "transfer resource"); + "Vulkan: BufferBackedDescriptor::MoveTransferResourceToBufferOutput() " + "no host accessible memory pointer"); } - for (const auto& resource : resources) { - void* resource_memory_ptr = resource.second->HostAccessibleMemoryPtr(); - auto* buffer = resource.first; - if (!resource_memory_ptr) { - return Result( - "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() " - "no host accessible memory pointer"); - } - - if (!buffer->ValuePtr()->empty()) { - return Result( - "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() " - "output buffer is not empty"); - } - - auto size_in_bytes = resource.second->GetSizeInBytes(); - buffer->SetElementCount(size_in_bytes / buffer->GetFormat()->SizeInBytes()); - buffer->ValuePtr()->resize(size_in_bytes); - std::memcpy(buffer->ValuePtr()->data(), resource_memory_ptr, size_in_bytes); + if (!buffer->ValuePtr()->empty()) { + return Result( + "Vulkan: BufferBackedDescriptor::MoveTransferResourceToBufferOutput() " + "output buffer is not empty"); } + auto size_in_bytes = transfer_resource->GetSizeInBytes(); + buffer->SetElementCount(size_in_bytes / buffer->GetFormat()->SizeInBytes()); + buffer->ValuePtr()->resize(size_in_bytes); + std::memcpy(buffer->ValuePtr()->data(), resource_memory_ptr, size_in_bytes); + return {}; } diff --git a/src/vulkan/buffer_backed_descriptor.h b/src/vulkan/buffer_backed_descriptor.h index 8f9df41..8a2d0a5 100644 --- a/src/vulkan/buffer_backed_descriptor.h +++ b/src/vulkan/buffer_backed_descriptor.h @@ -25,6 +25,7 @@ #include "src/buffer.h" #include "src/engine.h" #include "src/vulkan/descriptor.h" +#include "src/vulkan/pipeline.h" #include "src/vulkan/resource.h" namespace amber { @@ -36,13 +37,19 @@ class BufferBackedDescriptor : public Descriptor { DescriptorType type, Device* device, uint32_t desc_set, - uint32_t binding); + uint32_t binding, + Pipeline* pipeline); ~BufferBackedDescriptor() override; Result CreateResourceIfNeeded() override { return {}; } - Result RecordCopyDataToResourceIfNeeded(CommandBuffer* command) override; - Result RecordCopyDataToHost(CommandBuffer* command) override; - Result MoveResourceToBufferOutput() override; + static Result RecordCopyBufferDataToTransferResourceIfNeeded( + CommandBuffer* command_buffer, + Buffer* buffer, + Resource* transfer_resource); + static Result RecordCopyTransferResourceToHost(CommandBuffer* command_buffer, + Resource* transfer_resource); + static Result MoveTransferResourceToBufferOutput(Resource* transfer_resource, + Buffer* buffer); uint32_t GetDescriptorCount() override { return static_cast<uint32_t>(amber_buffers_.size()); } @@ -52,10 +59,8 @@ class BufferBackedDescriptor : public Descriptor { bool IsReadOnly() const; protected: - /// Returns a list of unique transfer buffer resources. Note that this list - /// may contain less items than the |amber_buffers| vector contains if two or - /// more amber buffers use same Vulkan buffer. - virtual std::vector<std::pair<Buffer*, Resource*>> GetResources() = 0; + // Pipeline where this descriptor is attached to. + Pipeline* pipeline_; private: std::vector<Buffer*> amber_buffers_; diff --git a/src/vulkan/buffer_descriptor.cc b/src/vulkan/buffer_descriptor.cc index aa8b2dd..d60ce08 100644 --- a/src/vulkan/buffer_descriptor.cc +++ b/src/vulkan/buffer_descriptor.cc @@ -29,65 +29,63 @@ BufferDescriptor::BufferDescriptor(Buffer* buffer, DescriptorType type, Device* device, uint32_t desc_set, - uint32_t binding) - : BufferBackedDescriptor(buffer, type, device, desc_set, binding) {} + uint32_t binding, + Pipeline* pipeline) + : BufferBackedDescriptor(buffer, + type, + device, + desc_set, + binding, + pipeline) {} BufferDescriptor::~BufferDescriptor() = default; Result BufferDescriptor::CreateResourceIfNeeded() { - if (!transfer_buffers_.empty()) { - return Result( - "Vulkan: BufferDescriptor::CreateResourceIfNeeded() must be called " - "only when |transfer_buffers| is empty"); + auto& transfer_resources = pipeline_->GetDescriptorTransferResources(); + + VkBufferUsageFlags flags = + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (IsUniformBuffer() || IsUniformBufferDynamic()) { + flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + } else if (IsStorageBuffer() || IsStorageBufferDynamic()) { + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } else if (IsUniformTexelBuffer()) { + flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + } else if (IsStorageTexelBuffer()) { + flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + } else { + return Result("Unexpected buffer type when deciding usage flags"); } - descriptor_offsets_.reserve(GetAmberBuffers().size()); - descriptor_ranges_.reserve(GetAmberBuffers().size()); - for (const auto& amber_buffer : GetAmberBuffers()) { - if (amber_buffer->ValuePtr()->empty()) - continue; - - // Check if the transfer buffer is already created. - if (transfer_buffers_.count(amber_buffer) > 0) - continue; - - auto size_in_bytes = - static_cast<uint32_t>(amber_buffer->ValuePtr()->size()); - - auto transfer_buffer = MakeUnique<TransferBuffer>( - device_, size_in_bytes, amber_buffer->GetFormat()); - - VkBufferUsageFlags flags = - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - if (IsUniformBuffer() || IsUniformBufferDynamic()) { - flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - } else if (IsStorageBuffer() || IsStorageBufferDynamic()) { - flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - } else if (IsUniformTexelBuffer()) { - flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; - } else if (IsStorageTexelBuffer()) { - flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + // Create (but don't initialize) the transfer buffer if not already created. + if (transfer_resources.count(amber_buffer) == 0) { + auto size_in_bytes = + static_cast<uint32_t>(amber_buffer->ValuePtr()->size()); + auto transfer_buffer = MakeUnique<TransferBuffer>( + device_, size_in_bytes, amber_buffer->GetFormat()); + transfer_buffer->SetReadOnly(IsReadOnly()); + transfer_resources[amber_buffer] = std::move(transfer_buffer); } else { - return Result("Unexpected buffer type when deciding usage flags"); + // Unset transfer buffer's read only property if needed. + if (!IsReadOnly()) { + transfer_resources[amber_buffer]->SetReadOnly(false); + } } - Result r = transfer_buffer->Initialize(flags); + // Update the buffer create flags. + Result r = + transfer_resources[amber_buffer]->AsTransferBuffer()->AddUsageFlags( + flags); if (!r.IsSuccess()) return r; - transfer_buffers_[amber_buffer] = std::move(transfer_buffer); } - is_descriptor_set_update_needed_ = true; - return {}; -} - -Result BufferDescriptor::MoveResourceToBufferOutput() { - Result r = BufferBackedDescriptor::MoveResourceToBufferOutput(); - transfer_buffers_.clear(); + descriptor_offsets_.reserve(GetAmberBuffers().size()); + descriptor_ranges_.reserve(GetAmberBuffers().size()); - return r; + return {}; } void BufferDescriptor::UpdateDescriptorSetIfNeeded( @@ -100,7 +98,9 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded( // Create VkDescriptorBufferInfo for every descriptor buffer. for (uint32_t i = 0; i < GetAmberBuffers().size(); i++) { - const auto& buffer = transfer_buffers_[GetAmberBuffers()[i]]; + const auto& buffer = + pipeline_->GetDescriptorTransferResources()[GetAmberBuffers()[i]] + ->AsTransferBuffer(); assert(buffer->GetVkBuffer() && "Unexpected descriptor type"); // Add buffer infos for uniform and storage buffers. if (IsUniformBuffer() || IsUniformBufferDynamic() || IsStorageBuffer() || @@ -146,23 +146,5 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded( is_descriptor_set_update_needed_ = false; } -std::vector<std::pair<Buffer*, Resource*>> BufferDescriptor::GetResources() { - std::vector<std::pair<Buffer*, Resource*>> ret; - // Add unique amber buffers and related transfer buffers to the vector. - for (const auto& amber_buffer : GetAmberBuffers()) { - // Skip duplicate values. - const auto& image = - std::find_if(ret.begin(), ret.end(), - [&](const std::pair<Buffer*, Resource*>& buffer) { - return buffer.first == amber_buffer; - }); - if (image != ret.end()) - continue; - - ret.emplace_back(amber_buffer, transfer_buffers_[amber_buffer].get()); - } - return ret; -} - } // namespace vulkan } // namespace amber diff --git a/src/vulkan/buffer_descriptor.h b/src/vulkan/buffer_descriptor.h index 2c3f390..439afa5 100644 --- a/src/vulkan/buffer_descriptor.h +++ b/src/vulkan/buffer_descriptor.h @@ -26,6 +26,7 @@ #include "src/buffer.h" #include "src/engine.h" #include "src/vulkan/buffer_backed_descriptor.h" +#include "src/vulkan/pipeline.h" #include "src/vulkan/transfer_buffer.h" namespace amber { @@ -42,12 +43,12 @@ class BufferDescriptor : public BufferBackedDescriptor { DescriptorType type, Device* device, uint32_t desc_set, - uint32_t binding); + uint32_t binding, + vulkan::Pipeline* pipeline); ~BufferDescriptor() override; void UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set) override; Result CreateResourceIfNeeded() override; - Result MoveResourceToBufferOutput() override; std::vector<uint32_t> GetDynamicOffsets() override { return dynamic_offsets_; } @@ -67,12 +68,7 @@ class BufferDescriptor : public BufferBackedDescriptor { BufferDescriptor* AsBufferDescriptor() override { return this; } - protected: - std::vector<std::pair<Buffer*, Resource*>> GetResources() override; - private: - std::unordered_map<Buffer*, std::unique_ptr<TransferBuffer>> - transfer_buffers_; std::vector<uint32_t> dynamic_offsets_; std::vector<VkDeviceSize> descriptor_offsets_; std::vector<VkDeviceSize> descriptor_ranges_; diff --git a/src/vulkan/command_buffer.cc b/src/vulkan/command_buffer.cc index 2843667..765ef94 100644 --- a/src/vulkan/command_buffer.cc +++ b/src/vulkan/command_buffer.cc @@ -108,7 +108,6 @@ Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms) { void CommandBuffer::Reset() { if (guarded_) { - device_->GetPtrs()->vkEndCommandBuffer(command_); device_->GetPtrs()->vkResetCommandBuffer(command_, 0); guarded_ = false; } diff --git a/src/vulkan/descriptor.h b/src/vulkan/descriptor.h index 03434a3..88f6813 100644 --- a/src/vulkan/descriptor.h +++ b/src/vulkan/descriptor.h @@ -31,6 +31,7 @@ namespace vulkan { class CommandBuffer; class Device; class BufferDescriptor; +class ImageDescriptor; class BufferBackedDescriptor; class SamplerDescriptor; @@ -57,16 +58,12 @@ class Descriptor { virtual void UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set) = 0; virtual Result CreateResourceIfNeeded() = 0; - virtual Result RecordCopyDataToResourceIfNeeded(CommandBuffer*) { return {}; } - virtual Result RecordCopyDataToHost(CommandBuffer*) { return {}; } - virtual Result MoveResourceToBufferOutput() { return {}; } - virtual Result SetSizeInElements(uint32_t) { return {}; } - virtual Result AddToBuffer(const std::vector<Value>&, uint32_t) { return {}; } virtual uint32_t GetDescriptorCount() { return 1; } virtual std::vector<uint32_t> GetDynamicOffsets() { return {}; } virtual std::vector<VkDeviceSize> GetDescriptorOffsets() { return {}; } virtual std::vector<VkDeviceSize> GetDescriptorRanges() { return {}; } virtual BufferDescriptor* AsBufferDescriptor() { return nullptr; } + virtual ImageDescriptor* AsImageDescriptor() { return nullptr; } virtual BufferBackedDescriptor* AsBufferBackedDescriptor() { return nullptr; } virtual SamplerDescriptor* AsSamplerDescriptor() { return nullptr; } uint32_t GetDescriptorSet() const { return descriptor_set_; } diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index 22cd77a..d951f49 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -53,6 +53,36 @@ const char k16BitStorage_InputOutput[] = const char kSubgroupSizeControl[] = "SubgroupSizeControl.subgroupSizeControl"; const char kComputeFullSubgroups[] = "SubgroupSizeControl.computeFullSubgroups"; +const char kSubgroupSupportedOperations[] = "SubgroupSupportedOperations"; +const char kSubgroupSupportedOperationsBasic[] = + "SubgroupSupportedOperations.basic"; +const char kSubgroupSupportedOperationsVote[] = + "SubgroupSupportedOperations.vote"; +const char kSubgroupSupportedOperationsArithmetic[] = + "SubgroupSupportedOperations.arithmetic"; +const char kSubgroupSupportedOperationsBallot[] = + "SubgroupSupportedOperations.ballot"; +const char kSubgroupSupportedOperationsShuffle[] = + "SubgroupSupportedOperations.shuffle"; +const char kSubgroupSupportedOperationsShuffleRelative[] = + "SubgroupSupportedOperations.shuffleRelative"; +const char kSubgroupSupportedOperationsClustered[] = + "SubgroupSupportedOperations.clustered"; +const char kSubgroupSupportedOperationsQuad[] = + "SubgroupSupportedOperations.quad"; +const char kSubgroupSupportedStages[] = "SubgroupSupportedStages"; +const char kSubgroupSupportedStagesVertex[] = "SubgroupSupportedStages.vertex"; +const char kSubgroupSupportedStagesTessellationControl[] = + "SubgroupSupportedStages.tessellationControl"; +const char kSubgroupSupportedStagesTessellationEvaluation[] = + "SubgroupSupportedStages.tessellationEvaluation"; +const char kSubgroupSupportedStagesGeometry[] = + "SubgroupSupportedStages.geometry"; +const char kSubgroupSupportedStagesFragment[] = + "SubgroupSupportedStages.fragment"; +const char kSubgroupSupportedStagesCompute[] = + "SubgroupSupportedStages.compute"; + struct BaseOutStructure { VkStructureType sType; void* pNext; @@ -437,6 +467,7 @@ Result Device::Initialize( VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr; VkPhysicalDeviceVulkan11Features* vulkan11_ptrs = nullptr; VkPhysicalDeviceVulkan12Features* vulkan12_ptrs = nullptr; + VkPhysicalDeviceVulkan13Features* vulkan13_ptrs = nullptr; VkPhysicalDeviceSubgroupSizeControlFeaturesEXT* subgroup_size_control_features = nullptr; void* ptr = available_features2.pNext; @@ -469,6 +500,9 @@ Result Device::Initialize( case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: vulkan12_ptrs = static_cast<VkPhysicalDeviceVulkan12Features*>(ptr); break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: + vulkan13_ptrs = static_cast<VkPhysicalDeviceVulkan13Features*>(ptr); + break; default: break; } @@ -513,7 +547,7 @@ Result Device::Initialize( "Shader 8-bit storage requested but feature not returned"); } if ((feature == kSubgroupSizeControl || feature == kComputeFullSubgroups) && - subgroup_size_control_features == nullptr) { + subgroup_size_control_features == nullptr && vulkan13_ptrs == nullptr) { return amber::Result("Missing subgroup size control features"); } @@ -622,13 +656,25 @@ Result Device::Initialize( } } - if (feature == kSubgroupSizeControl && - subgroup_size_control_features->subgroupSizeControl != VK_TRUE) { - return amber::Result("Missing subgroup size control feature"); - } - if (feature == kComputeFullSubgroups && - subgroup_size_control_features->computeFullSubgroups != VK_TRUE) { - return amber::Result("Missing compute full subgroups feature"); + // If Vulkan 1.3 structure exists the features are set there. + if (vulkan13_ptrs) { + if (feature == kSubgroupSizeControl && + vulkan13_ptrs->subgroupSizeControl != VK_TRUE) { + return amber::Result("Missing subgroup size control feature"); + } + if (feature == kComputeFullSubgroups && + vulkan13_ptrs->computeFullSubgroups != VK_TRUE) { + return amber::Result("Missing compute full subgroups feature"); + } + } else { + if (feature == kSubgroupSizeControl && + subgroup_size_control_features->subgroupSizeControl != VK_TRUE) { + return amber::Result("Missing subgroup size control feature"); + } + if (feature == kComputeFullSubgroups && + subgroup_size_control_features->computeFullSubgroups != VK_TRUE) { + return amber::Result("Missing compute full subgroups feature"); + } } } @@ -647,19 +693,153 @@ Result Device::Initialize( std::find(required_features.begin(), required_features.end(), kSubgroupSizeControl) != required_features.end(); - if (needs_subgroup_size_control) { + bool needs_subgroup_supported_operations = false; + bool needs_subgroup_supported_stages = false; + + // Search for subgroup supported operations requirements. + for (const auto& feature : required_features) + if (feature.find(kSubgroupSupportedOperations) != std::string::npos) + needs_subgroup_supported_operations = true; + + // Search for subgroup supported stages requirements. + for (const auto& feature : required_features) + if (feature.find(kSubgroupSupportedStages) != std::string::npos) + needs_subgroup_supported_stages = true; + + const bool needs_subgroup_properties = + needs_subgroup_supported_operations || needs_subgroup_supported_stages; + + if (needs_subgroup_size_control || needs_subgroup_properties) { + // Always chain all physical device properties structs in case at least one + // of them is needed. VkPhysicalDeviceProperties2 properties2 = {}; + VkPhysicalDeviceSubgroupProperties subgroup_properties = {}; + VkPhysicalDeviceVulkan11Properties vulkan11_properties = {}; + VkSubgroupFeatureFlags subgroup_supported_operations; + VkShaderStageFlags subgroup_supported_stages; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; properties2.pNext = &subgroup_size_control_properties_; subgroup_size_control_properties_.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT; + if (SupportsApiVersion(1, 2, 0)) { + subgroup_size_control_properties_.pNext = &vulkan11_properties; + vulkan11_properties.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; + } else { + subgroup_size_control_properties_.pNext = &subgroup_properties; + subgroup_properties.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; + } - if (!SupportsApiVersion(1, 1, 0)) { + if (needs_subgroup_size_control && !SupportsApiVersion(1, 1, 0)) { return Result( "Vulkan: Device::Initialize subgroup size control feature also " "requires an API version of 1.1 or higher"); } + if (needs_subgroup_properties && !SupportsApiVersion(1, 1, 0)) { + return Result( + "Vulkan: Device::Initialize subgroup properties also " + "requires an API version of 1.1 or higher"); + } ptrs_.vkGetPhysicalDeviceProperties2(physical_device_, &properties2); + + if (needs_subgroup_supported_operations) { + // Read supported subgroup operations from the correct struct depending on + // the device API + if (SupportsApiVersion(1, 2, 0)) { + subgroup_supported_operations = + vulkan11_properties.subgroupSupportedOperations; + } else { + subgroup_supported_operations = subgroup_properties.supportedOperations; + } + + for (const auto& feature : required_features) { + if (feature == kSubgroupSupportedOperationsBasic && + !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_BASIC_BIT)) { + return amber::Result("Missing subgroup operation basic feature"); + } + if (feature == kSubgroupSupportedOperationsVote && + !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_VOTE_BIT)) { + return amber::Result("Missing subgroup operation vote feature"); + } + if (feature == kSubgroupSupportedOperationsArithmetic && + !(subgroup_supported_operations & + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT)) { + return amber::Result("Missing subgroup operation arithmetic feature"); + } + if (feature == kSubgroupSupportedOperationsBallot && + !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_BALLOT_BIT)) { + return amber::Result("Missing subgroup operation ballot feature"); + } + if (feature == kSubgroupSupportedOperationsShuffle && + !(subgroup_supported_operations & + VK_SUBGROUP_FEATURE_SHUFFLE_BIT)) { + return amber::Result("Missing subgroup operation shuffle feature"); + } + if (feature == kSubgroupSupportedOperationsShuffleRelative && + !(subgroup_supported_operations & + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT)) { + return amber::Result( + "Missing subgroup operation shuffle relative feature"); + } + if (feature == kSubgroupSupportedOperationsClustered && + !(subgroup_supported_operations & + VK_SUBGROUP_FEATURE_CLUSTERED_BIT)) { + return amber::Result("Missing subgroup operation clustered feature"); + } + if (feature == kSubgroupSupportedOperationsQuad && + !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_QUAD_BIT)) { + return amber::Result("Missing subgroup operation quad feature"); + } + } + } + + if (needs_subgroup_supported_stages) { + // Read supported subgroup stages from the correct struct depending on the + // device API + if (SupportsApiVersion(1, 2, 0)) { + subgroup_supported_stages = vulkan11_properties.subgroupSupportedStages; + } else { + subgroup_supported_stages = subgroup_properties.supportedStages; + } + + for (const auto& feature : required_features) { + if (feature == kSubgroupSupportedStagesVertex && + !(subgroup_supported_stages & VK_SHADER_STAGE_VERTEX_BIT)) { + return amber::Result( + "Subgroup operations not supported for vertex shader stage"); + } + if (feature == kSubgroupSupportedStagesTessellationControl && + !(subgroup_supported_stages & + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)) { + return amber::Result( + "Subgroup operations not supported for tessellation control " + "shader stage"); + } + if (feature == kSubgroupSupportedStagesTessellationEvaluation && + !(subgroup_supported_stages & + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) { + return amber::Result( + "Subgroup operations not supported for tessellation evaluation " + "shader stage"); + } + if (feature == kSubgroupSupportedStagesGeometry && + !(subgroup_supported_stages & VK_SHADER_STAGE_GEOMETRY_BIT)) { + return amber::Result( + "Subgroup operations not supported for geometry shader stage"); + } + if (feature == kSubgroupSupportedStagesFragment && + !(subgroup_supported_stages & VK_SHADER_STAGE_FRAGMENT_BIT)) { + return amber::Result( + "Subgroup operations not supported for fragment shader stage"); + } + if (feature == kSubgroupSupportedStagesCompute && + !(subgroup_supported_stages & VK_SHADER_STAGE_COMPUTE_BIT)) { + return amber::Result( + "Subgroup operations not supported for compute shader stage"); + } + } + } } return {}; @@ -676,6 +856,7 @@ bool Device::IsFormatSupportedByPhysicalDevice(const Format& format, bool is_buffer_type_image = false; switch (type) { case BufferType::kColor: + case BufferType::kResolve: case BufferType::kStorageImage: flag = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; is_buffer_type_image = true; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 6bed716..1ed60f4 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -177,8 +177,11 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { } else { vk_pipeline = MakeUnique<GraphicsPipeline>( device_.get(), pipeline->GetColorAttachments(), - pipeline->GetDepthStencilBuffer(), engine_data.fence_timeout_ms, - stage_create_info); + pipeline->GetDepthStencilBuffer(), pipeline->GetResolveTargets(), + engine_data.fence_timeout_ms, stage_create_info); + + vk_pipeline->AsGraphics()->SetPatchControlPoints( + pipeline->GetPipelineData()->GetPatchControlPoints()); r = vk_pipeline->AsGraphics()->Initialize(pipeline->GetFramebufferWidth(), pipeline->GetFramebufferHeight(), diff --git a/src/vulkan/frame_buffer.cc b/src/vulkan/frame_buffer.cc index 47eb82d..b6ad13a 100644 --- a/src/vulkan/frame_buffer.cc +++ b/src/vulkan/frame_buffer.cc @@ -30,10 +30,12 @@ FrameBuffer::FrameBuffer( Device* device, const std::vector<const amber::Pipeline::BufferInfo*>& color_attachments, amber::Pipeline::BufferInfo depth_stencil_attachment, + const std::vector<const amber::Pipeline::BufferInfo*>& resolve_targets, uint32_t width, uint32_t height) : device_(device), color_attachments_(color_attachments), + resolve_targets_(resolve_targets), depth_stencil_attachment_(depth_stencil_attachment), width_(width), height_(height) {} @@ -62,15 +64,16 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass) { attachments.resize(color_attachments_.size()); for (auto* info : color_attachments_) { + const VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; color_images_.push_back(MakeUnique<TransferImage>( device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, width_ << info->base_mip_level, + VK_IMAGE_TYPE_2D, usage_flags, width_ << info->base_mip_level, height_ << info->base_mip_level, depth_, info->buffer->GetMipLevels(), - info->base_mip_level, 1u, 1u)); + info->base_mip_level, 1u, info->buffer->GetSamples())); - Result r = color_images_.back()->Initialize( - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + Result r = color_images_.back()->Initialize(); if (!r.IsSuccess()) return r; @@ -87,19 +90,37 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass) { aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; assert(aspect != 0); + const VkImageUsageFlags usage_flags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + depth_stencil_image_ = MakeUnique<TransferImage>( device_, *depth_stencil_attachment_.buffer->GetFormat(), aspect, - VK_IMAGE_TYPE_2D, width_, height_, depth_, 1u, 0u, 1u, 1u); + VK_IMAGE_TYPE_2D, usage_flags, width_, height_, depth_, 1u, 0u, 1u, 1u); - Result r = depth_stencil_image_->Initialize( - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + Result r = depth_stencil_image_->Initialize(); if (!r.IsSuccess()) return r; attachments.push_back(depth_stencil_image_->GetVkImageView()); } + for (auto* info : resolve_targets_) { + const VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + resolve_images_.push_back(MakeUnique<TransferImage>( + device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_TYPE_2D, usage_flags, width_, height_, depth_, 1u, 0u, 1u, + 1u)); + + Result r = resolve_images_.back()->Initialize(); + if (!r.IsSuccess()) + return r; + + attachments.push_back(resolve_images_.back()->GetVkImageView()); + } + VkFramebufferCreateInfo frame_buffer_info = VkFramebufferCreateInfo(); frame_buffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; frame_buffer_info.renderPass = render_pass; @@ -126,6 +147,9 @@ void FrameBuffer::ChangeFrameLayout(CommandBuffer* command, for (auto& img : color_images_) img->ImageBarrier(command, color_layout, color_stage); + for (auto& img : resolve_images_) + img->ImageBarrier(command, color_layout, color_stage); + if (depth_stencil_image_) depth_stencil_image_->ImageBarrier(command, depth_layout, depth_stage); } @@ -162,6 +186,9 @@ void FrameBuffer::TransferImagesToHost(CommandBuffer* command) { for (auto& img : color_images_) img->CopyToHost(command); + for (auto& img : resolve_images_) + img->CopyToHost(command); + if (depth_stencil_image_) depth_stencil_image_->CopyToHost(command); } @@ -176,6 +203,15 @@ void FrameBuffer::CopyImagesToBuffers() { info->buffer->GetSizeInBytes()); } + for (size_t i = 0; i < resolve_images_.size(); ++i) { + auto& img = resolve_images_[i]; + auto* info = resolve_targets_[i]; + auto* values = info->buffer->ValuePtr(); + values->resize(info->buffer->GetSizeInBytes()); + std::memcpy(values->data(), img->HostAccessibleMemoryPtr(), + info->buffer->GetSizeInBytes()); + } + if (depth_stencil_image_) { auto* values = depth_stencil_attachment_.buffer->ValuePtr(); values->resize(depth_stencil_attachment_.buffer->GetSizeInBytes()); @@ -205,6 +241,18 @@ void FrameBuffer::CopyBuffersToImages() { info->buffer->GetSizeInBytes()); } + for (size_t i = 0; i < resolve_images_.size(); ++i) { + auto& img = resolve_images_[i]; + auto* info = resolve_targets_[i]; + auto* values = info->buffer->ValuePtr(); + // Nothing to do if our local buffer is empty + if (values->empty()) + continue; + + std::memcpy(img->HostAccessibleMemoryPtr(), values->data(), + info->buffer->GetSizeInBytes()); + } + if (depth_stencil_image_) { auto* values = depth_stencil_attachment_.buffer->ValuePtr(); // Nothing to do if our local buffer is empty diff --git a/src/vulkan/frame_buffer.h b/src/vulkan/frame_buffer.h index 064b6d3..5774289 100644 --- a/src/vulkan/frame_buffer.h +++ b/src/vulkan/frame_buffer.h @@ -34,6 +34,7 @@ class FrameBuffer { Device* device, const std::vector<const amber::Pipeline::BufferInfo*>& color_attachments, amber::Pipeline::BufferInfo depth_stencil_attachment, + const std::vector<const amber::Pipeline::BufferInfo*>& resolve_targets, uint32_t width, uint32_t height); ~FrameBuffer(); @@ -70,9 +71,11 @@ class FrameBuffer { Device* device_ = nullptr; std::vector<const amber::Pipeline::BufferInfo*> color_attachments_; + std::vector<const amber::Pipeline::BufferInfo*> resolve_targets_; amber::Pipeline::BufferInfo depth_stencil_attachment_; VkFramebuffer frame_ = VK_NULL_HANDLE; std::vector<std::unique_ptr<TransferImage>> color_images_; + std::vector<std::unique_ptr<TransferImage>> resolve_images_; std::unique_ptr<TransferImage> depth_stencil_image_; uint32_t width_ = 0; uint32_t height_ = 0; diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index 5536440..138f32c 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -234,6 +234,8 @@ VkBlendFactor ToVkBlendFactor(BlendFactor factor) { return VK_BLEND_FACTOR_SRC1_ALPHA; case BlendFactor::kOneMinusSrc1Alpha: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; + case BlendFactor::kUnknown: + break; } assert(false && "Vulkan::Unknown BlendFactor"); return VK_BLEND_FACTOR_ZERO; @@ -343,6 +345,8 @@ VkBlendOp ToVkBlendOp(BlendOp op) { return VK_BLEND_OP_GREEN_EXT; case BlendOp::kBlue: return VK_BLEND_OP_BLUE_EXT; + case BlendOp::kUnknown: + break; } assert(false && "Vulkan::Unknown BlendOp"); return VK_BLEND_OP_ADD; @@ -386,6 +390,7 @@ GraphicsPipeline::GraphicsPipeline( Device* device, const std::vector<amber::Pipeline::BufferInfo>& color_buffers, amber::Pipeline::BufferInfo depth_stencil_buffer, + const std::vector<amber::Pipeline::BufferInfo>& resolve_targets, uint32_t fence_timeout_ms, const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info) : Pipeline(PipelineType::kGraphics, @@ -395,6 +400,8 @@ GraphicsPipeline::GraphicsPipeline( depth_stencil_buffer_(depth_stencil_buffer) { for (const auto& info : color_buffers) color_buffers_.push_back(&info); + for (const auto& info : resolve_targets) + resolve_targets_.push_back(&info); } GraphicsPipeline::~GraphicsPipeline() { @@ -412,6 +419,7 @@ Result GraphicsPipeline::CreateRenderPass() { std::vector<VkAttachmentReference> color_refer; VkAttachmentReference depth_refer = VkAttachmentReference(); + std::vector<VkAttachmentReference> resolve_refer; for (const auto* info : color_buffers_) { attachment_desc.push_back(kDefaultAttachmentDesc); @@ -421,6 +429,8 @@ Result GraphicsPipeline::CreateRenderPass() { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment_desc.back().finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment_desc.back().samples = + static_cast<VkSampleCountFlagBits>(info->buffer->GetSamples()); VkAttachmentReference ref = VkAttachmentReference(); ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1); @@ -446,6 +456,23 @@ Result GraphicsPipeline::CreateRenderPass() { subpass_desc.pDepthStencilAttachment = &depth_refer; } + for (const auto* info : resolve_targets_) { + attachment_desc.push_back(kDefaultAttachmentDesc); + attachment_desc.back().format = + device_->GetVkFormat(*info->buffer->GetFormat()); + attachment_desc.back().initialLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment_desc.back().finalLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference ref = VkAttachmentReference(); + ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1); + ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolve_refer.push_back(ref); + } + + subpass_desc.pResolveAttachments = resolve_refer.data(); + VkRenderPassCreateInfo render_pass_info = VkRenderPassCreateInfo(); render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_info.attachmentCount = @@ -621,6 +648,16 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline( VK_FALSE, /* alphaToOneEnable */ }; + // Search for multisampled color buffers and adjust the rasterization samples + // to match. + for (const auto& cb : color_buffers_) { + uint32_t samples = cb->buffer->GetSamples(); + assert(static_cast<VkSampleCountFlagBits>(samples) >= + multisampleInfo.rasterizationSamples); + multisampleInfo.rasterizationSamples = + static_cast<VkSampleCountFlagBits>(samples); + } + VkGraphicsPipelineCreateInfo pipeline_info = VkGraphicsPipelineCreateInfo(); pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.stageCount = static_cast<uint32_t>(shader_stage_info.size()); @@ -704,8 +741,9 @@ Result GraphicsPipeline::Initialize(uint32_t width, if (!r.IsSuccess()) return r; - frame_ = MakeUnique<FrameBuffer>(device_, color_buffers_, - depth_stencil_buffer_, width, height); + frame_ = + MakeUnique<FrameBuffer>(device_, color_buffers_, depth_stencil_buffer_, + resolve_targets_, width, height); r = frame_->Initialize(render_pass_); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/graphics_pipeline.h b/src/vulkan/graphics_pipeline.h index 7076231..cd55aad 100644 --- a/src/vulkan/graphics_pipeline.h +++ b/src/vulkan/graphics_pipeline.h @@ -43,6 +43,7 @@ class GraphicsPipeline : public Pipeline { Device* device, const std::vector<amber::Pipeline::BufferInfo>& color_buffers, amber::Pipeline::BufferInfo depth_stencil_buffer, + const std::vector<amber::Pipeline::BufferInfo>& resolve_targets, uint32_t fence_timeout_ms, const std::vector<VkPipelineShaderStageCreateInfo>&); ~GraphicsPipeline() override; @@ -86,8 +87,9 @@ class GraphicsPipeline : public Pipeline { VkRenderPass render_pass_ = VK_NULL_HANDLE; std::unique_ptr<FrameBuffer> frame_; - // color buffers are owned by the amber::Pipeline. + // color buffers and resolve targets are owned by the amber::Pipeline. std::vector<const amber::Pipeline::BufferInfo*> color_buffers_; + std::vector<const amber::Pipeline::BufferInfo*> resolve_targets_; amber::Pipeline::BufferInfo depth_stencil_buffer_; std::unique_ptr<IndexBuffer> index_buffer_; diff --git a/src/vulkan/image_descriptor.cc b/src/vulkan/image_descriptor.cc index 94e67d0..1d20244 100644 --- a/src/vulkan/image_descriptor.cc +++ b/src/vulkan/image_descriptor.cc @@ -29,51 +29,25 @@ ImageDescriptor::ImageDescriptor(Buffer* buffer, Device* device, uint32_t base_mip_level, uint32_t desc_set, - uint32_t binding) - : BufferBackedDescriptor(buffer, type, device, desc_set, binding), + uint32_t binding, + Pipeline* pipeline) + : BufferBackedDescriptor(buffer, type, device, desc_set, binding, pipeline), base_mip_level_(base_mip_level), vulkan_sampler_(device) {} ImageDescriptor::~ImageDescriptor() = default; -Result ImageDescriptor::RecordCopyDataToResourceIfNeeded( - CommandBuffer* command) { - const auto transfer_images = GetResources(); - for (const auto& image : transfer_images) { - // Static cast is safe, because the type is known to be TransferImage*. - static_cast<TransferImage*>(image.second) - ->ImageBarrier(command, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT); - } - - Result r = BufferBackedDescriptor::RecordCopyDataToResourceIfNeeded(command); - if (!r.IsSuccess()) - return r; - - // Just do this as early as possible. - for (const auto& image : transfer_images) { - static_cast<TransferImage*>(image.second) - ->ImageBarrier(command, VK_IMAGE_LAYOUT_GENERAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - } - - return {}; -} - Result ImageDescriptor::CreateResourceIfNeeded() { - if (!transfer_images_.empty()) { - return Result( - "Vulkan: ImageDescriptor::CreateResourceIfNeeded() must be called " - "only when |transfer_images| is empty"); - } + auto& transfer_resources = pipeline_->GetDescriptorTransferResources(); for (const auto& amber_buffer : GetAmberBuffers()) { if (amber_buffer->ValuePtr()->empty()) continue; // Check if the transfer image is already created. - if (transfer_images_.count(amber_buffer) > 0) + if (transfer_resources.count(amber_buffer) > 0) { continue; + } // Default to 2D image. VkImageType image_type = VK_IMAGE_TYPE_2D; @@ -103,14 +77,8 @@ Result ImageDescriptor::CreateResourceIfNeeded() { aspect = VK_IMAGE_ASPECT_COLOR_BIT; } - auto transfer_image = MakeUnique<TransferImage>( - device_, *fmt, aspect, image_type, amber_buffer->GetWidth(), - amber_buffer->GetHeight(), amber_buffer->GetDepth(), - amber_buffer->GetMipLevels(), base_mip_level_, VK_REMAINING_MIP_LEVELS, - amber_buffer->GetSamples()); VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (type_ == DescriptorType::kStorageImage) { usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else { @@ -119,11 +87,14 @@ Result ImageDescriptor::CreateResourceIfNeeded() { usage |= VK_IMAGE_USAGE_SAMPLED_BIT; } - Result r = transfer_image->Initialize(usage); - if (!r.IsSuccess()) - return r; + auto transfer_image = MakeUnique<TransferImage>( + device_, *fmt, aspect, image_type, usage, amber_buffer->GetWidth(), + amber_buffer->GetHeight(), amber_buffer->GetDepth(), + amber_buffer->GetMipLevels(), base_mip_level_, VK_REMAINING_MIP_LEVELS, + amber_buffer->GetSamples()); - transfer_images_[amber_buffer] = std::move(transfer_image); + // Store the transfer image to the pipeline's map of transfer images. + transfer_resources[amber_buffer] = std::move(transfer_image); } if (amber_sampler_) { @@ -136,28 +107,6 @@ Result ImageDescriptor::CreateResourceIfNeeded() { return {}; } -Result ImageDescriptor::RecordCopyDataToHost(CommandBuffer* command) { - if (!IsReadOnly()) { - for (auto& image : GetResources()) { - static_cast<TransferImage*>(image.second) - ->ImageBarrier(command, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT); - } - - BufferBackedDescriptor::RecordCopyDataToHost(command); - } - - return {}; -} - -Result ImageDescriptor::MoveResourceToBufferOutput() { - Result r = BufferBackedDescriptor::MoveResourceToBufferOutput(); - - transfer_images_.clear(); - - return r; -} - void ImageDescriptor::UpdateDescriptorSetIfNeeded( VkDescriptorSet descriptor_set) { if (!is_descriptor_set_update_needed_) @@ -170,7 +119,9 @@ void ImageDescriptor::UpdateDescriptorSetIfNeeded( // Create VkDescriptorImageInfo for every descriptor image. for (const auto& amber_buffer : GetAmberBuffers()) { - const auto& image = transfer_images_[amber_buffer]; + const auto& image = + pipeline_->GetDescriptorTransferResources()[amber_buffer] + ->AsTransferImage(); VkDescriptorImageInfo image_info = {vulkan_sampler_.GetVkSampler(), image->GetVkImageView(), layout}; image_infos.push_back(image_info); @@ -191,23 +142,5 @@ void ImageDescriptor::UpdateDescriptorSetIfNeeded( is_descriptor_set_update_needed_ = false; } -std::vector<std::pair<Buffer*, Resource*>> ImageDescriptor::GetResources() { - std::vector<std::pair<Buffer*, Resource*>> ret; - // Add unique amber buffers and related transfer images to the vector. - for (const auto& amber_buffer : GetAmberBuffers()) { - // Skip duplicate values. - const auto& image = - std::find_if(ret.begin(), ret.end(), - [&](const std::pair<Buffer*, Resource*>& buffer) { - return buffer.first == amber_buffer; - }); - if (image != ret.end()) - continue; - - ret.emplace_back(amber_buffer, transfer_images_[amber_buffer].get()); - } - return ret; -} - } // namespace vulkan } // namespace amber diff --git a/src/vulkan/image_descriptor.h b/src/vulkan/image_descriptor.h index 908ed17..3046436 100644 --- a/src/vulkan/image_descriptor.h +++ b/src/vulkan/image_descriptor.h @@ -21,6 +21,7 @@ #include <vector> #include "src/vulkan/buffer_backed_descriptor.h" +#include "src/vulkan/pipeline.h" #include "src/vulkan/sampler.h" #include "src/vulkan/transfer_image.h" @@ -34,22 +35,18 @@ class ImageDescriptor : public BufferBackedDescriptor { Device* device, uint32_t base_mip_level, uint32_t desc_set, - uint32_t binding); + uint32_t binding, + Pipeline* pipeline); ~ImageDescriptor() override; void UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set) override; - Result RecordCopyDataToResourceIfNeeded(CommandBuffer* command) override; Result CreateResourceIfNeeded() override; - Result RecordCopyDataToHost(CommandBuffer* command) override; - Result MoveResourceToBufferOutput() override; void SetAmberSampler(amber::Sampler* sampler) { amber_sampler_ = sampler; } - protected: - std::vector<std::pair<Buffer*, Resource*>> GetResources() override; + ImageDescriptor* AsImageDescriptor() override { return this; } private: uint32_t base_mip_level_ = 0; - std::unordered_map<Buffer*, std::unique_ptr<TransferImage>> transfer_images_; amber::Sampler* amber_sampler_ = nullptr; amber::vulkan::Sampler vulkan_sampler_; }; diff --git a/src/vulkan/index_buffer.cc b/src/vulkan/index_buffer.cc index 73a9083..b651427 100644 --- a/src/vulkan/index_buffer.cc +++ b/src/vulkan/index_buffer.cc @@ -38,8 +38,12 @@ Result IndexBuffer::SendIndexData(CommandBuffer* command, Buffer* buffer) { transfer_buffer_ = MakeUnique<TransferBuffer>(device_, buffer->GetSizeInBytes(), nullptr); - Result r = transfer_buffer_->Initialize(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT); + Result r = transfer_buffer_->AddUsageFlags(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + if (!r.IsSuccess()) + return r; + + r = transfer_buffer_->Initialize(); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc index 259f375..df301e4 100644 --- a/src/vulkan/pipeline.cc +++ b/src/vulkan/pipeline.cc @@ -273,6 +273,18 @@ Result Pipeline::GetDescriptorSlot(uint32_t desc_set, return {}; } +Result Pipeline::AddDescriptorBuffer(Buffer* amber_buffer) { + // Don't add the buffer if it's already added. + const auto& buffer = std::find_if( + descriptor_buffers_.begin(), descriptor_buffers_.end(), + [&](const Buffer* buf) { return buf == amber_buffer; }); + if (buffer != descriptor_buffers_.end()) { + return {}; + } + descriptor_buffers_.push_back(amber_buffer); + return {}; +} + Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { if (cmd == nullptr) return Result("Pipeline::AddBufferDescriptor BufferCommand is nullptr"); @@ -319,7 +331,7 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { if (is_image) { auto image_desc = MakeUnique<ImageDescriptor>( cmd->GetBuffer(), desc_type, device_, cmd->GetBaseMipLevel(), - cmd->GetDescriptorSet(), cmd->GetBinding()); + cmd->GetDescriptorSet(), cmd->GetBinding(), this); if (cmd->IsCombinedImageSampler()) image_desc->SetAmberSampler(cmd->GetSampler()); @@ -327,9 +339,10 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { } else { auto buffer_desc = MakeUnique<BufferDescriptor>( cmd->GetBuffer(), desc_type, device_, cmd->GetDescriptorSet(), - cmd->GetBinding()); + cmd->GetBinding(), this); descriptors.push_back(std::move(buffer_desc)); } + AddDescriptorBuffer(cmd->GetBuffer()); desc = descriptors.back().get(); } else { if (desc->GetDescriptorType() != desc_type) { @@ -338,6 +351,7 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) { "descriptor types"); } desc->AsBufferBackedDescriptor()->AddAmberBuffer(cmd->GetBuffer()); + AddDescriptorBuffer(cmd->GetBuffer()); } if (cmd->IsUniformDynamic() || cmd->IsSSBODynamic()) @@ -409,6 +423,16 @@ Result Pipeline::SendDescriptorDataToDeviceIfNeeded() { } } + // Initialize transfer buffers / images. + for (auto buffer : descriptor_buffers_) { + if (descriptor_transfer_resources_.count(buffer) == 0) { + return Result( + "Vulkan: Pipeline::SendDescriptorDataToDeviceIfNeeded() " + "descriptor's transfer resource is not found"); + } + descriptor_transfer_resources_[buffer]->Initialize(); + } + // Note that if a buffer for a descriptor is host accessible and // does not need to record a command to copy data to device, it // directly writes data to the buffer. The direct write must be @@ -424,11 +448,27 @@ Result Pipeline::SendDescriptorDataToDeviceIfNeeded() { if (!guard.IsRecording()) return guard.GetResult(); - for (auto& info : descriptor_set_info_) { - for (auto& desc : info.descriptors) { - Result r = desc->RecordCopyDataToResourceIfNeeded(command_.get()); - if (!r.IsSuccess()) - return r; + // Copy descriptor data to transfer resources. + for (auto& buffer : descriptor_buffers_) { + if (auto transfer_buffer = + descriptor_transfer_resources_[buffer]->AsTransferBuffer()) { + BufferBackedDescriptor::RecordCopyBufferDataToTransferResourceIfNeeded( + GetCommandBuffer(), buffer, transfer_buffer); + } else if (auto transfer_image = + descriptor_transfer_resources_[buffer]->AsTransferImage()) { + transfer_image->ImageBarrier(GetCommandBuffer(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + BufferBackedDescriptor::RecordCopyBufferDataToTransferResourceIfNeeded( + GetCommandBuffer(), buffer, transfer_image); + + transfer_image->ImageBarrier(GetCommandBuffer(), VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + } else { + return Result( + "Vulkan: Pipeline::SendDescriptorDataToDeviceIfNeeded() " + "this should be unreachable"); } } return guard.Submit(GetFenceTimeout()); @@ -472,14 +512,38 @@ void Pipeline::BindVkDescriptorSets(const VkPipelineLayout& pipeline_layout) { } Result Pipeline::ReadbackDescriptorsToHostDataQueue() { + // Record required commands to copy the data to a host visible buffer. { CommandBufferGuard guard(GetCommandBuffer()); if (!guard.IsRecording()) return guard.GetResult(); - for (auto& desc_set : descriptor_set_info_) { - for (auto& desc : desc_set.descriptors) - desc->RecordCopyDataToHost(command_.get()); + for (auto& buffer : descriptor_buffers_) { + if (descriptor_transfer_resources_.count(buffer) == 0) { + return Result( + "Vulkan: Pipeline::ReadbackDescriptorsToHostDataQueue() " + "descriptor's transfer resource is not found"); + } + if (auto transfer_buffer = + descriptor_transfer_resources_[buffer]->AsTransferBuffer()) { + Result r = BufferBackedDescriptor::RecordCopyTransferResourceToHost( + GetCommandBuffer(), transfer_buffer); + if (!r.IsSuccess()) + return r; + } else if (auto transfer_image = descriptor_transfer_resources_[buffer] + ->AsTransferImage()) { + transfer_image->ImageBarrier(GetCommandBuffer(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT); + Result r = BufferBackedDescriptor::RecordCopyTransferResourceToHost( + GetCommandBuffer(), transfer_image); + if (!r.IsSuccess()) + return r; + } else { + return Result( + "Vulkan: Pipeline::ReadbackDescriptorsToHostDataQueue() " + "this should be unreachable"); + } } Result r = guard.Submit(GetFenceTimeout()); @@ -487,14 +551,15 @@ Result Pipeline::ReadbackDescriptorsToHostDataQueue() { return r; } - for (auto& desc_set : descriptor_set_info_) { - for (auto& desc : desc_set.descriptors) { - Result r = desc->MoveResourceToBufferOutput(); - if (!r.IsSuccess()) - return r; - } + // Move data from transfer buffers to output buffers. + for (auto& buffer : descriptor_buffers_) { + auto& transfer_resource = descriptor_transfer_resources_[buffer]; + Result r = BufferBackedDescriptor::MoveTransferResourceToBufferOutput( + transfer_resource.get(), buffer); + if (!r.IsSuccess()) + return r; } - + descriptor_transfer_resources_.clear(); return {}; } diff --git a/src/vulkan/pipeline.h b/src/vulkan/pipeline.h index 98b0c2a..1f85cb6 100644 --- a/src/vulkan/pipeline.h +++ b/src/vulkan/pipeline.h @@ -27,6 +27,7 @@ #include "src/vulkan/buffer_backed_descriptor.h" #include "src/vulkan/command_buffer.h" #include "src/vulkan/push_constant.h" +#include "src/vulkan/resource.h" namespace amber { @@ -59,6 +60,11 @@ class Pipeline { /// buffer data object and put it into buffer data queue in host. Result ReadbackDescriptorsToHostDataQueue(); + std::unordered_map<Buffer*, std::unique_ptr<Resource>>& + GetDescriptorTransferResources() { + return descriptor_transfer_resources_; + } + void SetEntryPointName(VkShaderStageFlagBits stage, const std::string& entry) { entry_points_[stage] = entry; @@ -115,10 +121,17 @@ class Pipeline { Result CreateDescriptorSetLayouts(); Result CreateDescriptorPools(); Result CreateDescriptorSets(); + /// Adds a buffer used by a descriptor. The added buffers are be stored in + /// |descriptor_buffers_| vector in the order they are added. + Result AddDescriptorBuffer(Buffer* amber_buffer); PipelineType pipeline_type_; std::vector<DescriptorSetInfo> descriptor_set_info_; std::vector<VkPipelineShaderStageCreateInfo> shader_stage_info_; + std::unordered_map<Buffer*, std::unique_ptr<Resource>> + descriptor_transfer_resources_; + /// Buffers used by descriptors (buffer descriptors and image descriptors). + std::vector<Buffer*> descriptor_buffers_; uint32_t fence_timeout_ms_ = 1000; bool descriptor_related_objects_already_created_ = false; diff --git a/src/vulkan/resource.h b/src/vulkan/resource.h index 1ed447a..d3cc0de 100644 --- a/src/vulkan/resource.h +++ b/src/vulkan/resource.h @@ -27,9 +27,10 @@ namespace vulkan { class CommandBuffer; class Device; +class TransferBuffer; +class TransferImage; -// Class for Vulkan resources. Its children are Vulkan Buffer, Vulkan Image, -// and a class for push constant. +// Class for Vulkan resources. Its children are Vulkan Buffer and Vulkan Image. class Resource { public: virtual ~Resource(); @@ -46,6 +47,12 @@ class Resource { uint32_t GetSizeInBytes() const { return size_in_bytes_; } void UpdateMemoryWithRawData(const std::vector<uint8_t>& raw_data); + bool IsReadOnly() const { return is_read_only_; } + void SetReadOnly(bool read_only) { is_read_only_ = read_only; } + virtual Result Initialize() = 0; + virtual TransferBuffer* AsTransferBuffer() { return nullptr; } + virtual TransferImage* AsTransferImage() { return nullptr; } + protected: Resource(Device* device, uint32_t size); Result CreateVkBuffer(VkBuffer* buffer, VkBufferUsageFlags usage); @@ -82,6 +89,7 @@ class Resource { private: uint32_t size_in_bytes_ = 0; void* memory_ptr_ = nullptr; + bool is_read_only_ = false; }; } // namespace vulkan diff --git a/src/vulkan/transfer_buffer.cc b/src/vulkan/transfer_buffer.cc index a13b22e..512fb7b 100644 --- a/src/vulkan/transfer_buffer.cc +++ b/src/vulkan/transfer_buffer.cc @@ -44,8 +44,14 @@ TransferBuffer::~TransferBuffer() { } } -Result TransferBuffer::Initialize(const VkBufferUsageFlags usage) { - Result r = CreateVkBuffer(&buffer_, usage); +Result TransferBuffer::Initialize() { + if (buffer_) { + return Result( + "Vulkan: TransferBuffer::Initialize() transfer buffer already " + "initialized."); + } + + Result r = CreateVkBuffer(&buffer_, usage_flags_); if (!r.IsSuccess()) return r; @@ -58,8 +64,8 @@ Result TransferBuffer::Initialize(const VkBufferUsageFlags usage) { return r; // Create buffer view - if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) { + if (usage_flags_ & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) { VkBufferViewCreateInfo buffer_view_info = VkBufferViewCreateInfo(); buffer_view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; buffer_view_info.buffer = buffer_; diff --git a/src/vulkan/transfer_buffer.h b/src/vulkan/transfer_buffer.h index 2c0a51d..7d96bec 100644 --- a/src/vulkan/transfer_buffer.h +++ b/src/vulkan/transfer_buffer.h @@ -34,7 +34,17 @@ class TransferBuffer : public Resource { TransferBuffer(Device* device, uint32_t size_in_bytes, Format* format); ~TransferBuffer() override; - Result Initialize(const VkBufferUsageFlags usage); + TransferBuffer* AsTransferBuffer() override { return this; } + Result AddUsageFlags(VkBufferUsageFlags flags) { + if (buffer_ != VK_NULL_HANDLE) { + return Result( + "Vulkan: TransferBuffer::AddUsageFlags Usage flags can't be changed " + "after initializing the buffer."); + } + usage_flags_ |= flags; + return {}; + } + Result Initialize() override; const VkBufferView* GetVkBufferView() const { return &view_; } VkBuffer GetVkBuffer() const { return buffer_; } @@ -47,6 +57,7 @@ class TransferBuffer : public Resource { void CopyToHost(CommandBuffer* command_buffer) override; private: + VkBufferUsageFlags usage_flags_ = 0; VkBuffer buffer_ = VK_NULL_HANDLE; VkDeviceMemory memory_ = VK_NULL_HANDLE; VkBufferView view_ = VK_NULL_HANDLE; diff --git a/src/vulkan/transfer_image.cc b/src/vulkan/transfer_image.cc index 545549d..adfae62 100644 --- a/src/vulkan/transfer_image.cc +++ b/src/vulkan/transfer_image.cc @@ -70,6 +70,7 @@ TransferImage::TransferImage(Device* device, const Format& format, VkImageAspectFlags aspect, VkImageType image_type, + VkImageUsageFlags image_usage_flags, uint32_t x, uint32_t y, uint32_t z, @@ -96,6 +97,7 @@ TransferImage::TransferImage(Device* device, image_info_.extent = {x, y, z}; image_info_.mipLevels = mip_levels; image_info_.samples = GetVkSampleCount(samples); + image_info_.usage = image_usage_flags; } TransferImage::~TransferImage() { @@ -122,12 +124,10 @@ TransferImage::~TransferImage() { } } -Result TransferImage::Initialize(VkImageUsageFlags usage) { +Result TransferImage::Initialize() { if (image_ != VK_NULL_HANDLE) return Result("Vulkan::TransferImage was already initialized"); - image_info_.usage = usage; - if (device_->GetPtrs()->vkCreateImage(device_->GetVkDevice(), &image_info_, nullptr, &image_) != VK_SUCCESS) { return Result("Vulkan::Calling vkCreateImage Fail"); @@ -141,7 +141,7 @@ Result TransferImage::Initialize(VkImageUsageFlags usage) { return r; if (aspect_ & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && - !(usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + !(image_info_.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { // Combined depth/stencil image used as a descriptor. Only one aspect can be // used for the image view. r = CreateVkImageView(VK_IMAGE_ASPECT_DEPTH_BIT); diff --git a/src/vulkan/transfer_image.h b/src/vulkan/transfer_image.h index 741ee3c..3af71d2 100644 --- a/src/vulkan/transfer_image.h +++ b/src/vulkan/transfer_image.h @@ -33,6 +33,7 @@ class TransferImage : public Resource { const Format& format, VkImageAspectFlags aspect, VkImageType image_type, + VkImageUsageFlags image_usage_flags, uint32_t x, uint32_t y, uint32_t z, @@ -42,7 +43,8 @@ class TransferImage : public Resource { uint32_t samples); ~TransferImage() override; - Result Initialize(VkImageUsageFlags usage); + TransferImage* AsTransferImage() override { return this; } + Result Initialize() override; VkImageView GetVkImageView() const { return view_; } void ImageBarrier(CommandBuffer* command_buffer, diff --git a/src/vulkan/vertex_buffer.cc b/src/vulkan/vertex_buffer.cc index 7503681..557b0a3 100644 --- a/src/vulkan/vertex_buffer.cc +++ b/src/vulkan/vertex_buffer.cc @@ -85,8 +85,11 @@ Result VertexBuffer::SendVertexData(CommandBuffer* command) { uint32_t bytes = buf->GetSizeInBytes(); transfer_buffers_.push_back( MakeUnique<TransferBuffer>(device_, bytes, nullptr)); - Result r = transfer_buffers_.back()->Initialize( + Result r = transfer_buffers_.back()->AddUsageFlags( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + if (!r.IsSuccess()) + return r; + r = transfer_buffers_.back()->Initialize(); std::memcpy(transfer_buffers_.back()->HostAccessibleMemoryPtr(), buf->GetValues<void>(), bytes); diff --git a/tests/cases/compute_one_buffer_in_multiple_bindings.amber b/tests/cases/compute_one_buffer_in_multiple_bindings.amber new file mode 100644 index 0000000..d16bda5 --- /dev/null +++ b/tests/cases/compute_one_buffer_in_multiple_bindings.amber @@ -0,0 +1,94 @@ +#!amber +# Copyright 2021 The Amber Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SHADER compute compute_shader GLSL +#version 430 + +layout(set = 0, binding = 0) uniform uniform_0 { + vec4 uniform_data_0; +}; +layout(set = 0, binding = 1) buffer block_0 { + vec4 storage_data_0; +}; + +layout(set = 1, binding = 0) uniform uniform_1 { + vec4 uniform_data_1; +}; +layout(set = 1, binding = 1) buffer block_1 { + vec4 storage_data_1; +}; + +uniform layout(set = 2, binding = 0, rgba32f) imageBuffer texelBuffer; +uniform layout(set = 2, binding = 1) samplerBuffer texelsIn; + +void main() { + // Verify that the uniform and storage buffers have the same contents and multiply by 2 if true) + if (uniform_data_0 == storage_data_0) { + storage_data_0 = storage_data_0 * 2; + } + if (uniform_data_1 == storage_data_1) { + storage_data_1 = storage_data_1 * 2; + } + + // Load values from index 1 using storage texel buffer. + vec4 texel = imageLoad(texelBuffer, 1); + + // Load values from index 2 using uniform texel buffer. + vec4 color = texelFetch(texelsIn, 2); + + // Store values to index 3. + imageStore(texelBuffer, 3, texel + color); +} +END + +# The Vulkan spec lists the maximum value of minStorageBufferOffsetAlignment +# (i.e. the maximum possible alignment requirement) as 256 bytes. +# Meaningful data is placed at this offset. +BUFFER buf0 DATA_TYPE R32G32B32A32_SFLOAT DATA +1.0 2.0 3.0 4.0 +0.1 0.2 0.3 0.4 +0.5 0.6 0.7 0.8 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 +5.0 6.0 7.0 8.0 +END + +PIPELINE compute pipeline + ATTACH compute_shader + + BIND BUFFER buf0 AS uniform DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 1 + BIND BUFFER buf0 AS uniform DESCRIPTOR_SET 1 BINDING 0 DESCRIPTOR_OFFSET 256 + BIND BUFFER buf0 AS storage DESCRIPTOR_SET 1 BINDING 1 DESCRIPTOR_OFFSET 256 + BIND BUFFER buf0 AS storage_texel_buffer DESCRIPTOR_SET 2 BINDING 0 + BIND BUFFER buf0 AS uniform_texel_buffer DESCRIPTOR_SET 2 BINDING 1 +END + +RUN pipeline 1 1 1 + +EXPECT buf0 IDX 0 EQ 2.0 4.0 6.0 8.0 # Values written to the first storage buffer binding +EXPECT buf0 IDX 48 EQ 0.6 0.8 1.0 1.2 # Values written to the storage texel buffer binding +EXPECT buf0 IDX 256 EQ 10.0 12.0 14.0 16.0 # Values written to the second storage buffer binding diff --git a/tests/cases/debugger_hlsl_basic_compute.amber b/tests/cases/debugger_hlsl_basic_compute.amber index 84db5df..f1572b3 100644 --- a/tests/cases/debugger_hlsl_basic_compute.amber +++ b/tests/cases/debugger_hlsl_basic_compute.amber @@ -18,7 +18,7 @@ SET ENGINE_DATA fence_timeout_ms 1000000 VIRTUAL_FILE "compute.hlsl" [[vk::binding(0)]] -StructuredBuffer<int> data; +RWStructuredBuffer<int> data; [numthreads(1,1,1)] void main() { diff --git a/tests/cases/debugger_hlsl_basic_vertex.amber b/tests/cases/debugger_hlsl_basic_vertex.amber index 86d0381..79ea512 100644 --- a/tests/cases/debugger_hlsl_basic_vertex.amber +++ b/tests/cases/debugger_hlsl_basic_vertex.amber @@ -106,6 +106,12 @@ CLEAR pipeline DEBUG pipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6 THREAD VERTEX_INDEX 0 + EXPECT LOCATION "vs.hlsl" 6 "VS_OUTPUT main(float4 pos : POSITION," + STEP_IN + EXPECT LOCATION "vs.hlsl" 7 " float4 color : COLOR) {" + STEP_IN + EXPECT LOCATION "vs.hlsl" 8 " VS_OUTPUT vout;" + STEP_IN EXPECT LOCATION "vs.hlsl" 9 " vout.pos = pos;" EXPECT LOCAL "pos.x" EQ -1.000000 EXPECT LOCAL "pos.y" EQ -1.000000 diff --git a/tests/cases/debugger_hlsl_function_call.amber b/tests/cases/debugger_hlsl_function_call.amber index 9504b03..3542b15 100644 --- a/tests/cases/debugger_hlsl_function_call.amber +++ b/tests/cases/debugger_hlsl_function_call.amber @@ -18,7 +18,7 @@ SET ENGINE_DATA fence_timeout_ms 1000000 VIRTUAL_FILE "compute.hlsl" [[vk::binding(0)]] -StructuredBuffer<int> data; +RWStructuredBuffer<int> data; int C(int x) { diff --git a/tests/cases/debugger_hlsl_shadowed_vars.amber b/tests/cases/debugger_hlsl_shadowed_vars.amber index bf8a790..d1f75a5 100644 --- a/tests/cases/debugger_hlsl_shadowed_vars.amber +++ b/tests/cases/debugger_hlsl_shadowed_vars.amber @@ -99,7 +99,8 @@ BUFFER framebuffer FORMAT B8G8R8A8_UNORM PIPELINE graphics pipeline ATTACH vtex_shader SHADER_OPTIMIZATION vtex_shader - --legalize-hlsl + --inline-entry-points-exhaustive + --eliminate-dead-functions END ATTACH frag_shader @@ -117,6 +118,10 @@ CLEAR pipeline DEBUG pipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6 THREAD VERTEX_INDEX 0 + EXPECT LOCATION "vs.hlsl" 5 "VS_OUTPUT main(float4 pos : POSITION," + STEP_IN + EXPECT LOCATION "vs.hlsl" 6 " float4 color : COLOR) {" + STEP_IN EXPECT LOCATION "vs.hlsl" 7 " float a = 1.0;" STEP_IN EXPECT LOCATION "vs.hlsl" 8 " float b = 2.0;" diff --git a/tests/cases/debugger_spirv_line_stepping.amber b/tests/cases/debugger_spirv_line_stepping.amber index 1d3e33b..478e4fd 100644 --- a/tests/cases/debugger_spirv_line_stepping.amber +++ b/tests/cases/debugger_spirv_line_stepping.amber @@ -94,10 +94,16 @@ DEBUG pipeline 1 1 1 END EXPECT LOCATION "ComputeShader0.spvasm" 20 "%5 = OpVariable %11 Uniform" STEP_IN + EXPECT LOCATION "ComputeShader0.spvasm" 21 "%12 = OpConstant %9 0" + STEP_IN + EXPECT LOCATION "ComputeShader0.spvasm" 22 "%13 = OpConstant %10 0" + STEP_IN EXPECT LOCATION "ComputeShader0.spvasm" 25 "%2 = OpVariable %15 Input" STEP_IN EXPECT LOCATION "ComputeShader0.spvasm" 27 "%6 = OpVariable %11 Uniform" STEP_IN + EXPECT LOCATION "ComputeShader0.spvasm" 29 "%1 = OpFunction %7 None %8" + STEP_IN EXPECT LOCATION "ComputeShader0.spvasm" 31 "%19 = OpAccessChain %16 %2 %13" STEP_IN EXPECT LOCATION "ComputeShader0.spvasm" 32 "%20 = OpLoad %10 %19" diff --git a/tests/cases/draw_rect_blend.amber b/tests/cases/draw_rect_blend.amber new file mode 100644 index 0000000..c47b93f --- /dev/null +++ b/tests/cases/draw_rect_blend.amber @@ -0,0 +1,46 @@ +#!amber +# Copyright 2021 The Amber Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SHADER vertex vert_shader PASSTHROUGH +SHADER fragment frag_shader GLSL +#version 430 +layout(location = 0) out vec4 color_out; +void main() +{ + color_out = vec4(1.0, 0.0, 0.0, 0.5); +} +END + +BUFFER framebuffer FORMAT B8G8R8A8_UNORM + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + BIND BUFFER framebuffer AS color LOCATION 0 + + BLEND + SRC_COLOR_FACTOR src_alpha + DST_COLOR_FACTOR one_minus_src_alpha + COLOR_OP add + SRC_ALPHA_FACTOR one + DST_ALPHA_FACTOR one + ALPHA_OP max + END +END + +CLEAR_COLOR pipeline 0 255 0 255 +CLEAR pipeline +RUN pipeline DRAW_RECT POS 0 0 SIZE 250 250 +EXPECT framebuffer IDX 0 0 SIZE 250 250 EQ_RGBA 128 128 0 255 TOLERANCE 5% diff --git a/tests/cases/float16.amber b/tests/cases/float16.amber index 88baf13..0a8fd04 100644 --- a/tests/cases/float16.amber +++ b/tests/cases/float16.amber @@ -13,9 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -INSTANCE_EXTENSION VK_KHR_get_physical_device_properties2 DEVICE_EXTENSION VK_KHR_shader_float16_int8 +DEVICE_EXTENSION VK_KHR_16bit_storage +DEVICE_EXTENSION VK_KHR_storage_buffer_storage_class DEVICE_FEATURE Float16Int8Features.shaderFloat16 +DEVICE_FEATURE Storage16BitFeatures.storageBuffer16BitAccess SHADER compute f16 GLSL #version 450 diff --git a/tests/cases/multisample_resolve.amber b/tests/cases/multisample_resolve.amber new file mode 100644 index 0000000..594f9bb --- /dev/null +++ b/tests/cases/multisample_resolve.amber @@ -0,0 +1,50 @@ +#!amber +# Copyright 2021 The Amber Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +DEVICE_FEATURE sampleRateShading + +SHADER vertex vert_shader PASSTHROUGH + +SHADER fragment frag_shader GLSL +#version 440 +layout(location = 0) out vec4 color; + +void main (void) +{ + if (gl_SampleID == 0) + color = vec4(1, 0, 0, 1); + else if (gl_SampleID == 1) + color = vec4(0, 1, 0, 1); + else if (gl_SampleID == 2) + color = vec4(0, 0, 1, 1); + else + color = vec4(1, 1, 1, 1); +} +END + +IMAGE framebuffer_ms FORMAT R8G8B8A8_UNORM DIM_2D WIDTH 64 HEIGHT 64 SAMPLES 4 +IMAGE framebuffer FORMAT R8G8B8A8_UNORM DIM_2D WIDTH 64 HEIGHT 64 + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER framebuffer_ms AS color LOCATION 0 + BIND BUFFER framebuffer AS resolve +END + +RUN pipeline DRAW_RECT POS 0 0 SIZE 64 64 + +EXPECT framebuffer IDX 0 0 SIZE 64 64 EQ_RGBA 128 128 128 255 TOLERANCE 5% diff --git a/tests/cases/tessellation_isolines.amber b/tests/cases/tessellation_isolines.amber new file mode 100644 index 0000000..dd3f298 --- /dev/null +++ b/tests/cases/tessellation_isolines.amber @@ -0,0 +1,130 @@ +#!amber +# Copyright 2021 The Amber Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +DEVICE_FEATURE tessellationShader + +SHADER vertex vert GLSL +#version 450 + +layout (location = 0) in vec3 inPosition; + +void main(void) +{ + gl_Position = vec4(inPosition, 1.0); +} +END + +SHADER tessellation_control tesc GLSL +#version 450 + +layout (vertices = 4) out; + +void main(void) +{ + gl_TessLevelOuter[0] = 6.0; + gl_TessLevelOuter[1] = 2.0; + + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; +} +END + +SHADER tessellation_evaluation tese GLSL +#version 450 + +layout (isolines, equal_spacing, cw) in; + +void main(void) +{ + vec4 p1 = mix(gl_in[0].gl_Position, + gl_in[1].gl_Position, + gl_TessCoord.x); + + vec4 p2 = mix(gl_in[2].gl_Position, + gl_in[3].gl_Position, + gl_TessCoord.x); + + gl_Position = mix(p1, p2, gl_TessCoord.y); +} +END + +SHADER fragment frag GLSL +#version 450 + +layout (location = 0) out vec4 outColor; + +void main(void) +{ + outColor = vec4(1, 0, 0, 1); +} +END + +SHADER compute comp_shader GLSL +#version 450 +layout(local_size_x=10,local_size_y=10) in; +uniform layout(set=0, binding=0, rgba8) image2D resultImage; + +layout(set = 0, binding = 1) buffer block0 +{ + int counter; +}; + +void main() +{ + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + vec4 color = imageLoad(resultImage, uv); + if(color.r > 0.0) atomicAdd(counter, 1); +} +END + +BUFFER vertexPosition DATA_TYPE vec3<float> DATA +-1.0 -1.0 0.0 + 1.0 -1.0 0.0 +-1.0 1.0 0.0 + 1.0 1.0 0.0 +END + +BUFFER counter DATA_TYPE int32 DATA 0 END + +BUFFER framebuffer FORMAT B8G8R8A8_UNORM + +PIPELINE graphics pipeline + ATTACH vert + ATTACH tesc + ATTACH tese + ATTACH frag + + PATCH_CONTROL_POINTS 4 + + FRAMEBUFFER_SIZE 100 100 + VERTEX_DATA vertexPosition LOCATION 0 + BIND BUFFER framebuffer AS color LOCATION 0 +END + +CLEAR_COLOR pipeline 0 0 0 255 +CLEAR pipeline + +RUN pipeline DRAW_ARRAY AS PATCH_LIST START_IDX 0 COUNT 4 + +PIPELINE compute verify_pipeline + ATTACH comp_shader + BIND BUFFER framebuffer AS storage_image DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER counter AS storage DESCRIPTOR_SET 0 BINDING 1 + FRAMEBUFFER_SIZE 100 100 +END + +# Count the number of red pixels as the line position might differ between implementations. +RUN verify_pipeline 10 10 1 + +EXPECT counter IDX 0 TOLERANCE 50 EQ 500 diff --git a/tests/run_tests.py b/tests/run_tests.py index 1fb7eb6..6cd8fc3 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -96,6 +96,8 @@ SUPPRESSIONS_SWIFTSHADER = [ # Unsupported depth/stencil formats "draw_rectangles_depth_test_d24s8.amber", "draw_rectangles_depth_test_x8d24.amber", + # Tessellation not supported + "tessellation_isolines.amber", ] OPENCL_CASES = [ diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 4319556..4668223 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -52,19 +52,30 @@ endif() if (${AMBER_USE_LOCAL_VULKAN}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vulkan-headers) - set(BUILD_TESTS FALSE) - - # The vulkan-loader CMake file assumes that directory exists if - # Wayland support is to be built. - if(NOT EXISTS ${WAYLAND_CLIENT_INCLUDE_DIR}) - message(STATUS "Amber: Disabling Wayland support in Vulkan-Loader") - set(BUILD_WSI_WAYLAND_SUPPORT OFF CACHE BOOL "" FORCE) + # Skip adding the validation layers and the Vulkan loader on Android. + if (NOT ANDROID) + + set(BUILD_TESTS FALSE) + + # The vulkan-loader CMake file assumes that directory exists if + # Wayland support is to be built. + if(NOT EXISTS ${WAYLAND_CLIENT_INCLUDE_DIR}) + message(STATUS "Amber: Disabling Wayland support in Vulkan-Loader") + set(BUILD_WSI_WAYLAND_SUPPORT OFF CACHE BOOL "" FORCE) + endif() + message(STATUS "Amber: Disabling X11 support in Vulkan-Loader") + set(BUILD_WSI_XLIB_SUPPORT OFF CACHE BOOL "" FORCE) + + set(ROBIN_HOOD_HASHING_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/robin-hood-hashing" CACHE STRING "" FORCE) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/robin-hood-hashing) + set(SPIRV_HEADERS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/include" CACHE STRING "" FORCE) + + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vulkan-loader) + if (MSVC) + option(BUILD_WERROR "Treat compiler warnings as errors" OFF) + endif() + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vulkan-validationlayers) endif() - message(STATUS "Amber: Disabling X11 support in Vulkan-Loader") - set(BUILD_WSI_XLIB_SUPPORT OFF CACHE BOOL "" FORCE) - - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vulkan-loader) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vulkan-validationlayers) endif() if (${AMBER_ENABLE_VK_DEBUGGING}) @@ -152,6 +163,8 @@ if (${AMBER_ENABLE_CLSPV}) set(AMBER_CLSPV_LLVM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/clspv-llvm") endif() + list(APPEND CMAKE_MODULE_PATH ${AMBER_CLSPV_LLVM_DIR}/llvm/cmake/modules/) + set(CLSPV_LLVM_SOURCE_DIR "${AMBER_CLSPV_LLVM_DIR}/llvm" CACHE STRING "") set(CLSPV_CLANG_SOURCE_DIR "${AMBER_CLSPV_LLVM_DIR}/clang" CACHE STRING "") set(SPIRV_HEADERS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers" CACHE STRING "") @@ -168,4 +181,8 @@ if (${AMBER_ENABLE_CLSPV}) set(LLVM_INCLUDE_UTILS OFF CACHE BOOL "") add_subdirectory(${AMBER_CLSPV_DIR} ${CMAKE_CURRENT_BINARY_DIR}/clspv) + + # TODO(asuonpaa): Using the latest LLVM gives multiple warnings of using deprecated + # arguments. Remove this when CLSPV doesn't use them. + add_compile_options(clspv, NO_DEPRECATED_FLAGS) endif() diff --git a/tools/roll-all b/tools/roll-all index 97f00c3..48557e8 100755 --- a/tools/roll-all +++ b/tools/roll-all @@ -15,7 +15,6 @@ # Defined to use origin/master instead of origin/main clspv=1 -clspv_llvm=1 cpplint=1 dxc=1 glslang=1 @@ -25,7 +24,6 @@ lodepng=1 spirv_headers=1 spirv_tools=1 swiftshader=1 -vulkan_headers=1 vulkan_loader=1 vulkan_validationlayers=1 |