aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2022-06-27 23:38:19 +0000
committerXin Li <delphij@google.com>2022-06-27 23:38:19 +0000
commitd7d16deb18c42c6ef223dfa2497626e0b0f429bf (patch)
tree7bf7238d34d1cdf3671a43fe4147a53606453504
parentdf4d0b1c5c3a98c8f275d223c14433808f8cbb7e (diff)
parent3f8fbfe46bdb1dd1526687a84c644c1b2846a636 (diff)
downloadamber-d7d16deb18c42c6ef223dfa2497626e0b0f429bf.tar.gz
Merge tm-dev-plus-aosp-without-vendor@8763363temp_sam_242648940
Bug: 236760014 Merged-In: I38ea866610c30c001e4c5580d81fd446a45f2ebb Change-Id: I121e387e7d3b6518a6c9de4ae207fedccf05399a
-rw-r--r--.gitignore5
-rw-r--r--CMakeLists.txt4
-rw-r--r--DEPS35
-rw-r--r--android_gradle/app/build.gradle44
-rw-r--r--android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java2
-rw-r--r--android_gradle/app/src/main/AndroidManifest.xml1
-rw-r--r--android_gradle/app/src/main/java/com/google/amber/Amber.java2
-rw-r--r--android_gradle/build.gradle13
-rw-r--r--android_gradle/gradle.properties2
-rw-r--r--android_gradle/gradle/wrapper/gradle-wrapper.jarbin54329 -> 59203 bytes
-rw-r--r--android_gradle/gradle/wrapper/gradle-wrapper.properties6
-rw-r--r--android_gradle/settings.gradle7
-rw-r--r--docs/amber_script.md142
-rw-r--r--docs/debugger.md6
-rw-r--r--samples/CMakeLists.txt8
-rw-r--r--samples/amber.cc8
-rw-r--r--samples/android_helper.cc (renamed from samples/android_main.cc)18
-rw-r--r--samples/config_helper_vulkan.cc98
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/amberscript/parser.cc237
-rw-r--r--src/amberscript/parser.h3
-rw-r--r--src/amberscript/parser_bind_test.cc384
-rw-r--r--src/amberscript/parser_blend_test.cc140
-rw-r--r--src/amberscript/parser_pipeline_test.cc82
-rw-r--r--src/amberscript/parser_viewport_test.cc388
-rw-r--r--src/buffer.h4
-rw-r--r--src/command.h12
-rw-r--r--src/command_data.cc150
-rw-r--r--src/command_data.h8
-rw-r--r--src/float16_helper.cc22
-rw-r--r--src/pipeline.cc20
-rw-r--r--src/pipeline.h18
-rw-r--r--src/pipeline_data.h27
-rw-r--r--src/pipeline_test.cc10
-rw-r--r--src/script.cc16
-rw-r--r--src/vkscript/command_parser.cc6
-rw-r--r--src/vulkan/CMakeLists.txt9
-rw-r--r--src/vulkan/buffer_backed_descriptor.cc104
-rw-r--r--src/vulkan/buffer_backed_descriptor.h19
-rw-r--r--src/vulkan/buffer_descriptor.cc124
-rw-r--r--src/vulkan/buffer_descriptor.h26
-rw-r--r--src/vulkan/command_buffer.cc1
-rw-r--r--src/vulkan/descriptor.h9
-rw-r--r--src/vulkan/device.cc201
-rw-r--r--src/vulkan/engine_vulkan.cc9
-rw-r--r--src/vulkan/frame_buffer.cc66
-rw-r--r--src/vulkan/frame_buffer.h3
-rw-r--r--src/vulkan/graphics_pipeline.cc52
-rw-r--r--src/vulkan/graphics_pipeline.h4
-rw-r--r--src/vulkan/image_descriptor.cc93
-rw-r--r--src/vulkan/image_descriptor.h13
-rw-r--r--src/vulkan/index_buffer.cc8
-rw-r--r--src/vulkan/pipeline.cc112
-rw-r--r--src/vulkan/pipeline.h13
-rw-r--r--src/vulkan/pipeline_test.cc4
-rw-r--r--src/vulkan/resource.h12
-rw-r--r--src/vulkan/transfer_buffer.cc14
-rw-r--r--src/vulkan/transfer_buffer.h13
-rw-r--r--src/vulkan/transfer_image.cc8
-rw-r--r--src/vulkan/transfer_image.h4
-rw-r--r--src/vulkan/vertex_buffer.cc5
-rw-r--r--tests/cases/compute_descriptor_array_ssbo.amber21
-rw-r--r--tests/cases/compute_descriptor_array_storagetexelbuffer.amber23
-rw-r--r--tests/cases/compute_dynamic_buffers.amber9
-rw-r--r--tests/cases/compute_dynamic_buffers_descriptor_array.amber17
-rw-r--r--tests/cases/compute_one_buffer_in_multiple_bindings.amber94
-rw-r--r--tests/cases/debugger_hlsl_basic_compute.amber2
-rw-r--r--tests/cases/debugger_hlsl_basic_vertex.amber6
-rw-r--r--tests/cases/debugger_hlsl_function_call.amber2
-rw-r--r--tests/cases/debugger_hlsl_shadowed_vars.amber7
-rw-r--r--tests/cases/debugger_spirv_line_stepping.amber6
-rw-r--r--tests/cases/draw_rect_blend.amber46
-rw-r--r--tests/cases/float16.amber4
-rw-r--r--tests/cases/graphics_descriptor_array_combined_image_sampler.amber13
-rw-r--r--tests/cases/graphics_descriptor_array_sampled_image.amber14
-rw-r--r--tests/cases/multisample_resolve.amber50
-rw-r--r--tests/cases/non_default_entry_point.amber2
-rw-r--r--tests/cases/shader_specialization.amber2
-rw-r--r--tests/cases/storage16.amber1
-rw-r--r--tests/cases/tessellation_isolines.amber130
-rw-r--r--tests/cases/viewport.amber59
-rw-r--r--tests/cases/viewport_depth.amber61
-rwxr-xr-xtests/run_tests.py2
-rw-r--r--third_party/CMakeLists.txt41
-rwxr-xr-xtools/roll-all2
85 files changed, 3050 insertions, 424 deletions
diff --git a/.gitignore b/.gitignore
index d5f3eb0..e847034 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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()
diff --git a/DEPS b/DEPS
index ff7507f..1286b6d 100644
--- a/DEPS
+++ b/DEPS
@@ -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
index f6b961f..e708b1c 100644
--- a/android_gradle/gradle/wrapper/gradle-wrapper.jar
+++ b/android_gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
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 57e0632..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.
@@ -485,6 +594,12 @@ The following commands are all specified within the `PIPELINE` command.
```
```groovy
+ # Set the viewport size. If no viewport is provided then it defaults to the
+ # whole framebuffer size. Depth range defaults to 0 to 1.
+ VIEWPORT {x} {y} SIZE {width} {height} [MIN_DEPTH {mind}] [MAX_DEPTH {maxd}]
+```
+
+```groovy
# Set subgroup size control setting. Require that subgroups must be launched
# with all invocations active for given shader. Allow SubgroupSize to vary
# for given shader. Require a specific SubgroupSize the for given shader.
@@ -494,7 +609,7 @@ The following commands are all specified within the `PIPELINE` command.
# and be less than or equal to maxSubgroupSize
# - MIN to set the required subgroup size to the minSubgroupSize
# - MAX to set the required subgroup size to the maxSubgroupSize
- SUBROUP {name_of_shader}
+ SUBGROUP {name_of_shader}
FULLY_POPULATED {fully_populated_enable}
VARYING_SIZE {varying_size_enable}
REQUIRED_SIZE {subgroup_size}
@@ -530,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
@@ -559,13 +679,18 @@ All BIND BUFFER and BIND SAMPLER commands below define a descriptor set and bind
These commands can be replaced with BIND BUFFER_ARRAY and BIND SAMPLER_ARRAY commands.
In these cases multiple buffer or sampler names need to be provided, separated by spaces.
This creates a descriptor array of buffers or samplers bound to the same descriptor set
-and binding ID. An array of offsets should be provided via `OFFSET offset1 offset2 ...`
-when using dynamic buffers with BUFFER_ARRAY.
+and binding ID. An array of dynamic offsets should be provided via `OFFSET offset1 offset2 ...`
+when using dynamic buffers with BUFFER_ARRAY. Optional descriptor binding offset(s) and range(s)
+can be defined via `DESCRIPTOR_OFFSET offset1 offset2 ...` and
+`DESCRIPTOR_RANGE range1 range2 ...` when using uniform or storage buffers. Offsets and
+ranges can be used also with dynamic buffers.
```groovy
# Bind the buffer of the given |buffer_type| at the given descriptor set
- # and binding. The buffer will use a start index of 0.
+ # and binding. The buffer will use a byte offset |descriptor_offset|
+ # with range |range|.
BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {buffer_type} DESCRIPTOR_SET _id_ \
- BINDING _id_
+ BINDING _id_ [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \
+ [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]
# Attach |buffer_name| as a storage image. The MIP level will have a base
# value of |level|.
@@ -586,9 +711,12 @@ when using dynamic buffers with BUFFER_ARRAY.
BIND {SAMPLER | SAMPLER_ARRAY} {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_
# Bind |buffer_name| as dynamic uniform/storage buffer at the given descriptor set
- # and binding. The buffer will use a start index of |offset|.
+ # and binding. The buffer will use a byte offset |offset| + |descriptor_offset|
+ # with range |range|.
BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {uniform_dynamic | storage_dynamic} \
- DESCRIPTOR_SET _id_ BINDING _id_ OFFSET _offset_
+ DESCRIPTOR_SET _id_ BINDING _id_ OFFSET _offset_ \
+ [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \
+ [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]
```
```groovy
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 00e3e54..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,9 +160,11 @@ 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
+ amberscript/parser_viewport_test.cc
buffer_test.cc
command_data_test.cc
descriptor_set_and_binding_parser_test.cc
diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc
index 50760f0..d3e0eb6 100644
--- a/src/amberscript/parser.cc
+++ b/src/amberscript/parser.cc
@@ -602,6 +602,8 @@ Result Parser::ParsePipelineBody(const std::string& cmd_name,
r = ParsePipelineShaderOptimizations(pipeline.get());
} else if (tok == "FRAMEBUFFER_SIZE") {
r = ParsePipelineFramebufferSize(pipeline.get());
+ } else if (tok == "VIEWPORT") {
+ r = ParsePipelineViewport(pipeline.get());
} else if (tok == "BIND") {
r = ParsePipelineBind(pipeline.get());
} else if (tok == "VERTEX_DATA") {
@@ -620,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);
}
@@ -929,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())
@@ -949,6 +969,75 @@ Result Parser::ParsePipelineFramebufferSize(Pipeline* pipeline) {
return ValidateEndOfStatement("FRAMEBUFFER_SIZE command");
}
+Result Parser::ParsePipelineViewport(Pipeline* pipeline) {
+ Viewport vp;
+ vp.mind = 0.0f;
+ vp.maxd = 1.0f;
+
+ float val[2];
+ for (int i = 0; i < 2; i++) {
+ auto token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing offset for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid offset for VIEWPORT command");
+
+ val[i] = token->AsFloat();
+ }
+ vp.x = val[0];
+ vp.y = val[1];
+
+ auto token = tokenizer_->NextToken();
+ if (!token->IsIdentifier() || token->AsString() != "SIZE")
+ return Result("missing SIZE for VIEWPORT command");
+
+ for (int i = 0; i < 2; i++) {
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing size for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid size for VIEWPORT command");
+
+ val[i] = token->AsFloat();
+ }
+ vp.w = val[0];
+ vp.h = val[1];
+
+ token = tokenizer_->PeekNextToken();
+ while (token->IsIdentifier()) {
+ if (token->AsString() == "MIN_DEPTH") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing min_depth for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid min_depth for VIEWPORT command");
+
+ vp.mind = token->AsFloat();
+ }
+ if (token->AsString() == "MAX_DEPTH") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing max_depth for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid max_depth for VIEWPORT command");
+
+ vp.maxd = token->AsFloat();
+ }
+
+ token = tokenizer_->PeekNextToken();
+ }
+
+ pipeline->GetPipelineData()->SetViewport(vp);
+
+ return ValidateEndOfStatement("VIEWPORT command");
+}
+
Result Parser::ToBufferType(const std::string& name, BufferType* type) {
assert(type);
if (name == "color")
@@ -975,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);
@@ -1089,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);
}
}
@@ -1172,10 +1265,60 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) {
}
}
+ // Set default descriptor buffer offsets to 0 and descriptor buffer
+ // ranges to VK_WHOLE_SIZE (~0ULL).
+ std::vector<uint64_t> descriptor_offsets(buffers.size(), 0);
+ std::vector<uint64_t> descriptor_ranges(buffers.size(), ~0ULL);
+ if (buffer_type == BufferType::kUniformDynamic ||
+ buffer_type == BufferType::kStorageDynamic ||
+ buffer_type == BufferType::kStorage ||
+ buffer_type == BufferType::kUniform) {
+ token = tokenizer_->PeekNextToken();
+ if (token->IsIdentifier() &&
+ token->AsString() == "DESCRIPTOR_OFFSET") {
+ token = tokenizer_->NextToken();
+ for (size_t i = 0; i < buffers.size(); i++) {
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger()) {
+ if (i > 0) {
+ return Result(
+ "expecting a DESCRIPTOR_OFFSET value for each buffer in "
+ "the array");
+ } else {
+ return Result(
+ "expecting an integer value for DESCRIPTOR_OFFSET");
+ }
+ }
+ descriptor_offsets[i] = token->AsUint64();
+ }
+ }
+
+ token = tokenizer_->PeekNextToken();
+ if (token->IsIdentifier() &&
+ token->AsString() == "DESCRIPTOR_RANGE") {
+ token = tokenizer_->NextToken();
+ for (size_t i = 0; i < buffers.size(); i++) {
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger()) {
+ if (i > 0) {
+ return Result(
+ "expecting a DESCRIPTOR_RANGE value for each buffer in "
+ "the array");
+ } else {
+ return Result(
+ "expecting an integer value for DESCRIPTOR_RANGE");
+ }
+ }
+ descriptor_ranges[i] = token->AsUint64();
+ }
+ }
+ }
+
pipeline->ClearBuffers(descriptor_set, binding);
for (size_t i = 0; i < buffers.size(); i++) {
pipeline->AddBuffer(buffers[i], buffer_type, descriptor_set, binding,
- base_mip_level, dynamic_offsets[i]);
+ base_mip_level, dynamic_offsets[i],
+ descriptor_offsets[i], descriptor_ranges[i]);
}
} else if (token->IsIdentifier() && token->AsString() == "KERNEL") {
token = tokenizer_->NextToken();
@@ -1722,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 e8cb835..25d3493 100644
--- a/src/amberscript/parser.h
+++ b/src/amberscript/parser.h
@@ -64,7 +64,9 @@ 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*);
Result ParsePipelineVertexData(Pipeline*);
Result ParsePipelineIndexData(Pipeline*);
@@ -72,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 64f3948..8aac5e5 100644
--- a/src/amberscript/parser_bind_test.cc
+++ b/src/amberscript/parser_bind_test.cc
@@ -1393,11 +1393,53 @@ END
EXPECT_EQ(BufferType::kUniform, bufs[0].type);
EXPECT_EQ(1U, bufs[0].descriptor_set);
EXPECT_EQ(2U, bufs[0].binding);
+ EXPECT_EQ(0U, bufs[0].descriptor_offset);
+ EXPECT_EQ(~0ULL, bufs[0].descriptor_range);
EXPECT_EQ(static_cast<uint32_t>(0), bufs[0].location);
EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
bufs[0].buffer->GetFormat()->GetFormatType());
}
+TEST_F(AmberScriptParserTest, BindBufferDescriptorOffsetAndRange) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_OFFSET 256 DESCRIPTOR_RANGE 512
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 3 DESCRIPTOR_OFFSET 256 DESCRIPTOR_RANGE -1
+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& bufs = pipeline->GetBuffers();
+ ASSERT_EQ(2U, bufs.size());
+ EXPECT_EQ(BufferType::kUniform, bufs[0].type);
+ EXPECT_EQ(1U, bufs[0].descriptor_set);
+ EXPECT_EQ(2U, bufs[0].binding);
+ EXPECT_EQ(256U, bufs[0].descriptor_offset);
+ EXPECT_EQ(512U, bufs[0].descriptor_range);
+ EXPECT_EQ(static_cast<uint32_t>(0), bufs[0].location);
+ EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
+ bufs[0].buffer->GetFormat()->GetFormatType());
+ // Verify the descriptor range from the second buffer.
+ EXPECT_EQ(~0ULL, bufs[1].descriptor_range);
+}
+
TEST_F(AmberScriptParserTest, BindBufferMissingBindingValue) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
@@ -2859,6 +2901,33 @@ END)";
EXPECT_EQ("13: missing BINDING for BIND command", r.Error());
}
+TEST_F(AmberScriptParserTest, BindDescriptorOffsetWithUnsupportedBufferType) {
+ std::string unsupported_buffer_types[] = {"uniform_texel_buffer",
+ "storage_texel_buffer",
+ "sampled_image", "storage_image"};
+
+ for (const auto& buffer_type : unsupported_buffer_types) {
+ std::ostringstream in;
+ in << R"(
+SHADER compute compute_shader GLSL
+# GLSL Shader
+END
+
+BUFFER texture FORMAT R8G8B8A8_UNORM
+
+PIPELINE compute pipeline
+ ATTACH compute_shader
+ BIND BUFFER texture AS )"
+ << buffer_type << R"( DESCRIPTOR_SET 0 BINDING 0 DESCRIPTOR_OFFSET 0
+END)";
+ Parser parser;
+ Result r = parser.Parse(in.str());
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("10: extra parameters after BIND command: DESCRIPTOR_OFFSET",
+ r.Error());
+ }
+}
+
TEST_F(AmberScriptParserTest, BindBufferArray) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
@@ -2891,12 +2960,200 @@ END
EXPECT_EQ(BufferType::kUniform, bufs[i].type);
EXPECT_EQ(1U, bufs[i].descriptor_set);
EXPECT_EQ(2U, bufs[i].binding);
+ EXPECT_EQ(0U, bufs[i].descriptor_offset);
+ EXPECT_EQ(~0ULL, bufs[i].descriptor_range);
EXPECT_EQ(static_cast<uint32_t>(0), bufs[i].location);
EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
bufs[i].buffer->GetFormat()->GetFormatType());
}
}
+TEST_F(AmberScriptParserTest, BindBufferArrayWithDescriptorOffsetAndRange) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_buf1 FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER_ARRAY my_buf1 my_buf1 AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_OFFSET 256 512 DESCRIPTOR_RANGE 1024 2048
+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& bufs = pipeline->GetBuffers();
+ ASSERT_EQ(2U, bufs.size());
+ for (size_t i = 0; i < 2; i++) {
+ EXPECT_EQ(BufferType::kUniform, bufs[i].type);
+ EXPECT_EQ(1U, bufs[i].descriptor_set);
+ EXPECT_EQ(2U, bufs[i].binding);
+ EXPECT_EQ(256U * (i + 1), bufs[i].descriptor_offset);
+ EXPECT_EQ(1024U * (i + 1), bufs[i].descriptor_range);
+ EXPECT_EQ(static_cast<uint32_t>(0), bufs[i].location);
+ EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
+ bufs[i].buffer->GetFormat()->GetFormatType());
+ }
+}
+
+TEST_F(AmberScriptParserTest,
+ BindDynamicBufferArrayWithDescriptorOffsetAndRange) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_buf1 FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER_ARRAY my_buf1 my_buf1 AS uniform_dynamic DESCRIPTOR_SET 1 BINDING 2 OFFSET 16 32 DESCRIPTOR_OFFSET 256 512 DESCRIPTOR_RANGE 1024 2048
+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& bufs = pipeline->GetBuffers();
+ ASSERT_EQ(2U, bufs.size());
+ for (size_t i = 0; i < 2; i++) {
+ EXPECT_EQ(BufferType::kUniformDynamic, bufs[i].type);
+ EXPECT_EQ(1U, bufs[i].descriptor_set);
+ EXPECT_EQ(2U, bufs[i].binding);
+ EXPECT_EQ(16U * (i + 1), bufs[i].dynamic_offset);
+ EXPECT_EQ(256U * (i + 1), bufs[i].descriptor_offset);
+ EXPECT_EQ(1024U * (i + 1), bufs[i].descriptor_range);
+ EXPECT_EQ(static_cast<uint32_t>(0), bufs[i].location);
+ EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
+ bufs[i].buffer->GetFormat()->GetFormatType());
+ }
+}
+
+TEST_F(AmberScriptParserTest, BindBufferArrayOnlyOneDescriptorOffset) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER_ARRAY my_buf my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_OFFSET 256
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ(
+ "13: expecting a DESCRIPTOR_OFFSET value for each buffer in the array",
+ r.Error());
+}
+
+TEST_F(AmberScriptParserTest, BindBufferArrayOnlyOneDescriptorRange) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER_ARRAY my_buf my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_RANGE 256
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ(
+ "13: expecting a DESCRIPTOR_RANGE value for each buffer in the array",
+ r.Error());
+}
+
+TEST_F(AmberScriptParserTest, BindUniformBufferEmptyDescriptorOffset) {
+ std::string in = R"(
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+PIPELINE graphics my_pipeline
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_OFFSET
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("5: expecting an integer value for DESCRIPTOR_OFFSET", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, BindUniformBufferInvalidDescriptorOffset) {
+ std::string in = R"(
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+PIPELINE graphics my_pipeline
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_OFFSET foo
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("4: expecting an integer value for DESCRIPTOR_OFFSET", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, BindUniformBufferEmptyDescriptorRange) {
+ std::string in = R"(
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+PIPELINE graphics my_pipeline
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_RANGE
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("5: expecting an integer value for DESCRIPTOR_RANGE", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, BindUniformBufferInvalidDescriptorRange) {
+ std::string in = R"(
+BUFFER my_buf FORMAT R32G32B32A32_SFLOAT
+PIPELINE graphics my_pipeline
+ BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 DESCRIPTOR_RANGE foo
+END
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("4: expecting an integer value for DESCRIPTOR_RANGE", r.Error());
+}
+
TEST_F(AmberScriptParserTest, BindBufferArrayOnlyOneBuffer) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
@@ -3251,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/amberscript/parser_viewport_test.cc b/src/amberscript/parser_viewport_test.cc
new file mode 100644
index 0000000..ec19fb2
--- /dev/null
+++ b/src/amberscript/parser_viewport_test.cc
@@ -0,0 +1,388 @@
+// 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, NoViewport) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+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_FALSE(pipeline->GetPipelineData()->HasViewportData());
+}
+
+TEST_F(AmberScriptParserTest, ViewportNoDepth) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 5.0 7.0 SIZE 10.0 12.0
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(5.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(7.0f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(10.0f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(12.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMinDepth) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 12.2 9.7 SIZE 0.5 106.1 MIN_DEPTH 0.3
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(12.2f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(9.7f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(106.1f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.3f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMaxDepth) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 12.2 9.7 SIZE 0.5 106.1 MAX_DEPTH 0.456
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(12.2f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(9.7f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(106.1f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(0.456f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportAllValues) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT -0.6 5.2 SIZE 13.8 9.4 MIN_DEPTH 0.5 MAX_DEPTH 0.6
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(-0.6f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(5.2f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(13.8f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(9.4f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(0.6f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportIntegers) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT -2 7 SIZE 15 20 MIN_DEPTH 1 MAX_DEPTH 2
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(-2.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(7.0f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(15.0f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(20.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(2.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMixedIntegers) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT -2 13.1 SIZE 15.9 20
+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()->HasViewportData());
+ ASSERT_FLOAT_EQ(-2.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(13.1f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(15.9f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(20.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingSize) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 0.0 2.0 12.0 24.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: missing SIZE for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidSizeNotOptional) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 0.0 2.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("16: missing SIZE for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingOffset) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 0.0 SIZE 12.0 24.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: invalid offset for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingSizeValue) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 0.0 2.0 SIZE 12.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("16: missing size for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingDepthValue) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+ BIND BUFFER my_fb AS color LOCATION 0
+ BIND BUFFER my_ds AS depth_stencil
+
+ VIEWPORT 0.0 2.0 SIZE 12.0 24.0 MIN_DEPTH MAX_DEPTH 1.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: invalid min_depth for VIEWPORT command", r.Error());
+}
+
+} // 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.h b/src/command.h
index 207c336..26b9dc2 100644
--- a/src/command.h
+++ b/src/command.h
@@ -546,6 +546,16 @@ class BufferCommand : public BindableResourceCommand {
}
uint32_t GetDynamicOffset() const { return dynamic_offset_; }
+ void SetDescriptorOffset(uint64_t descriptor_offset) {
+ descriptor_offset_ = descriptor_offset;
+ }
+ uint64_t GetDescriptorOffset() const { return descriptor_offset_; }
+
+ void SetDescriptorRange(uint64_t descriptor_range) {
+ descriptor_range_ = descriptor_range;
+ }
+ uint64_t GetDescriptorRange() const { return descriptor_range_; }
+
void SetValues(std::vector<Value>&& values) { values_ = std::move(values); }
const std::vector<Value>& GetValues() const { return values_; }
@@ -565,6 +575,8 @@ class BufferCommand : public BindableResourceCommand {
uint32_t offset_ = 0;
uint32_t base_mip_level_ = 0;
uint32_t dynamic_offset_ = 0;
+ uint64_t descriptor_offset_ = 0;
+ uint64_t descriptor_range_ = ~0ULL;
std::vector<Value> values_;
};
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/float16_helper.cc b/src/float16_helper.cc
index 617bd72..5cb35e7 100644
--- a/src/float16_helper.cc
+++ b/src/float16_helper.cc
@@ -15,6 +15,7 @@
#include "src/float16_helper.h"
#include <cassert>
+#include <cstring>
// Float10
// | 9 8 7 6 5 | 4 3 2 1 0 |
@@ -75,8 +76,11 @@ float HexFloat16ToFloat(const uint8_t* value) {
}
uint32_t hex = sign | exponent | mantissa;
- float* hex_float = reinterpret_cast<float*>(&hex);
- return *hex_float;
+ float hex_float;
+ static_assert((sizeof(uint32_t) == sizeof(float)),
+ "sizeof(uint32_t) != sizeof(float)");
+ memcpy(&hex_float, &hex, sizeof(float));
+ return hex_float;
}
// Convert float |value| whose size is 11 bits to 32 bits float
@@ -89,8 +93,11 @@ float HexFloat11ToFloat(const uint8_t* value) {
uint32_t mantissa = (static_cast<uint32_t>(value[0]) & 0x3f) << 17U;
uint32_t hex = exponent | mantissa;
- float* hex_float = reinterpret_cast<float*>(&hex);
- return *hex_float;
+ float hex_float;
+ static_assert((sizeof(uint32_t) == sizeof(float)),
+ "sizeof(uint32_t) != sizeof(float)");
+ memcpy(&hex_float, &hex, sizeof(float));
+ return hex_float;
}
// Convert float |value| whose size is 10 bits to 32 bits float
@@ -103,8 +110,11 @@ float HexFloat10ToFloat(const uint8_t* value) {
uint32_t mantissa = (static_cast<uint32_t>(value[0]) & 0x1f) << 18U;
uint32_t hex = exponent | mantissa;
- float* hex_float = reinterpret_cast<float*>(&hex);
- return *hex_float;
+ float hex_float;
+ static_assert((sizeof(uint32_t) == sizeof(float)),
+ "sizeof(uint32_t) != sizeof(float)");
+ memcpy(&hex_float, &hex, sizeof(float));
+ return hex_float;
}
} // namespace
diff --git a/src/pipeline.cc b/src/pipeline.cc
index 55c6bae..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_) {
@@ -516,7 +528,9 @@ void Pipeline::AddBuffer(Buffer* buf,
uint32_t descriptor_set,
uint32_t binding,
uint32_t base_mip_level,
- uint32_t dynamic_offset) {
+ uint32_t dynamic_offset,
+ uint64_t descriptor_offset,
+ uint64_t descriptor_range) {
buffers_.push_back(BufferInfo{buf});
auto& info = buffers_.back();
@@ -526,6 +540,8 @@ void Pipeline::AddBuffer(Buffer* buf,
info.base_mip_level = base_mip_level;
info.dynamic_offset = dynamic_offset;
info.sampler = buf->GetSampler();
+ info.descriptor_offset = descriptor_offset;
+ info.descriptor_range = descriptor_range;
}
void Pipeline::AddBuffer(Buffer* buf,
@@ -862,7 +878,7 @@ Result Pipeline::GenerateOpenCLPodBuffers() {
opencl_pod_buffer_map_.insert(
buf_iter,
std::make_pair(std::make_pair(descriptor_set, binding), buffer));
- AddBuffer(buffer, buffer_type, descriptor_set, binding, 0, 0);
+ AddBuffer(buffer, buffer_type, descriptor_set, binding, 0, 0, 0, ~0ULL);
} else {
buffer = buf_iter->second;
}
diff --git a/src/pipeline.h b/src/pipeline.h
index ec38a3a..9010c59 100644
--- a/src/pipeline.h
+++ b/src/pipeline.h
@@ -203,6 +203,8 @@ class Pipeline {
uint32_t offset = 0;
uint32_t stride = 0;
Sampler* sampler = nullptr;
+ uint64_t descriptor_offset = 0;
+ uint64_t descriptor_range = ~0ULL; // ~0ULL == VK_WHOLE_SIZE
};
/// Information on a sampler attached to the pipeline.
@@ -301,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
@@ -335,13 +345,16 @@ class Pipeline {
Buffer* GetIndexBuffer() const { return index_buffer_; }
/// Adds |buf| of |type| to the pipeline at the given |descriptor_set|,
- /// |binding|, |base_mip_level|, and |dynamic_offset|.
+ /// |binding|, |base_mip_level|, |descriptor_offset|, |descriptor_range| and
+ /// |dynamic_offset|.
void AddBuffer(Buffer* buf,
BufferType type,
uint32_t descriptor_set,
uint32_t binding,
uint32_t base_mip_level,
- uint32_t dynamic_offset);
+ uint32_t dynamic_offset,
+ uint64_t descriptor_offset,
+ uint64_t descriptor_range);
/// Adds |buf| to the pipeline at the given |arg_name|.
void AddBuffer(Buffer* buf, BufferType type, const std::string& arg_name);
/// Adds |buf| to the pipeline at the given |arg_no|.
@@ -431,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 dc67c03..c763f37 100644
--- a/src/pipeline_data.h
+++ b/src/pipeline_data.h
@@ -21,6 +21,15 @@
namespace amber {
+struct Viewport {
+ float x;
+ float y;
+ float w;
+ float h;
+ float mind;
+ float maxd;
+};
+
/// Stores information used to configure a pipeline.
class PipelineData {
public:
@@ -161,6 +170,19 @@ class PipelineData {
void SetAlphaBlendOp(BlendOp op) { alpha_blend_op_ = op; }
BlendOp GetAlphaBlendOp() const { return alpha_blend_op_; }
+ void SetViewport(const Viewport& v) {
+ has_viewport_data = true;
+ vp = v;
+ }
+
+ 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;
@@ -213,6 +235,11 @@ class PipelineData {
float depth_bias_slope_factor_ = 0.0f;
float min_depth_bounds_ = 0.0f;
float max_depth_bounds_ = 0.0f;
+
+ bool has_viewport_data = false;
+ Viewport vp;
+
+ uint32_t patch_control_points_ = 3u;
};
} // namespace amber
diff --git a/src/pipeline_test.cc b/src/pipeline_test.cc
index e16313c..c0d2f67 100644
--- a/src/pipeline_test.cc
+++ b/src/pipeline_test.cc
@@ -262,7 +262,7 @@ TEST_F(PipelineTest, PipelineBufferWithoutFormat) {
auto buf = MakeUnique<Buffer>();
buf->SetName("MyBuffer");
- p.AddBuffer(buf.get(), BufferType::kStorage, 0, 0, 0, 0);
+ p.AddBuffer(buf.get(), BufferType::kStorage, 0, 0, 0, 0, 0, 0);
Result r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
@@ -365,11 +365,11 @@ TEST_F(PipelineTest, Clone) {
auto buf1 = MakeUnique<Buffer>();
buf1->SetName("buf1");
- p.AddBuffer(buf1.get(), BufferType::kStorage, 1, 1, 0, 0);
+ p.AddBuffer(buf1.get(), BufferType::kStorage, 1, 1, 0, 0, 0, 0);
auto buf2 = MakeUnique<Buffer>();
buf2->SetName("buf2");
- p.AddBuffer(buf2.get(), BufferType::kStorage, 1, 2, 0, 16);
+ p.AddBuffer(buf2.get(), BufferType::kStorage, 1, 2, 0, 16, 256, 512);
auto clone = p.Clone();
EXPECT_EQ("", clone->GetName());
@@ -400,11 +400,15 @@ TEST_F(PipelineTest, Clone) {
EXPECT_EQ(1U, bufs[0].descriptor_set);
EXPECT_EQ(1U, bufs[0].binding);
EXPECT_EQ(0U, bufs[0].dynamic_offset);
+ EXPECT_EQ(0U, bufs[0].descriptor_offset);
+ EXPECT_EQ(0U, bufs[0].descriptor_range);
EXPECT_EQ("buf2", bufs[1].buffer->GetName());
EXPECT_EQ(1U, bufs[1].descriptor_set);
EXPECT_EQ(2U, bufs[1].binding);
EXPECT_EQ(16U, bufs[1].dynamic_offset);
+ EXPECT_EQ(256U, bufs[1].descriptor_offset);
+ EXPECT_EQ(512U, bufs[1].descriptor_range);
}
TEST_F(PipelineTest, OpenCLUpdateBindings) {
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/vkscript/command_parser.cc b/src/vkscript/command_parser.cc
index 0953344..610c7e6 100644
--- a/src/vkscript/command_parser.cc
+++ b/src/vkscript/command_parser.cc
@@ -577,7 +577,8 @@ Result CommandParser::ProcessSSBO() {
buffer = b.get();
script_->AddBuffer(std::move(b));
pipeline_->ClearBuffers(set, binding);
- pipeline_->AddBuffer(buffer, BufferType::kStorage, set, binding, 0, 0);
+ pipeline_->AddBuffer(buffer, BufferType::kStorage, set, binding, 0, 0, 0,
+ ~0ULL);
}
cmd->SetBuffer(buffer);
}
@@ -729,7 +730,8 @@ Result CommandParser::ProcessUniform() {
buffer = b.get();
script_->AddBuffer(std::move(b));
pipeline_->ClearBuffers(set, binding);
- pipeline_->AddBuffer(buffer, BufferType::kUniform, set, binding, 0, 0);
+ pipeline_->AddBuffer(buffer, BufferType::kUniform, set, binding, 0, 0, 0,
+ ~0ULL);
}
cmd->SetBuffer(buffer);
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 2f7aa98..a2e874d 100644
--- a/src/vulkan/buffer_backed_descriptor.cc
+++ b/src/vulkan/buffer_backed_descriptor.cc
@@ -26,92 +26,64 @@ 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) {
- auto resources = GetResources();
- auto buffers = GetAmberBuffers();
- if (resources.size() != buffers.size())
- return Result(
- "Vulkan: BufferBackedDescriptor::RecordCopyDataToResourceIfNeeded() "
- "resource and buffer vector sizes are not matching");
-
- for (size_t i = 0; i < resources.size(); i++) {
- if (!buffers[i]->ValuePtr()->empty()) {
- resources[i]->UpdateMemoryWithRawData(*buffers[i]->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())
- buffers[i]->ValuePtr()->clear();
- }
-
- resources[i]->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->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();
- auto buffers = GetAmberBuffers();
- if (resources.size() != buffers.size())
+ void* resource_memory_ptr = transfer_resource->HostAccessibleMemoryPtr();
+ if (!resource_memory_ptr) {
return Result(
- "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() resource "
- "and buffer vector sizes are not matching");
+ "Vulkan: BufferBackedDescriptor::MoveTransferResourceToBufferOutput() "
+ "no host accessible memory pointer");
+ }
- if (resources.empty()) {
+ if (!buffer->ValuePtr()->empty()) {
return Result(
- "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() no "
- "transfer resource");
+ "Vulkan: BufferBackedDescriptor::MoveTransferResourceToBufferOutput() "
+ "output buffer is not empty");
}
- for (size_t i = 0; i < resources.size(); i++) {
- void* resource_memory_ptr = resources[i]->HostAccessibleMemoryPtr();
- if (!resource_memory_ptr) {
- return Result(
- "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() "
- "no host accessible memory pointer");
- }
-
- if (!buffers[i]->ValuePtr()->empty()) {
- return Result(
- "Vulkan: BufferBackedDescriptor::MoveResourceToBufferOutput() "
- "output buffer is not empty");
- }
-
- auto size_in_bytes = resources[i]->GetSizeInBytes();
- buffers[i]->SetElementCount(size_in_bytes /
- buffers[i]->GetFormat()->SizeInBytes());
- buffers[i]->ValuePtr()->resize(size_in_bytes);
- std::memcpy(buffers[i]->ValuePtr()->data(), resource_memory_ptr,
- size_in_bytes);
- }
+ 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 c626dd8..8a2d0a5 100644
--- a/src/vulkan/buffer_backed_descriptor.h
+++ b/src/vulkan/buffer_backed_descriptor.h
@@ -16,6 +16,7 @@
#define SRC_VULKAN_BUFFER_BACKED_DESCRIPTOR_H_
#include <memory>
+#include <utility>
#include <vector>
#include "amber/result.h"
@@ -24,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 {
@@ -35,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());
}
@@ -51,7 +59,8 @@ class BufferBackedDescriptor : public Descriptor {
bool IsReadOnly() const;
protected:
- virtual std::vector<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 510565d..d60ce08 100644
--- a/src/vulkan/buffer_descriptor.cc
+++ b/src/vulkan/buffer_descriptor.cc
@@ -14,6 +14,8 @@
#include "src/vulkan/buffer_descriptor.h"
+#include <algorithm>
+#include <utility>
#include <vector>
#include "src/make_unique.h"
@@ -27,58 +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");
}
- transfer_buffers_.reserve(GetAmberBuffers().size());
-
for (const auto& amber_buffer : GetAmberBuffers()) {
- if (amber_buffer->ValuePtr()->empty())
- continue;
-
- uint32_t size_in_bytes =
- amber_buffer ? static_cast<uint32_t>(amber_buffer->ValuePtr()->size())
- : 0;
- transfer_buffers_.emplace_back(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_buffers_.back()->Initialize(flags);
+ // Update the buffer create flags.
+ Result r =
+ transfer_resources[amber_buffer]->AsTransferBuffer()->AddUsageFlags(
+ flags);
if (!r.IsSuccess())
return r;
}
-
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(
@@ -89,12 +96,35 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded(
std::vector<VkDescriptorBufferInfo> buffer_infos;
std::vector<VkBufferView> buffer_views;
- for (const auto& buffer : transfer_buffers_) {
- VkDescriptorBufferInfo buffer_info;
- buffer_info.buffer = buffer->GetVkBuffer();
- buffer_info.offset = 0;
- buffer_info.range = VK_WHOLE_SIZE;
- buffer_infos.push_back(buffer_info);
+ // Create VkDescriptorBufferInfo for every descriptor buffer.
+ for (uint32_t i = 0; i < GetAmberBuffers().size(); 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() ||
+ IsStorageBufferDynamic()) {
+ uint64_t range = descriptor_ranges_[i];
+ // If dynamic offset is used, we must change range with VK_WHOLE_SIZE to
+ // an actual range.
+ // From vulkan spec: For each dynamic uniform or storage buffer binding in
+ // pDescriptorSets, the sum of the effective offset, as defined above, and
+ // the range of the binding must be less than or equal to the size of the
+ // buffer.
+ if ((IsUniformBufferDynamic() || IsStorageBufferDynamic()) &&
+ descriptor_ranges_[i] == VK_WHOLE_SIZE) {
+ range = buffer->GetSizeInBytes() - dynamic_offsets_[i] -
+ descriptor_offsets_[i];
+ }
+
+ VkDescriptorBufferInfo buffer_info;
+ buffer_info.buffer = buffer->GetVkBuffer();
+ buffer_info.offset = descriptor_offsets_[i];
+ buffer_info.range = range;
+
+ buffer_infos.push_back(buffer_info);
+ }
if (IsUniformTexelBuffer() || IsStorageTexelBuffer()) {
buffer_views.push_back(*buffer->GetVkBufferView());
@@ -106,7 +136,7 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded(
write.dstSet = descriptor_set;
write.dstBinding = binding_;
write.dstArrayElement = 0;
- write.descriptorCount = static_cast<uint32_t>(buffer_infos.size());
+ write.descriptorCount = static_cast<uint32_t>(GetAmberBuffers().size());
write.descriptorType = GetVkDescriptorType();
write.pBufferInfo = buffer_infos.data();
write.pTexelBufferView = buffer_views.data();
@@ -116,13 +146,5 @@ void BufferDescriptor::UpdateDescriptorSetIfNeeded(
is_descriptor_set_update_needed_ = false;
}
-std::vector<Resource*> BufferDescriptor::GetResources() {
- std::vector<Resource*> ret;
- for (auto& b : transfer_buffers_) {
- ret.push_back(b.get());
- }
- return ret;
-}
-
} // namespace vulkan
} // namespace amber
diff --git a/src/vulkan/buffer_descriptor.h b/src/vulkan/buffer_descriptor.h
index d481ae5..439afa5 100644
--- a/src/vulkan/buffer_descriptor.h
+++ b/src/vulkan/buffer_descriptor.h
@@ -16,6 +16,8 @@
#define SRC_VULKAN_BUFFER_DESCRIPTOR_H_
#include <memory>
+#include <unordered_map>
+#include <utility>
#include <vector>
#include "amber/result.h"
@@ -24,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 {
@@ -40,24 +43,35 @@ 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_;
}
void AddDynamicOffset(uint32_t offset) { dynamic_offsets_.push_back(offset); }
- BufferDescriptor* AsBufferDescriptor() override { return this; }
+ std::vector<uint64_t> GetDescriptorOffsets() override {
+ return descriptor_offsets_;
+ }
+ void AddDescriptorOffset(uint64_t descriptor_offset) {
+ descriptor_offsets_.push_back(descriptor_offset);
+ }
+ std::vector<uint64_t> GetDescriptorRanges() override {
+ return descriptor_ranges_;
+ }
+ void AddDescriptorRange(uint64_t descriptor_range) {
+ descriptor_ranges_.push_back(descriptor_range);
+ }
- protected:
- std::vector<Resource*> GetResources() override;
+ BufferDescriptor* AsBufferDescriptor() override { return this; }
private:
- std::vector<std::unique_ptr<TransferBuffer>> transfer_buffers_;
std::vector<uint32_t> dynamic_offsets_;
+ std::vector<VkDeviceSize> descriptor_offsets_;
+ std::vector<VkDeviceSize> descriptor_ranges_;
};
} // namespace vulkan
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 ba702ff..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,14 +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 536993f..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(),
@@ -254,6 +257,8 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) {
cmd->SetBinding(buf_info.binding);
cmd->SetBaseMipLevel(buf_info.base_mip_level);
cmd->SetDynamicOffset(buf_info.dynamic_offset);
+ cmd->SetDescriptorOffset(buf_info.descriptor_offset);
+ cmd->SetDescriptorRange(buf_info.descriptor_range);
cmd->SetBuffer(buf_info.buffer);
cmd->SetSampler(buf_info.sampler);
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 b83bea1..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 =
@@ -579,6 +606,16 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline(
0, 0, static_cast<float>(frame_width_), static_cast<float>(frame_height_),
0, 1};
+ if (pipeline_data->HasViewportData()) {
+ Viewport vp = pipeline_data->GetViewport();
+ viewport.x = vp.x;
+ viewport.y = vp.y;
+ viewport.width = vp.w;
+ viewport.height = vp.h;
+ viewport.minDepth = vp.mind;
+ viewport.maxDepth = vp.maxd;
+ }
+
VkRect2D scissor = {{0, 0}, {frame_width_, frame_height_}};
VkPipelineViewportStateCreateInfo viewport_info =
@@ -611,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());
@@ -694,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 550ce0b..1d20244 100644
--- a/src/vulkan/image_descriptor.cc
+++ b/src/vulkan/image_descriptor.cc
@@ -14,6 +14,10 @@
#include "src/vulkan/image_descriptor.h"
+#include <algorithm>
+#include <unordered_map>
+#include <utility>
+
#include "src/vulkan/device.h"
#include "src/vulkan/resource.h"
@@ -25,46 +29,26 @@ 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) {
- for (auto& image : transfer_images_) {
- image->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 (auto& image : transfer_images_) {
- image->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");
- }
-
- transfer_images_.reserve(GetAmberBuffers().size());
+ 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_resources.count(amber_buffer) > 0) {
+ continue;
+ }
+
// Default to 2D image.
VkImageType image_type = VK_IMAGE_TYPE_2D;
switch (amber_buffer->GetImageDimension()) {
@@ -93,14 +77,8 @@ Result ImageDescriptor::CreateResourceIfNeeded() {
aspect = VK_IMAGE_ASPECT_COLOR_BIT;
}
- transfer_images_.emplace_back(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 {
@@ -109,10 +87,14 @@ Result ImageDescriptor::CreateResourceIfNeeded() {
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
}
- Result r = transfer_images_.back()->Initialize(usage);
+ 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());
- if (!r.IsSuccess())
- return r;
+ // Store the transfer image to the pipeline's map of transfer images.
+ transfer_resources[amber_buffer] = std::move(transfer_image);
}
if (amber_sampler_) {
@@ -125,27 +107,6 @@ Result ImageDescriptor::CreateResourceIfNeeded() {
return {};
}
-Result ImageDescriptor::RecordCopyDataToHost(CommandBuffer* command) {
- if (!IsReadOnly()) {
- for (auto& image : transfer_images_) {
- image->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_)
@@ -156,7 +117,11 @@ void ImageDescriptor::UpdateDescriptorSetIfNeeded(
std::vector<VkDescriptorImageInfo> image_infos;
- for (const auto& image : transfer_images_) {
+ // Create VkDescriptorImageInfo for every descriptor image.
+ for (const auto& amber_buffer : GetAmberBuffers()) {
+ const auto& image =
+ pipeline_->GetDescriptorTransferResources()[amber_buffer]
+ ->AsTransferImage();
VkDescriptorImageInfo image_info = {vulkan_sampler_.GetVkSampler(),
image->GetVkImageView(), layout};
image_infos.push_back(image_info);
@@ -177,13 +142,5 @@ void ImageDescriptor::UpdateDescriptorSetIfNeeded(
is_descriptor_set_update_needed_ = false;
}
-std::vector<Resource*> ImageDescriptor::GetResources() {
- std::vector<Resource*> ret;
- for (auto& i : transfer_images_) {
- ret.push_back(i.get());
- }
- return ret;
-}
-
} // namespace vulkan
} // namespace amber
diff --git a/src/vulkan/image_descriptor.h b/src/vulkan/image_descriptor.h
index 5f8dd0e..3046436 100644
--- a/src/vulkan/image_descriptor.h
+++ b/src/vulkan/image_descriptor.h
@@ -16,9 +16,12 @@
#define SRC_VULKAN_IMAGE_DESCRIPTOR_H_
#include <memory>
+#include <unordered_map>
+#include <utility>
#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"
@@ -32,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<Resource*> GetResources() override;
+ ImageDescriptor* AsImageDescriptor() override { return this; }
private:
uint32_t base_mip_level_ = 0;
- std::vector<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 e0b875c..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,16 +331,18 @@ 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());
+
descriptors.push_back(std::move(image_desc));
} 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) {
@@ -336,18 +350,19 @@ Result Pipeline::AddBufferDescriptor(const BufferCommand* cmd) {
"Descriptors bound to the same binding needs to have matching "
"descriptor types");
}
- // Check that the buffer is not added already.
- const auto& buffers = desc->AsBufferBackedDescriptor()->GetAmberBuffers();
- if (std::find(buffers.begin(), buffers.end(), cmd->GetBuffer()) !=
- buffers.end()) {
- return Result("Buffer has been added already");
- }
desc->AsBufferBackedDescriptor()->AddAmberBuffer(cmd->GetBuffer());
+ AddDescriptorBuffer(cmd->GetBuffer());
}
if (cmd->IsUniformDynamic() || cmd->IsSSBODynamic())
desc->AsBufferDescriptor()->AddDynamicOffset(cmd->GetDynamicOffset());
+ if (cmd->IsUniform() || cmd->IsUniformDynamic() || cmd->IsSSBO() ||
+ cmd->IsSSBODynamic()) {
+ desc->AsBufferDescriptor()->AddDescriptorOffset(cmd->GetDescriptorOffset());
+ desc->AsBufferDescriptor()->AddDescriptorRange(cmd->GetDescriptorRange());
+ }
+
if (cmd->IsSSBO() && !desc->IsStorageBuffer()) {
return Result(
"Vulkan::AddBufferDescriptor BufferCommand for SSBO uses wrong "
@@ -408,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
@@ -423,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());
@@ -471,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());
@@ -486,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/pipeline_test.cc b/src/vulkan/pipeline_test.cc
index 53eca44..9f60174 100644
--- a/src/vulkan/pipeline_test.cc
+++ b/src/vulkan/pipeline_test.cc
@@ -44,9 +44,9 @@ TEST_F(VulkanPipelineTest, AddBufferDescriptorAddBufferTwice) {
&amber_pipeline);
Result r = pipeline.AddBufferDescriptor(cmd.get());
ASSERT_TRUE(r.IsSuccess()) << r.Error();
- // Adding same buffer again should fail.
+ // Adding same buffer again shouldn't fail.
r = pipeline.AddBufferDescriptor(cmd.get());
- ASSERT_FALSE(r.IsSuccess());
+ ASSERT_TRUE(r.IsSuccess());
}
} // namespace vulkan
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_descriptor_array_ssbo.amber b/tests/cases/compute_descriptor_array_ssbo.amber
index bd4c773..0eb6b7d 100644
--- a/tests/cases/compute_descriptor_array_ssbo.amber
+++ b/tests/cases/compute_descriptor_array_ssbo.amber
@@ -20,12 +20,19 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0) buffer block0
{
int data;
-} ssbo_array[2];
+} ssbo_array_0[2];
+
+layout(binding = 1) buffer block1
+{
+ int data;
+} ssbo_array_1[2];
void main()
{
- ssbo_array[0].data = 1;
- ssbo_array[1].data = 2;
+ ssbo_array_0[0].data = 1;
+ ssbo_array_0[1].data = 2;
+ ssbo_array_1[0].data = 3;
+ ssbo_array_1[1].data = 4;
}
END
@@ -37,13 +44,21 @@ BUFFER buf1 DATA_TYPE int32 DATA
0
END
+# The Vulkan spec lists the maximum value of minStorageBufferOffsetAlignment
+# (i.e. the maximum possible alignment requirement) as 256 bytes, so we will use
+# buffer with size of 65 int32 values = 260 bytes.
+BUFFER buf2 DATA_TYPE int32 SIZE 65 FILL 0
+
PIPELINE compute pipeline
ATTACH compute_shader
BIND BUFFER_ARRAY buf0 buf1 AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER_ARRAY buf2 buf2 AS storage DESCRIPTOR_SET 0 BINDING 1 DESCRIPTOR_OFFSET 0 256 DESCRIPTOR_RANGE 256 4
END
RUN pipeline 1 1 1
EXPECT buf0 IDX 0 EQ 1
EXPECT buf1 IDX 0 EQ 2
+EXPECT buf2 IDX 0 EQ 3
+EXPECT buf2 IDX 256 EQ 4
diff --git a/tests/cases/compute_descriptor_array_storagetexelbuffer.amber b/tests/cases/compute_descriptor_array_storagetexelbuffer.amber
index d4a1994..3ddae3c 100644
--- a/tests/cases/compute_descriptor_array_storagetexelbuffer.amber
+++ b/tests/cases/compute_descriptor_array_storagetexelbuffer.amber
@@ -17,13 +17,20 @@ SHADER compute compute_shader GLSL
#version 430
layout(local_size_x=4,local_size_y=1) in;
uniform layout(set=0, binding=0) samplerBuffer texelsIn;
-uniform layout(set=0, binding=1, rgba32f) imageBuffer texelsOut[2];
+uniform layout(set=0, binding=1, rgba32f) imageBuffer texelsOut_0[2];
+uniform layout(set=0, binding=2, rgba32f) imageBuffer texelsOut_1[2];
void main ()
{
vec4 color = texelFetch(texelsIn, int(gl_GlobalInvocationID));
- imageStore(texelsOut[0], int(gl_GlobalInvocationID), color);
- imageStore(texelsOut[1], int(gl_GlobalInvocationID), color * 2.0);
+ imageStore(texelsOut_0[0], int(gl_GlobalInvocationID), color);
+ imageStore(texelsOut_0[1], int(gl_GlobalInvocationID), color * 2.0);
+ if (int(gl_GlobalInvocationID) < 2) {
+ imageStore(texelsOut_1[0], int(gl_GlobalInvocationID), color * 3.0);
+ }
+ else {
+ imageStore(texelsOut_1[1], int(gl_GlobalInvocationID), color * 4.0);
+ }
}
END
@@ -36,6 +43,7 @@ END
BUFFER texel_buffer_out0 DATA_TYPE R32G32B32A32_SFLOAT SIZE 4 FILL 0
BUFFER texel_buffer_out1 DATA_TYPE R32G32B32A32_SFLOAT SIZE 4 FILL 0
+BUFFER texel_buffer_out2 DATA_TYPE R32G32B32A32_SFLOAT SIZE 4 FILL 0
BUFFER ref0 DATA_TYPE R32G32B32A32_SFLOAT DATA
1.0 0.0 0.0 1.0
@@ -51,13 +59,22 @@ BUFFER ref1 DATA_TYPE R32G32B32A32_SFLOAT DATA
0.0 2.0 2.0 2.0
END
+BUFFER ref2 DATA_TYPE R32G32B32A32_SFLOAT DATA
+3.0 0.0 0.0 3.0
+0.0 3.0 0.0 3.0
+0.0 0.0 4.0 4.0
+0.0 4.0 4.0 4.0
+END
+
PIPELINE compute pipeline
ATTACH compute_shader
BIND BUFFER texel_buffer_in AS uniform_texel_buffer DESCRIPTOR_SET 0 BINDING 0
BIND BUFFER_ARRAY texel_buffer_out0 texel_buffer_out1 AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING 1
+ BIND BUFFER_ARRAY texel_buffer_out2 texel_buffer_out2 AS storage_texel_buffer DESCRIPTOR_SET 0 BINDING 2
END
RUN pipeline 1 1 1
EXPECT texel_buffer_out0 EQ_BUFFER ref0
EXPECT texel_buffer_out1 EQ_BUFFER ref1
+EXPECT texel_buffer_out2 EQ_BUFFER ref2
diff --git a/tests/cases/compute_dynamic_buffers.amber b/tests/cases/compute_dynamic_buffers.amber
index 9412e30..9dd4149 100644
--- a/tests/cases/compute_dynamic_buffers.amber
+++ b/tests/cases/compute_dynamic_buffers.amber
@@ -25,11 +25,16 @@ layout(set = 0, binding = 1) buffer block1
{
vec4 data1;
};
+layout(set = 0, binding = 2) buffer block2
+{
+ vec4 data2;
+};
void main()
{
data0 = vec4(1, 2, 3, 4);
data1 = vec4(5, 6, 7, 8);
+ data2 = vec4(9, 10, 11, 12);
}
END
@@ -39,6 +44,7 @@ END
# after the alignment (256 / 16 + 1).
BUFFER buf0 DATA_TYPE vec4<float> SIZE 17 FILL 0.0
BUFFER buf1 DATA_TYPE vec4<float> SIZE 17 FILL 0.0
+BUFFER buf2 DATA_TYPE vec4<float> SIZE 33 FILL 0.0
PIPELINE compute pipeline
ATTACH compute_shader
@@ -46,9 +52,12 @@ PIPELINE compute pipeline
BIND BUFFER buf0 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 0 OFFSET 0
# Using the maximum possible required offset alignment of 256 bytes to support all implementations.
BIND BUFFER buf1 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 1 OFFSET 256
+ # Same as above, but with buffer offset of 256 bytes (total offset of 512).
+ BIND BUFFER buf2 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 2 OFFSET 256 DESCRIPTOR_OFFSET 256
END
RUN pipeline 1 1 1
EXPECT buf0 IDX 0 EQ 1.0 2.0 3.0 4.0
EXPECT buf1 IDX 256 EQ 5.0 6.0 7.0 8.0
+EXPECT buf2 IDX 512 EQ 9.0 10.0 11.0 12.0
diff --git a/tests/cases/compute_dynamic_buffers_descriptor_array.amber b/tests/cases/compute_dynamic_buffers_descriptor_array.amber
index fe07b6c..ccc4c42 100644
--- a/tests/cases/compute_dynamic_buffers_descriptor_array.amber
+++ b/tests/cases/compute_dynamic_buffers_descriptor_array.amber
@@ -19,12 +19,18 @@ SHADER compute compute_shader GLSL
layout(set = 0, binding = 0) buffer block0
{
vec4 data;
-} ssbo_array[2];
+} ssbo_array_0[2];
+layout(set = 0, binding = 1) buffer block1
+{
+ int data;
+} ssbo_array_1[2];
void main()
{
- ssbo_array[0].data = vec4(1, 2, 3, 4);
- ssbo_array[1].data = vec4(5, 6, 7, 8);
+ ssbo_array_0[0].data = vec4(1, 2, 3, 4);
+ ssbo_array_0[1].data = vec4(5, 6, 7, 8);
+ ssbo_array_1[0].data = 9;
+ ssbo_array_1[1].data = 10;
}
END
@@ -34,15 +40,20 @@ END
# after the alignment (256 / 16 + 1).
BUFFER buf0 DATA_TYPE vec4<float> SIZE 17 FILL 0.0
BUFFER buf1 DATA_TYPE vec4<float> SIZE 17 FILL 0.0
+# Same as above, but with int32 and double size: 512 / 4 + 1
+BUFFER buf2 DATA_TYPE int32 SIZE 129 FILL 0
PIPELINE compute pipeline
ATTACH compute_shader
# Using the maximum possible required offset alignment of 256 bytes to support all implementations.
BIND BUFFER_ARRAY buf0 buf1 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 0 OFFSET 0 256
+ BIND BUFFER_ARRAY buf2 buf2 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 1 OFFSET 0 256 DESCRIPTOR_OFFSET 0 256
END
RUN pipeline 1 1 1
EXPECT buf0 IDX 0 EQ 1.0 2.0 3.0 4.0
EXPECT buf1 IDX 256 EQ 5.0 6.0 7.0 8.0
+EXPECT buf2 IDX 0 EQ 9
+EXPECT buf2 IDX 512 EQ 10
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/graphics_descriptor_array_combined_image_sampler.amber b/tests/cases/graphics_descriptor_array_combined_image_sampler.amber
index d7fe3c0..e80ca1e 100644
--- a/tests/cases/graphics_descriptor_array_combined_image_sampler.amber
+++ b/tests/cases/graphics_descriptor_array_combined_image_sampler.amber
@@ -40,10 +40,16 @@ SHADER fragment frag_shader_tex GLSL
#version 430
layout(location = 0) in vec2 texcoords_in;
layout(location = 0) out vec4 color_out;
-uniform layout(set=0, binding=0) sampler2D tex_sampler[2];
+uniform layout(set=0, binding=0) sampler2D tex_sampler_0[2];
+uniform layout(set=0, binding=1) sampler2D tex_sampler_1[2];
void main() {
- color_out = texture(tex_sampler[0], texcoords_in);
- color_out = color_out + texture(tex_sampler[1], texcoords_in);
+ vec4 tex_0_color = texture(tex_sampler_0[0], texcoords_in);
+ color_out = tex_0_color + texture(tex_sampler_0[1], texcoords_in);
+ // tex_sampler_1[0] and tex_sampler_1[1] should be equal to tex_sampler_0[0]
+ if (tex_0_color != texture(tex_sampler_1[0], texcoords_in) ||
+ tex_0_color != texture(tex_sampler_1[1], texcoords_in)) {
+ color_out = vec4(1.0);
+ }
}
END
@@ -75,6 +81,7 @@ PIPELINE graphics pipeline
ATTACH vert_shader_tex
ATTACH frag_shader_tex
BIND BUFFER_ARRAY texture0 texture1 AS combined_image_sampler SAMPLER sampler DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER_ARRAY texture0 texture0 AS combined_image_sampler SAMPLER sampler DESCRIPTOR_SET 0 BINDING 1
VERTEX_DATA position LOCATION 0
VERTEX_DATA texcoords LOCATION 1
BIND BUFFER framebuffer AS color LOCATION 0
diff --git a/tests/cases/graphics_descriptor_array_sampled_image.amber b/tests/cases/graphics_descriptor_array_sampled_image.amber
index 497f6da..3342054 100644
--- a/tests/cases/graphics_descriptor_array_sampled_image.amber
+++ b/tests/cases/graphics_descriptor_array_sampled_image.amber
@@ -40,11 +40,18 @@ SHADER fragment frag_shader_tex GLSL
#version 430
layout(location = 0) in vec2 texcoords_in;
layout(location = 0) out vec4 color_out;
-uniform layout(set=0, binding=0) texture2D tex[2];
+uniform layout(set=0, binding=0) texture2D tex_0[2];
uniform layout(set=0, binding=1) sampler tex_sampler;
+uniform layout(set=0, binding=2) texture2D tex_1[2];
void main() {
- color_out = texture(sampler2D(tex[0], tex_sampler), texcoords_in);
- color_out += texture(sampler2D(tex[1], tex_sampler), texcoords_in);
+ vec4 tex_0_color = texture(sampler2D(tex_0[0], tex_sampler), texcoords_in);
+ color_out = tex_0_color;
+ color_out += texture(sampler2D(tex_0[1], tex_sampler), texcoords_in);
+ // tex_1[0] and tex_1[1] should be equal to tex_0[0].
+ if (tex_0_color != texture(sampler2D(tex_1[0], tex_sampler), texcoords_in) ||
+ tex_0_color != texture(sampler2D(tex_1[1], tex_sampler), texcoords_in)) {
+ color_out = vec4(1.0);
+ }
}
END
@@ -77,6 +84,7 @@ PIPELINE graphics pipeline
ATTACH frag_shader_tex
BIND BUFFER_ARRAY texture0 texture1 AS sampled_image DESCRIPTOR_SET 0 BINDING 0
BIND SAMPLER sampler DESCRIPTOR_SET 0 BINDING 1
+ BIND BUFFER_ARRAY texture0 texture0 AS sampled_image DESCRIPTOR_SET 0 BINDING 2
VERTEX_DATA position LOCATION 0
VERTEX_DATA texcoords LOCATION 1
BIND BUFFER framebuffer AS color LOCATION 0
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/non_default_entry_point.amber b/tests/cases/non_default_entry_point.amber
index 36b2135..3a0892f 100644
--- a/tests/cases/non_default_entry_point.amber
+++ b/tests/cases/non_default_entry_point.amber
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+DEVICE_EXTENSION VK_KHR_storage_buffer_storage_class
+
SHADER compute my_shader SPIRV-ASM
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
diff --git a/tests/cases/shader_specialization.amber b/tests/cases/shader_specialization.amber
index 1db2a4f..4514b6f 100644
--- a/tests/cases/shader_specialization.amber
+++ b/tests/cases/shader_specialization.amber
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+DEVICE_EXTENSION VK_KHR_storage_buffer_storage_class
+
SHADER compute my_compute SPIRV-ASM
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
diff --git a/tests/cases/storage16.amber b/tests/cases/storage16.amber
index 5cf8113..36a62dc 100644
--- a/tests/cases/storage16.amber
+++ b/tests/cases/storage16.amber
@@ -19,6 +19,7 @@ DEVICE_EXTENSION VK_KHR_16bit_storage
DEVICE_FEATURE shaderInt16
DEVICE_FEATURE Storage16BitFeatures.uniformAndStorageBuffer16BitAccess
DEVICE_FEATURE Storage16BitFeatures.storagePushConstant16
+DEVICE_FEATURE Storage16BitFeatures.storageBuffer16BitAccess
SHADER compute comp_shader GLSL
#version 450
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/cases/viewport.amber b/tests/cases/viewport.amber
new file mode 100644
index 0000000..ca9b0a5
--- /dev/null
+++ b/tests/cases/viewport.amber
@@ -0,0 +1,59 @@
+#!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 GLSL
+#version 430
+
+layout(location = 0) in vec4 position;
+
+void main() {
+ gl_Position = vec4(position.xy, 0.5, 1.0);
+}
+END
+
+SHADER fragment frag_shader GLSL
+#version 430
+
+layout(location = 0) out vec4 final_color;
+
+void main() {
+ final_color = vec4(0, 1, 0, 1);
+}
+END
+
+BUFFER framebuffer FORMAT B8G8R8A8_UNORM
+
+PIPELINE graphics pipeline1
+ ATTACH vert_shader
+ ATTACH frag_shader
+
+ FRAMEBUFFER_SIZE 256 256
+ VIEWPORT 10.0 10.0 SIZE 100.0 100.0
+
+ BIND BUFFER framebuffer AS color LOCATION 0
+END
+
+CLEAR_COLOR pipeline1 255 255 255 255
+CLEAR pipeline1
+RUN pipeline1 DRAW_RECT POS 0 0 SIZE 256 256
+
+# Check within the viewport
+EXPECT framebuffer IDX 10 10 SIZE 100 100 EQ_RGBA 0 255 0 255
+# Check the borders were untouched
+EXPECT framebuffer IDX 0 0 SIZE 10 256 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 110 0 SIZE 146 256 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 10 0 SIZE 100 10 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 10 110 SIZE 100 146 EQ_RGBA 255 255 255 255
diff --git a/tests/cases/viewport_depth.amber b/tests/cases/viewport_depth.amber
new file mode 100644
index 0000000..2bf7a9e
--- /dev/null
+++ b/tests/cases/viewport_depth.amber
@@ -0,0 +1,61 @@
+#!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 GLSL
+#version 430
+
+layout(location = 0) in vec4 position;
+
+void main() {
+ gl_Position = vec4(position.xy, 0.5, 1.0);
+}
+END
+
+SHADER fragment frag_shader GLSL
+#version 430
+
+layout(location = 0) out vec4 final_color;
+
+void main() {
+ final_color = vec4(0, 1, 0, 1);
+}
+END
+
+BUFFER framebuffer FORMAT B8G8R8A8_UNORM
+BUFFER depth FORMAT D32_SFLOAT
+
+PIPELINE graphics pipeline1
+ ATTACH vert_shader
+ ATTACH frag_shader
+
+ DEPTH
+ TEST on
+ WRITE on
+ END
+
+ FRAMEBUFFER_SIZE 256 256
+ VIEWPORT 0.0 0.0 SIZE 256.0 256.0 MIN_DEPTH 0.3 MAX_DEPTH 0.9
+
+ BIND BUFFER framebuffer AS color LOCATION 0
+ BIND BUFFER depth AS depth_stencil
+END
+
+CLEAR_DEPTH pipeline1 1.0
+CLEAR_COLOR pipeline1 255 255 255 255
+CLEAR pipeline1
+RUN pipeline1 DRAW_RECT POS 0 0 SIZE 256 256
+
+EXPECT depth IDX 0 TOLERANCE 1.0e-6 EQ 0.6
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