diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:17:07 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:17:07 +0000 |
commit | bcfa77eb624a994e150b8d6356f3f0fca58816ed (patch) | |
tree | 7bf7238d34d1cdf3671a43fe4147a53606453504 | |
parent | 9b2aa5bf17bf55d96d83daf3beeef380e199de3a (diff) | |
parent | 3f8fbfe46bdb1dd1526687a84c644c1b2846a636 (diff) | |
download | amber-android13-mainline-os-statsd-release.tar.gz |
Snap for 8564071 from 3f8fbfe46bdb1dd1526687a84c644c1b2846a636 to mainline-os-statsd-releaseaml_sta_331910000aml_sta_331811000aml_sta_331711010aml_sta_331610000aml_sta_331511000aml_sta_331410000aml_sta_331311000aml_sta_331010010aml_sta_330910000android13-mainline-os-statsd-release
Change-Id: Id2cbf025c31c5839e6bdc68a62902af544481da9
85 files changed, 3050 insertions, 424 deletions
@@ -17,6 +17,7 @@ third_party/swiftshader third_party/vulkan-headers third_party/vulkan-loader third_party/vulkan-validationlayers/ +third_party/robin-hood-hashing .vs *.pyc @@ -25,5 +26,5 @@ third_party/vulkan-validationlayers/ [._]*.s[a-w][a-z] # C-Lion -.idea -cmake-build-debug +.idea/ +cmake-build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f65d5f..c064649 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,6 @@ endif() function(amber_default_compile_options TARGET) if (${COMPILER_IS_LIKE_GNU}) target_compile_options(${TARGET} PRIVATE - -std=c++11 -fno-exceptions -fvisibility=hidden -Wall @@ -230,7 +229,6 @@ function(amber_default_compile_options TARGET) endif() if (MSVC) - # Specify /EHs for exception handling. target_compile_options(${TARGET} PRIVATE /bigobj /EHsc @@ -266,6 +264,6 @@ endfunction() add_subdirectory(third_party) add_subdirectory(src) -if (${AMBER_ENABLE_SAMPLES} AND NOT ANDROID) +if (${AMBER_ENABLE_SAMPLES}) add_subdirectory(samples) endif() @@ -8,23 +8,25 @@ vars = { 'microsoft_git': 'https://github.com/Microsoft', 'nlohmann_git': 'https://github.com/nlohmann', 'swiftshader_git': 'https://swiftshader.googlesource.com', + 'martinus_git': 'https://github.com/martinus', - 'clspv_llvm_revision': '7e30989dabce9ddbca0cbad7a8f25fb4e756d334', - 'clspv_revision': 'e0406e7053d1bb46b4bbeb57f0f2bbfca32f5612', - 'cppdap_revision': '1fd23dda91e01550be1a421de307e6fedb2035a9', + 'clspv_llvm_revision': 'b70366c9c430e1eadd59d5a1dfbb9c4d84f83de5', + 'clspv_revision': 'f99809bdab1710846633b4ec24f5448263e75da7', + 'cppdap_revision': '88e89520148b2f95e17ca9348587a28215ffc921', 'cpplint_revision': '26470f9ccb354ff2f6d098f831271a1833701b28', - 'dxc_revision': '489c2e4d32417cd6693db5673ab071d82e1f5974', - 'glslang_revision': '7f6559d2802d0653541060f0909e33d137b9c8ba', - 'googletest_revision': '0555b0eacbc56df1fd762c6aa87bb84be9e4ce7e', - 'json_revision': '350ff4f7ced7c4117eae2fb93df02823c8021fcb', - 'lodepng_revision': '7fdcc96a5e5864eee72911c3ca79b1d9f0d12292', - 'shaderc_revision': '88f9156d7f6a2a30baed1ace196faa3bc5eccc05', - 'spirv_headers_revision': '5ab5c96198f30804a6a29961b8905f292a8ae600', - 'spirv_tools_revision': '1f2fcddd3963b9c29bf360daf7656c5977c2aadd', - 'swiftshader_revision': '04515da400d5fbc22d852af1369c4d46bd54991e', - 'vulkan_headers_revision': '11c6670b4a4f766ed4f1e777d1b3c3dc082dfa5f', - 'vulkan_loader_revision': 'be6ccb9ecaf77dfef59246a1e8502e99c8e1a511', - 'vulkan_validationlayers_revision': '0cb8cc8cfcb2b86a767c9516ac2d62edb4e38ebe', + 'dxc_revision': 'c45db48d565a9edc14b025e43b90e62264d06eea', + 'glslang_revision': '81cc10a498b25a90147cccd6e8939493c1e9e20e', + 'googletest_revision': '16f637fbf4ffc3f7a01fa4eceb7906634565242f', + 'json_revision': '4f8fba14066156b73f1189a2b8bd568bde5284c5', + 'lodepng_revision': '5601b8272a6850b7c5d693dd0c0e16da50be8d8d', + 'shaderc_revision': 'e72186b66bb90ed06aaf15cbdc9a053581a0616b', + 'spirv_headers_revision': 'b42ba6d92faf6b4938e6f22ddd186dbdacc98d78', + 'spirv_tools_revision': 'a73e724359a274d7cf4f4248eba5be1e7764fbfd', + 'swiftshader_revision': 'bca23447ad4667a7b79973569ab5d8d905d211ac', + 'vulkan_headers_revision': '1dace16d8044758d32736eb59802d171970e9448', + 'vulkan_loader_revision': '8aad559a09388ceb5b968af64a2b965d3886e5a0', + 'vulkan_validationlayers_revision': 'a6c1ddca49331d8addde052554487180ee8aec13', + 'robin_hood_hashing_revision': '24b3f50f9532153edc23b29ae277dcccfd75a462', } deps = { @@ -75,4 +77,7 @@ deps = { 'third_party/vulkan-loader': Var('khronos_git') + '/Vulkan-Loader.git@' + Var('vulkan_loader_revision'), + + 'third_party/robin-hood-hashing': Var('martinus_git') + '/robin-hood-hashing.git@' + + Var('robin_hood_hashing_revision'), } diff --git a/android_gradle/app/build.gradle b/android_gradle/app/build.gradle index 40c4c54..b756f6b 100644 --- a/android_gradle/app/build.gradle +++ b/android_gradle/app/build.gradle @@ -1,26 +1,37 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' +} android { - compileSdkVersion 29 - buildToolsVersion "29.0.2" + compileSdk 30 + buildToolsVersion "30.0.2" + ndkVersion "21.4.7075529" defaultConfig { applicationId "com.google.amber" minSdkVersion 24 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + externalNativeBuild { + cmake { + arguments "-DAMBER_USE_LOCAL_VULKAN=1" + targets "amber_ndk" + } + } } - sourceSets { - androidTest.manifest.srcFile "src/androidTest/AndroidManifest.xml" + externalNativeBuild { + cmake { + path "../../CMakeLists.txt" + } } - dependencies { - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test:rules:1.1.0' + sourceSets { + androidTest.manifest.srcFile "src/androidTest/AndroidManifest.xml" } buildTypes { @@ -29,6 +40,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt') } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { @@ -41,9 +56,10 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } diff --git a/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java b/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java index 4864843..ad92154 100644 --- a/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java +++ b/android_gradle/app/src/androidTest/java/com/google/amber/AmberLauncher.java @@ -54,7 +54,7 @@ public class AmberLauncher { String stdout_file = args.getString("stdout", new File(outputDir, "amber_stdout.txt").toString()); String stderr_file = args.getString("stderr", new File(outputDir, "amber_stderr.txt").toString()); - int res = Amber.androidMain(args_list.toArray(new String[0]), stdout_file, stderr_file); + int res = Amber.androidHelper(args_list.toArray(new String[0]), stdout_file, stderr_file); // If the process crashes during the above call or we call System.exit below, the output // from `adb shell am instrument ...` will be: diff --git a/android_gradle/app/src/main/AndroidManifest.xml b/android_gradle/app/src/main/AndroidManifest.xml index 0ab9856..c74c390 100644 --- a/android_gradle/app/src/main/AndroidManifest.xml +++ b/android_gradle/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ <application android:allowBackup="true" + android:fullBackupOnly="true" android:label="Amber" android:supportsRtl="true"> <meta-data diff --git a/android_gradle/app/src/main/java/com/google/amber/Amber.java b/android_gradle/app/src/main/java/com/google/amber/Amber.java index 8319ccf..008c528 100644 --- a/android_gradle/app/src/main/java/com/google/amber/Amber.java +++ b/android_gradle/app/src/main/java/com/google/amber/Amber.java @@ -19,5 +19,5 @@ public class Amber { System.loadLibrary("amber_ndk"); } - public static native int androidMain(String[] args, String stdout_file, String stderr_file); + public static native int androidHelper(String[] args, String stdout_file, String stderr_file); } diff --git a/android_gradle/build.gradle b/android_gradle/build.gradle index 82c93bf..d340082 100644 --- a/android_gradle/build.gradle +++ b/android_gradle/build.gradle @@ -4,25 +4,16 @@ buildscript { repositories { google() - jcenter() - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0-alpha04' + classpath 'com.android.tools.build:gradle:7.0.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } -allprojects { - repositories { - google() - jcenter() - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } - } -} - task clean(type: Delete) { delete rootProject.buildDir } diff --git a/android_gradle/gradle.properties b/android_gradle/gradle.properties index 199d16e..4941ecd 100644 --- a/android_gradle/gradle.properties +++ b/android_gradle/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/android_gradle/gradle/wrapper/gradle-wrapper.jar b/android_gradle/gradle/wrapper/gradle-wrapper.jar Binary files differindex f6b961f..e708b1c 100644 --- a/android_gradle/gradle/wrapper/gradle-wrapper.jar +++ b/android_gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/android_gradle/gradle/wrapper/gradle-wrapper.properties b/android_gradle/gradle/wrapper/gradle-wrapper.properties index 421d5b6..e81b594 100644 --- a/android_gradle/gradle/wrapper/gradle-wrapper.properties +++ b/android_gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 09 14:37:37 GMT 2019 +#Sat Sep 25 16:43:12 BST 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-rc-1-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/android_gradle/settings.gradle b/android_gradle/settings.gradle index 9a979bb..2c4357f 100644 --- a/android_gradle/settings.gradle +++ b/android_gradle/settings.gradle @@ -1,2 +1,9 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} rootProject.name='Amber' include ':app' diff --git a/docs/amber_script.md b/docs/amber_script.md index 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 |