From 7494850d4fd1e4056d7d9f2e9abbafb749e2dbee Mon Sep 17 00:00:00 2001 From: Greg Grebe Date: Tue, 10 Mar 2020 13:29:46 -0400 Subject: [PATCH] Add dEQP-VK.pipeline.creation_cache_control.* Add new test groups: dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.* dEQP-VK.pipeline.creation_cache_control.compute_pipelines.* Add new tests: *.single_pipeline_no_compile *.batch_pipelines_early_return *.duplicate_single_recreate_explicit_caching *.duplicate_single_recreate_no_caching *.duplicate_single_recreate_derivative *.duplicate_batch_pipelines_explicit_cache *.duplicate_batch_pipelines_no_cache *.duplicate_batch_pipelines_derivative_index VK_EXT_pipeline_creation_cache_control adds the ability for vkCreate*Pipeline calls to fail rather compile when requested by the application. These tests use both single and batch pipeline creation with the most common methods of caching: explicit caching, no cache/ implicit caching, and pipeline derivatives. This ensures that drivers are responsive to the needs of an application using this extension by not only checking the output but the time taken to execute the vkCreate*Pipeline call. The tests explicitly fail in the following cases: - Any result other than SUCCESS or PIPELINE_COMPILE_REQUIRED. - An invalid pipeline handle returned when created without FAIL_ON_PIPELINE_COMPILE_REQUIRED. - A valid pipeline is returned sequentially following a failed pipeline with the flag EARLY_RETURN_ON_FAILURE set during batch pipeline creation. Failures due to timing will only be QUALITY warnings. The shaders used contain random constant values baked into the GLSL in an attempt to force the need to compile pipelines through fuzzing. Any unexpectedly successful pipeline creations (such as due to accidental cache hits) will raise a COMPATIBILITY warning. Affects no existing tests. Components: Framework, Vulkan Vulkan issue: 2013 Change-Id: I90dec48293a5c8ece66fc871a13c6d6f0e3002ff (cherry picked from commit 26cb99a1eb50332a93bc329a4d34a5d9239a5667) --- AndroidGen.mk | 1 + android/cts/master/vk-master-2020-03-01.txt | 16 + android/cts/master/vk-master.txt | 16 + .../framework/vulkan/vkMandatoryFeatures.inl | 19 + .../modules/vulkan/pipeline/CMakeLists.txt | 16 +- .../vktPipelineCreationCacheControlTests.cpp | 1412 ++++++++++++++++++++ .../vktPipelineCreationCacheControlTests.hpp | 39 + .../modules/vulkan/pipeline/vktPipelineTests.cpp | 2 + .../vulkancts/modules/vulkan/util/CMakeLists.txt | 1 + .../modules/vulkan/util/vktConstexprVectorUtil.hpp | 87 ++ external/vulkancts/mustpass/master/vk-default.txt | 16 + .../vulkancts/scripts/src/mandatory_features.txt | 1 + framework/common/tcuStringTemplate.hpp | 44 + 13 files changed, 1663 insertions(+), 7 deletions(-) create mode 100644 external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.cpp create mode 100644 external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.hpp create mode 100644 external/vulkancts/modules/vulkan/util/vktConstexprVectorUtil.hpp diff --git a/AndroidGen.mk b/AndroidGen.mk index 98d33e3..cee1e3d 100644 --- a/AndroidGen.mk +++ b/AndroidGen.mk @@ -199,6 +199,7 @@ LOCAL_SRC_FILES := \ external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.cpp \ external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.cpp \ external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.cpp \ + external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.cpp \ external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationFeedbackTests.cpp \ external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthRangeUnrestrictedTests.cpp \ external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.cpp \ diff --git a/android/cts/master/vk-master-2020-03-01.txt b/android/cts/master/vk-master-2020-03-01.txt index 9ad4b7f..0e30398 100644 --- a/android/cts/master/vk-master-2020-03-01.txt +++ b/android/cts/master/vk-master-2020-03-01.txt @@ -148533,6 +148533,22 @@ dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_0_depthfail dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_pass dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_depthfail +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_derivative_index +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_derivative_index dEQP-VK.binding_model.descriptor_update.samplerless.sampled_img_sampler_zero dEQP-VK.binding_model.descriptor_update.samplerless.sampled_img_sampler_one dEQP-VK.binding_model.descriptor_update.samplerless.sampled_img_sampler_destroyed diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt index ccf56ef..1d6a2dc 100644 --- a/android/cts/master/vk-master.txt +++ b/android/cts/master/vk-master.txt @@ -325546,6 +325546,22 @@ dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_0_depthfail dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_pass dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_depthfail +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_derivative_index +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_derivative_index dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d_base_mip dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d_base_slice diff --git a/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl b/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl index 7a71a92..0c76ee5 100644 --- a/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl +++ b/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl @@ -176,6 +176,16 @@ bool checkMandatoryFeatures(const vkt::Context& context) nextPtr = &physicalDevicePerformanceQueryFeaturesKHR.pNext; } + vk::VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT physicalDevicePipelineCreationCacheControlFeaturesEXT; + deMemset(&physicalDevicePipelineCreationCacheControlFeaturesEXT, 0, sizeof(physicalDevicePipelineCreationCacheControlFeaturesEXT)); + + if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_EXT_pipeline_creation_cache_control")) ) + { + physicalDevicePipelineCreationCacheControlFeaturesEXT.sType = getStructureType(); + *nextPtr = &physicalDevicePipelineCreationCacheControlFeaturesEXT; + nextPtr = &physicalDevicePipelineCreationCacheControlFeaturesEXT.pNext; + } + vk::VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR physicalDevicePipelineExecutablePropertiesFeaturesKHR; deMemset(&physicalDevicePipelineExecutablePropertiesFeaturesKHR, 0, sizeof(physicalDevicePipelineExecutablePropertiesFeaturesKHR)); @@ -723,6 +733,15 @@ bool checkMandatoryFeatures(const vkt::Context& context) } } + if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_EXT_pipeline_creation_cache_control")) ) + { + if ( physicalDevicePipelineCreationCacheControlFeaturesEXT.pipelineCreationCacheControl == VK_FALSE ) + { + log << tcu::TestLog::Message << "Mandatory feature pipelineCreationCacheControl not supported" << tcu::TestLog::EndMessage; + result = false; + } + } + if ( context.contextSupports(vk::ApiVersion(1, 2, 0)) ) { if ( physicalDeviceVulkan12Features.separateDepthStencilLayouts == VK_FALSE ) diff --git a/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt index 2df5782..c239120 100644 --- a/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt @@ -1,9 +1,4 @@ -include_directories( - .. - ../amber - ) - set(DEQP_VK_PIPELINE_SRCS vktPipelineBlendTests.cpp vktPipelineBlendTests.hpp @@ -101,6 +96,8 @@ set(DEQP_VK_PIPELINE_SRCS vktPipelineBlendOperationAdvancedTests.hpp vktPipelineExtendedDynamicStateTests.cpp vktPipelineExtendedDynamicStateTests.hpp + vktPipelineCreationCacheControlTests.cpp + vktPipelineCreationCacheControlTests.hpp ) set(DEQP_VK_PIPELINE_LIBS @@ -111,8 +108,13 @@ set(DEQP_VK_PIPELINE_LIBS ) PCH(DEQP_VK_PIPELINE_SRCS ../pch.cpp) -include_directories("../../../../amber/src/include") -include_directories("../amber") add_library(deqp-vk-pipeline STATIC ${DEQP_VK_PIPELINE_SRCS}) target_link_libraries(deqp-vk-pipeline ${DEQP_VK_PIPELINE_LIBS}) +target_include_directories(deqp-vk-pipeline + PRIVATE + .. + ../../../../amber/src/include + ../amber + ../util +) \ No newline at end of file diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.cpp new file mode 100644 index 0000000..5289088 --- /dev/null +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.cpp @@ -0,0 +1,1412 @@ +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2020 The Khronos Group Inc. + * Copyright (c) 2020 Advanced Micro Devices, Inc. + * + * 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 implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/*! + * \file + * \brief Pipeline Cache Tests + */ +/*--------------------------------------------------------------------*/ + +#include "vktPipelineCreationCacheControlTests.hpp" + +#include "deRandom.hpp" +#include "deUniquePtr.hpp" +#include "tcuStringTemplate.hpp" +#include "vkDeviceUtil.hpp" +#include "vkRefUtil.hpp" +#include "vktConstexprVectorUtil.hpp" +#include "vktTestCase.hpp" +#include "vktTestCaseUtil.hpp" + +#include +#include +#include +#include + +namespace vkt +{ +namespace pipeline +{ +namespace +{ +using namespace vk; + +using tcu::StringTemplate; +using tcu::TestCaseGroup; +using tcu::TestContext; +using tcu::TestStatus; + +using ::std::array; +using ::std::string; +using ::std::vector; + +/*--------------------------------------------------------------------*//*! + * Elements common to all test types + *//*--------------------------------------------------------------------*/ +namespace test_common +{ +static constexpr auto VK_NULL_HANDLE = DE_NULL; + +using ::std::chrono::high_resolution_clock; +using ::std::chrono::microseconds; + +using duration = high_resolution_clock::duration; +using UniquePipeline = Move; +using UniqueShaderModule = Move; + +/*--------------------------------------------------------------------*//*! + * \brief Paired Vulkan API result with elapsed duration + *//*--------------------------------------------------------------------*/ +struct TimedResult +{ + VkResult result; + duration elapsed; +}; + +/*--------------------------------------------------------------------*//*! + * \brief Validation function type output from vkCreate*Pipelines() + * + * \param result - VkResult returned from API call + * \param pipeliens - vector of pipelines created + * \param elapsed - high_resolution_clock::duration of time elapsed in API + * \param reason - output string to give the reason for failure + * + * \return QP_TEST_RESULT_PASS on success QP_TEST_RESULT_FAIL otherwise + *//*--------------------------------------------------------------------*/ +using Validator = qpTestResult (*)(VkResult, const vector&, duration, string&); + +static constexpr size_t VALIDATOR_ARRAY_MAX = 4; +using ValidatorArray = ConstexprVector; + +/*--------------------------------------------------------------------*//*! + * \brief Run a loop of validation tests and return the result + *//*--------------------------------------------------------------------*/ +template +TestStatus validateResults(VkResult result, + const pipelines_t& pipelines, + duration elapsed, + const ValidatorArray& validators) +{ + using de::contains; + static constexpr VkResult ALLOWED_RESULTS[] = {VK_SUCCESS, VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT}; + + string reason; + + if (contains(DE_ARRAY_BEGIN(ALLOWED_RESULTS), DE_ARRAY_END(ALLOWED_RESULTS), result) == DE_FALSE) + { + static const StringTemplate ERROR_MSG = {"Pipeline creation returned an error result: ${0}"}; + TCU_THROW(InternalError, ERROR_MSG.format(result).c_str()); + } + + for (const auto& validator : validators) + { + const auto qpResult = validator(result, pipelines, elapsed, reason); + if (qpResult != QP_TEST_RESULT_PASS) + { + return {qpResult, reason}; + } + } + + return TestStatus::pass("Test passed."); +} + +/*--------------------------------------------------------------------*//*! + * \brief Generate an error if result does not match VK_RESULT + *//*--------------------------------------------------------------------*/ +template +qpTestResult checkResult(VkResult result, const vector&, duration, string& reason) +{ + if (VK_RESULT != result) + { + static const StringTemplate ERROR_MSG = {"Got ${0}, Expected ${1}"}; + reason = ERROR_MSG.format(result, VK_RESULT); + return FAIL_RESULT; + } + + return QP_TEST_RESULT_PASS; +} + +/*--------------------------------------------------------------------*//*! + * \brief Generate an error if pipeline[INDEX] is not valid + *//*--------------------------------------------------------------------*/ +template +qpTestResult checkPipelineMustBeValid(VkResult, const vector& pipelines, duration, string& reason) +{ + if (pipelines.size() <= INDEX) + { + static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; + TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); + } + + if (*pipelines[INDEX] == VK_NULL_HANDLE) + { + static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not a valid VkPipeline object"}; + reason = ERROR_MSG.format(INDEX); + return FAIL_RESULT; + } + + return QP_TEST_RESULT_PASS; +} + +/*--------------------------------------------------------------------*//*! + * \brief Generate an error if pipeline[INDEX] is not VK_NULL_HANDLE + *//*--------------------------------------------------------------------*/ +template +qpTestResult checkPipelineMustBeNull(VkResult, const vector& pipelines, duration, string& reason) +{ + if (pipelines.size() <= INDEX) + { + static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; + TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); + } + + if (*pipelines[INDEX] != VK_NULL_HANDLE) + { + static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not VK_NULL_HANDLE"}; + reason = ERROR_MSG.format(INDEX); + return FAIL_RESULT; + } + + return QP_TEST_RESULT_PASS; +} + +/*--------------------------------------------------------------------*//*! + * \brief Generate an error if any pipeline is valid after an early-return failure + *//*--------------------------------------------------------------------*/ +template +qpTestResult checkPipelineNullAfterIndex(VkResult, const vector& pipelines, duration, string& reason) +{ + if (pipelines.size() <= INDEX) + { + static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; + TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); + } + + if (pipelines.size() - 1 == INDEX) + { + static const StringTemplate ERROR_MSG = {"Index ${0} is the last pipeline, likely a malformed test case"}; + TCU_THROW(TestError, ERROR_MSG.format(INDEX)); + } + + // Only have to iterate through if the requested index is null + if (*pipelines[INDEX] == VK_NULL_HANDLE) + { + for (size_t i = INDEX + 1; i < pipelines.size(); ++i) + { + if (*pipelines[i] != VK_NULL_HANDLE) + { + static const StringTemplate ERROR_MSG = { + "pipelines[${0}] is not VK_NULL_HANDLE after a explicit early return index"}; + reason = ERROR_MSG.format(i); + return FAIL_RESULT; + } + } + } + + return QP_TEST_RESULT_PASS; +} + +/*--------------------------------------------------------------------*//*! + * Time limit constants + *//*--------------------------------------------------------------------*/ +enum ElapsedTime +{ + ELAPSED_TIME_INFINITE = microseconds{-1}.count(), + ELAPSED_TIME_IMMEDIATE = microseconds{500}.count(), + ELAPSED_TIME_FAST = microseconds{1000}.count() +}; + +/*--------------------------------------------------------------------*//*! + * \brief Generate an error if elapsed time exceeds MAX_TIME + *//*--------------------------------------------------------------------*/ +template +qpTestResult checkElapsedTime(VkResult, const vector&, duration elapsed, string& reason) +{ +#if defined(DE_DEBUG) + DE_UNREF(elapsed); + DE_UNREF(reason); + + // In debug mode timing is not likely to be accurate + return QP_TEST_RESULT_PASS; +#else + + using ::std::chrono::duration_cast; + + static constexpr microseconds ALLOWED_TIME = microseconds{MAX_TIME}; + + if (elapsed > ALLOWED_TIME) + { + static const StringTemplate ERROR_MSG = {"pipeline creation took longer than ${0}us (actual time: ${1}us)"}; + reason = ERROR_MSG.format(ALLOWED_TIME.count(), duration_cast(elapsed).count()); + return FAIL_RESULT; + } + + return QP_TEST_RESULT_PASS; +#endif +} + +/*--------------------------------------------------------------------*//*! + * \brief Test case parameters + *//*--------------------------------------------------------------------*/ +struct TestParams +{ + enum CacheType + { + NO_CACHE = 0, + EXPLICIT_CACHE, + DERIVATIVE_HANDLE, + DERIVATIVE_INDEX + }; + + struct Iteration + { + static constexpr size_t MAX_VARIANTS = 4; + using Variant = VkPipelineCreateFlags; + using VariantArray = ConstexprVector; + + static constexpr Variant NORMAL = 0; + static constexpr Variant NO_COMPILE = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT; + static constexpr Variant EARLY_RETURN = NO_COMPILE | VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT; + + static constexpr VariantArray SINGLE_NORMAL = VariantArray{NORMAL}; + static constexpr VariantArray SINGLE_NOCOMPILE = VariantArray{NO_COMPILE}; + static constexpr VariantArray BATCH_NOCOMPILE_COMPILE_NOCOMPILE = VariantArray{NO_COMPILE, NORMAL, NO_COMPILE}; + static constexpr VariantArray BATCH_RETURN_COMPILE_NOCOMPILE = VariantArray{EARLY_RETURN, NORMAL, NO_COMPILE}; + + inline constexpr Iteration() : variants{}, validators{} {}; + inline constexpr Iteration(const VariantArray& v, const ValidatorArray& f) : variants{v}, validators{f} {}; + + VariantArray variants; + ValidatorArray validators; + }; + + static constexpr size_t MAX_ITERATIONS = 4; + using IterationArray = ConstexprVector; + + const char* name; + const char* description; + CacheType cacheType; + IterationArray iterations; +}; + +/*--------------------------------------------------------------------*//*! + * \brief Verify extension and feature support + *//*--------------------------------------------------------------------*/ +void checkSupport(Context& context, const TestParams&) +{ + static constexpr char EXT_NAME[] = "VK_EXT_pipeline_creation_cache_control"; + if (!context.requireDeviceFunctionality(EXT_NAME)) + { + TCU_THROW(NotSupportedError, "Extension 'VK_EXT_pipeline_creation_cache_control' is not supported"); + } + + const auto features = context.getPipelineCreationCacheControlFeaturesEXT(); + if (features.pipelineCreationCacheControl == DE_FALSE) + { + TCU_THROW(NotSupportedError, "Feature 'pipelineCreationCacheControl' is not enabled"); + } +} + +/*--------------------------------------------------------------------*//*! + * \brief Generate a random floating point number as a string + *//*--------------------------------------------------------------------*/ +float randomFloat() +{ +#if !defined(DE_DEBUG) + static de::Random state = {::std::random_device{}()}; +#else + static de::Random state = {0xDEADBEEF}; +#endif + + return state.getFloat(); +} + +/*--------------------------------------------------------------------*//*! + * \brief Get a string of VkResults from a vector + *//*--------------------------------------------------------------------*/ +string getResultsString(const vector& results) +{ + using ::std::ostringstream; + + ostringstream output; + + output << "results[" << results.size() << "]={ "; + + if (!results.empty()) + { + output << results[0]; + } + + for (size_t i = 1; i < results.size(); ++i) + { + output << ", " << results[i]; + } + + output << " }"; + + return output.str(); +} + +/*--------------------------------------------------------------------*//*! + * \brief Cast a pointer to an the expected SPIRV type + *//*--------------------------------------------------------------------*/ +template +inline const deUint32* shader_cast(const _t* ptr) +{ + return reinterpret_cast(ptr); +} + +/*--------------------------------------------------------------------*//*! + * \brief Capture a container of Vulkan handles into Move<> types + *//*--------------------------------------------------------------------*/ +template , + typename deleter_t = Deleter, + typename output_t = vector> +output_t wrapHandles(const DeviceInterface& vk, + VkDevice device, + const input_container_t& input, + const VkAllocationCallbacks* allocator = DE_NULL) +{ + using ::std::begin; + using ::std::end; + using ::std::transform; + + auto output = output_t{}; + output.resize(input.size()); + + struct Predicate + { + deleter_t deleter; + move_t operator()(handle_t v) + { + return (v != VK_NULL_HANDLE) ? move_t{check(v), deleter} : move_t{}; + } + }; + + const auto wrapHandle = Predicate{deleter_t{vk, device, allocator}}; + + transform(begin(input), end(input), begin(output), wrapHandle); + + return output; +} + +/*--------------------------------------------------------------------*//*! + * \brief create vkPipelineCache for test params + *//*--------------------------------------------------------------------*/ +Move createPipelineCache(const DeviceInterface& vk, VkDevice device, const TestParams& params) +{ + if (params.cacheType != TestParams::EXPLICIT_CACHE) + { + return {}; + } + + static constexpr auto cacheInfo = VkPipelineCacheCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, //sType + DE_NULL, //pNext + VkPipelineCacheCreateFlags{}, //flags + deUintptr{0}, //initialDataSize + DE_NULL //pInitialData + }; + + return createPipelineCache(vk, device, &cacheInfo); +} + +/*--------------------------------------------------------------------*//*! + * \brief create VkPipelineLayout with descriptor sets from test parameters + *//*--------------------------------------------------------------------*/ +Move createPipelineLayout(const DeviceInterface& vk, + VkDevice device, + const vector& setLayouts, + const TestParams&) +{ + const auto layoutCreateInfo = VkPipelineLayoutCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineLayoutCreateFlags{}, // flags + static_cast(setLayouts.size()), // setLayoutCount + setLayouts.data(), // pSetLayouts + deUint32{0u}, // pushConstantRangeCount + DE_NULL, // pPushConstantRanges + }; + + return createPipelineLayout(vk, device, &layoutCreateInfo); +} + +/*--------------------------------------------------------------------*//*! + * \brief create basic VkPipelineLayout from test parameters + *//*--------------------------------------------------------------------*/ +Move createPipelineLayout(const DeviceInterface& vk, VkDevice device, const TestParams&) +{ + static constexpr auto layoutCreateInfo = VkPipelineLayoutCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineLayoutCreateFlags{}, // flags + deUint32{0u}, // setLayoutCount + DE_NULL, // pSetLayouts + deUint32{0u}, // pushConstantRangeCount + DE_NULL, // pPushConstantRanges + }; + + return createPipelineLayout(vk, device, &layoutCreateInfo); +} + +/*--------------------------------------------------------------------*//*! + * \brief Create array of shader modules + *//*--------------------------------------------------------------------*/ +vector createShaderModules(const DeviceInterface& vk, + VkDevice device, + const BinaryCollection& collection, + const vector& names) +{ + auto output = vector{}; + output.reserve(names.size()); + + for (const auto& name : names) + { + const auto& binary = collection.get(name); + const auto createInfo = VkShaderModuleCreateInfo{ + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType + DE_NULL, // pNext + VkShaderModuleCreateFlags{}, // flags + binary.getSize(), // codeSize + shader_cast(binary.getBinary()) // pCode + }; + + output.push_back(createShaderModule(vk, device, &createInfo)); + } + + return output; +} + +/*--------------------------------------------------------------------*//*! + * \brief Create array of shader binding stages + *//*--------------------------------------------------------------------*/ +vector createShaderStages(const vector>& modules, + const vector& stages) +{ + DE_ASSERT(modules.size() == stages.size()); + + auto output = vector{}; + output.reserve(modules.size()); + + int i = 0; + + for (const auto& module : modules) + { + const auto stageInfo = VkPipelineShaderStageCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineShaderStageCreateFlags{}, // flags + stages[i++], // stage + *module, // module + "main", // pName + DE_NULL // pSpecializationInfo + }; + + output.push_back(stageInfo); + } + + return output; +} + +} // namespace test_common + +/*--------------------------------------------------------------------*//*! + * \brief Graphics pipeline specific testing + *//*--------------------------------------------------------------------*/ +namespace graphics_tests +{ +using namespace test_common; + +/*--------------------------------------------------------------------*//*! + * \brief Common graphics pipeline create info initialization + *//*--------------------------------------------------------------------*/ +VkGraphicsPipelineCreateInfo getPipelineCreateInfoCommon() +{ + static constexpr auto VERTEX_BINDING = VkVertexInputBindingDescription{ + deUint32{0u}, // binding + sizeof(float[4]), // stride + VK_VERTEX_INPUT_RATE_VERTEX // inputRate + }; + + static constexpr auto VERTEX_ATTRIBUTE = VkVertexInputAttributeDescription{ + deUint32{0u}, // location + deUint32{0u}, // binding + VK_FORMAT_R32G32B32A32_SFLOAT, // format + deUint32{0u} // offset + }; + + static constexpr auto VERTEX_INPUT_STATE = VkPipelineVertexInputStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineVertexInputStateCreateFlags{}, // flags + deUint32{1u}, // vertexBindingDescriptionCount + &VERTEX_BINDING, // pVertexBindingDescriptions + deUint32{1u}, // vertexAttributeDescriptionCount + &VERTEX_ATTRIBUTE // pVertexAttributeDescriptions + }; + + static constexpr auto IA_STATE = VkPipelineInputAssemblyStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineInputAssemblyStateCreateFlags{}, // flags + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // topology + VK_TRUE // primitiveRestartEnable + }; + + static constexpr auto TESSALATION_STATE = VkPipelineTessellationStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineTessellationStateCreateFlags{}, // flags + deUint32{0u} // patchControlPoints + }; + + static constexpr auto VIEWPORT = VkViewport{ + 0.f, // x + 0.f, // y + 1.f, // width + 1.f, // height + 0.f, // minDepth + 1.f // maxDept + }; + + static constexpr auto SCISSOR_RECT = VkRect2D{ + {0, 0}, // offset + {256, 256} // extent + }; + + static constexpr auto VIEWPORT_STATE = VkPipelineViewportStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineViewportStateCreateFlags{}, // flags + deUint32{1u}, // viewportCount + &VIEWPORT, // pViewports + deUint32{1u}, // scissorCount + &SCISSOR_RECT // pScissors + }; + + static constexpr auto RASTERIZATION_STATE = VkPipelineRasterizationStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineRasterizationStateCreateFlags{}, // flags + VK_TRUE, // depthClampEnable + VK_TRUE, // rasterizerDiscardEnable + VK_POLYGON_MODE_FILL, // polygonMode + VK_CULL_MODE_NONE, // cullMode + VK_FRONT_FACE_CLOCKWISE, // frontFace + VK_FALSE, // depthBiasEnable + 0.f, // depthBiasConstantFactor + 0.f, // depthBiasClamp + 0.f, // depthBiasSlopeFactor + 1.f // lineWidth + }; + + static constexpr auto SAMPLE_MASK = VkSampleMask{}; + + static constexpr auto MULTISAMPLE_STATE = VkPipelineMultisampleStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineMultisampleStateCreateFlags{}, // flags + VK_SAMPLE_COUNT_1_BIT, // rasterizationSamples + VK_FALSE, // sampleShadingEnable + 0.f, // minSampleShading + &SAMPLE_MASK, // pSampleMask + VK_FALSE, // alphaToCoverageEnable + VK_FALSE // alphaToOneEnable + }; + + static constexpr auto STENCIL_OP_STATE = VkStencilOpState{ + VK_STENCIL_OP_ZERO, // failOp + VK_STENCIL_OP_ZERO, // passOp + VK_STENCIL_OP_ZERO, // depthFailOp + VK_COMPARE_OP_ALWAYS, // compareOp + deUint32{0u}, // compareMask + deUint32{0u}, // writeMask + deUint32{0u} // reference + }; + + static constexpr auto DEPTH_STENCIL_STATE = VkPipelineDepthStencilStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineDepthStencilStateCreateFlags{}, // flags + VK_FALSE, // depthTestEnable + VK_FALSE, // depthWriteEnable + VK_COMPARE_OP_ALWAYS, // depthCompareOp + VK_FALSE, // depthBoundsTestEnable + VK_FALSE, // stencilTestEnable + STENCIL_OP_STATE, // front + STENCIL_OP_STATE, // back + 0.f, // minDepthBounds + 1.f // maxDepthBounds + }; + + static constexpr auto COLOR_FLAGS_ALL = VkColorComponentFlags{VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT}; + + static constexpr auto COLOR_BLEND_ATTACH_STATE = VkPipelineColorBlendAttachmentState{ + VK_FALSE, // blendEnable + VK_BLEND_FACTOR_ONE, // srcColorBlendFactor + VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor + VK_BLEND_OP_ADD, // colorBlendOp + VK_BLEND_FACTOR_ONE, // srcAlphaBlendFactor + VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor + VK_BLEND_OP_ADD, // alphaBlendOp + COLOR_FLAGS_ALL // colorWriteMask + }; + + static constexpr auto COLOR_BLEND_STATE = VkPipelineColorBlendStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineColorBlendStateCreateFlags{}, // flags + VK_FALSE, // logicOpEnable + VK_LOGIC_OP_SET, // logicOp + deUint32{1u}, // attachmentCount + &COLOR_BLEND_ATTACH_STATE, // pAttachments + {0.f, 0.f, 0.f, 0.f} // blendConstants[4] + }; + + static constexpr auto DYNAMIC_STATE = VkPipelineDynamicStateCreateInfo{ + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType; + DE_NULL, // pNext; + VkPipelineDynamicStateCreateFlags{}, // flags; + deUint32{0u}, // dynamicStateCount; + DE_NULL // pDynamicStates; + }; + + return VkGraphicsPipelineCreateInfo{ + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineCreateFlags{}, // flags + deUint32{0u}, // stageCount + DE_NULL, // pStages + &VERTEX_INPUT_STATE, // pVertexInputState + &IA_STATE, // pInputAssemblyState + &TESSALATION_STATE, // pTessellationState + &VIEWPORT_STATE, // pViewportState + &RASTERIZATION_STATE, // pRasterizationState + &MULTISAMPLE_STATE, // pMultisampleState + &DEPTH_STENCIL_STATE, // pDepthStencilState + &COLOR_BLEND_STATE, // pColorBlendState + &DYNAMIC_STATE, // pDynamicState + VK_NULL_HANDLE, // layout + VK_NULL_HANDLE, // renderPass + deUint32{0u}, // subpass + VK_NULL_HANDLE, // basePipelineHandle + deInt32{-1} // basePipelineIndex + }; +} + +/*--------------------------------------------------------------------*//*! + * \brief create VkGraphicsPipelineCreateInfo structs from test iteration + *//*--------------------------------------------------------------------*/ +vector createPipelineCreateInfos(const TestParams::Iteration& iteration, + const VkGraphicsPipelineCreateInfo& base, + VkPipeline basePipeline, + const TestParams& testParameter) +{ + auto output = vector{}; + output.reserve(iteration.variants.size()); + + deInt32 count = 0; + deInt32 basePipelineIndex = -1; + + for (VkPipelineCreateFlags flags : iteration.variants) + { + const auto curIndex = count++; + auto createInfo = base; + + if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX) + { + if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) + { + if (basePipelineIndex != -1) + { + flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT; + } + } + else + { + flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; + + if (basePipelineIndex == -1) + { + basePipelineIndex = curIndex; + } + } + } + + createInfo.flags = flags; + createInfo.basePipelineHandle = basePipeline; + createInfo.basePipelineIndex = basePipelineIndex; + + output.push_back(createInfo); + } + + return output; +} + +/*--------------------------------------------------------------------*//*! + * \brief create VkRenderPass object for Graphics test + *//*--------------------------------------------------------------------*/ +Move createRenderPass(const DeviceInterface& vk, VkDevice device, const TestParams&) +{ + static constexpr auto COLOR_FORMAT = VK_FORMAT_R8G8B8_UNORM; + + static constexpr auto COLOR_ATTACHMENT_REF = VkAttachmentReference{ + deUint32{0u}, // attachment + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // layout + }; + + static constexpr auto SUBPASS = VkSubpassDescription{ + VkSubpassDescriptionFlags{}, // flags + VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint + deUint32{0u}, // inputAttachmentCount + DE_NULL, // pInputAttachments + deUint32{1u}, // colorAttachmentCount + &COLOR_ATTACHMENT_REF, // pColorAttachments + DE_NULL, // pResolveAttachments + DE_NULL, // pDepthStencilAttachment + deUint32{0u}, // preserveAttachmentCount + DE_NULL // pPreserveAttachments + }; + + static constexpr auto COLOR_ATTACHMENT = VkAttachmentDescription{ + VkAttachmentDescriptionFlags{}, // flags + COLOR_FORMAT, // format + VK_SAMPLE_COUNT_1_BIT, // samples + VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp + VK_ATTACHMENT_STORE_OP_STORE, // storeOp + VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp + VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp + VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // finalLayout + }; + + static constexpr auto RENDER_PASS_CREATE_INFO = VkRenderPassCreateInfo{ + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType + DE_NULL, // pNext + VkRenderPassCreateFlags{}, // flags + deUint32{1u}, // attachmentCount + &COLOR_ATTACHMENT, // pAttachments + deUint32{1u}, // subpassCount + &SUBPASS, // pSubpasses + deUint32{0u}, // dependencyCount + DE_NULL // pDependencies + }; + + return createRenderPass(vk, device, &RENDER_PASS_CREATE_INFO); +} + +/*--------------------------------------------------------------------*//*! + * \brief Initialize shader programs + *//*--------------------------------------------------------------------*/ +void initPrograms(SourceCollections& dst, const TestParams&) +{ + using ::glu::FragmentSource; + using ::glu::VertexSource; + + // Vertex Shader + static const StringTemplate VS_TEXT = {"#version 310 es\n" + "layout(location = 0) in vec4 position;\n" + "layout(location = 0) out vec3 vertColor;\n" + "void main (void)\n" + "{\n" + " gl_Position = position;\n" + " vertColor = vec3(${0}, ${1}, ${2});\n" + "}\n"}; + + // Fragment Shader + static const StringTemplate FS_TEXT = {"#version 310 es\n" + "precision highp float;\n" + "layout(location = 0) in vec3 vertColor;\n" + "layout(location = 0) out vec4 outColor;\n" + "void main (void)\n" + "{\n" + " const vec3 fragColor = vec3(${0}, ${1}, ${2});\n" + " outColor = vec4((fragColor + vertColor) * 0.5, 1.0);\n" + "}\n"}; + + dst.glslSources.add("vertex") << VertexSource{VS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; + dst.glslSources.add("fragment") << FragmentSource{FS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; +} + +/*--------------------------------------------------------------------*//*! + * \brief return both result and elapsed time from pipeline creation + *//*--------------------------------------------------------------------*/ +template +TimedResult timePipelineCreation(const DeviceInterface& vk, + const VkDevice device, + const VkPipelineCache cache, + const create_infos_t& createInfos, + pipelines_t& pipelines, + const VkAllocationCallbacks* pAllocator = DE_NULL) +{ + DE_ASSERT(createInfos.size() <= pipelines.size()); + + const auto timeStart = high_resolution_clock::now(); + const auto result = vk.createGraphicsPipelines( + device, cache, static_cast(createInfos.size()), createInfos.data(), pAllocator, pipelines.data()); + const auto elapsed = high_resolution_clock::now() - timeStart; + return {result, elapsed}; +} + +/*--------------------------------------------------------------------*//*! + * \brief Test instance function + *//*--------------------------------------------------------------------*/ +TestStatus testInstance(Context& context, const TestParams& testParameter) +{ + const auto& vk = context.getDeviceInterface(); + const auto device = context.getDevice(); + const auto pipelineCache = createPipelineCache(vk, device, testParameter); + const auto layout = createPipelineLayout(vk, device, testParameter); + const auto renderPass = createRenderPass(vk, device, testParameter); + const auto modules = createShaderModules(vk, device, context.getBinaryCollection(), {"vertex", "fragment"}); + const auto shaderStages = createShaderStages(modules, {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}); + + // Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE + auto basePipeline = UniquePipeline{}; + + auto baseCreateInfo = getPipelineCreateInfoCommon(); + baseCreateInfo.layout = layout.get(); + baseCreateInfo.renderPass = renderPass.get(); + baseCreateInfo.stageCount = static_cast(shaderStages.size()); + baseCreateInfo.pStages = shaderStages.data(); + + auto results = vector{}; + results.reserve(testParameter.iterations.size()); + + for (const auto& i : testParameter.iterations) + { + const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter); + auto created = vector{}; + created.resize(createInfos.size()); + + const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created); + auto pipelines = wrapHandles(vk, device, created); + + const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators); + if (status.getCode() != QP_TEST_RESULT_PASS) + { + return status; + } + + if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE)) + { + for (auto& pipeline : pipelines) + { + if (*pipeline != VK_NULL_HANDLE) + { + basePipeline = pipeline; + break; + } + } + } + + results.push_back(timedResult.result); + } + + static const StringTemplate PASS_MSG = {"Test Passed. ${0}"}; + return TestStatus::pass(PASS_MSG.format(getResultsString(results))); +} + +} // namespace graphics_tests + +/*--------------------------------------------------------------------*//*! + * \brief Compute pipeline specific testing + *//*--------------------------------------------------------------------*/ +namespace compute_tests +{ +using namespace test_common; + +/*--------------------------------------------------------------------*//*! + * \brief create VkComputePipelineCreateInfo structs from test iteration + *//*--------------------------------------------------------------------*/ +vector createPipelineCreateInfos(const TestParams::Iteration& iteration, + const VkComputePipelineCreateInfo& base, + VkPipeline basePipeline, + const TestParams& testParameter) +{ + auto output = vector{}; + output.reserve(iteration.variants.size()); + + deInt32 count = 0; + deInt32 basePipelineIndex = -1; + + for (VkPipelineCreateFlags flags : iteration.variants) + { + const auto curIndex = count++; + auto createInfo = base; + + if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX) + { + if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) + { + if (basePipelineIndex != -1) + { + flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT; + } + } + else + { + flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; + + if (basePipelineIndex == -1) + { + basePipelineIndex = curIndex; + } + } + } + + createInfo.flags = flags; + createInfo.basePipelineHandle = basePipeline; + createInfo.basePipelineIndex = basePipelineIndex; + + output.push_back(createInfo); + } + + return output; +} + +/*--------------------------------------------------------------------*//*! + * \brief create compute descriptor set layout + *//*--------------------------------------------------------------------*/ +Move createDescriptorSetLayout(const DeviceInterface& vk, VkDevice device, const TestParams&) +{ + static constexpr auto DESCRIPTOR_SET_LAYOUT_BINDING = VkDescriptorSetLayoutBinding{ + deUint32{0u}, // binding + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptorType + deUint32{1u}, // descriptorCount + VK_SHADER_STAGE_COMPUTE_BIT, // stageFlags + DE_NULL // pImmutableSamplers + }; + + static constexpr auto DESCRIPTOR_SET_LAYOUT_CREATE_INFO = VkDescriptorSetLayoutCreateInfo{ + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType + DE_NULL, // pNext + VkDescriptorSetLayoutCreateFlags{}, // flags + deUint32{1u}, // bindingCount + &DESCRIPTOR_SET_LAYOUT_BINDING // pBindings + }; + + return createDescriptorSetLayout(vk, device, &DESCRIPTOR_SET_LAYOUT_CREATE_INFO); +} + +/*--------------------------------------------------------------------*//*! + * \brief Initialize shader programs + *//*--------------------------------------------------------------------*/ +void initPrograms(SourceCollections& dst, const TestParams&) +{ + using ::glu::ComputeSource; + + static const StringTemplate CS_TEXT = {"#version 450\n" + "precision highp float;\n" + "layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;\n" + "layout (std140, binding = 0) buffer buf { vec3 data[]; };\n" + "void main (void)\n" + "{\n" + " data[gl_GlobalInvocationID.x] = vec3(${0}, ${1}, ${2});\n" + "}\n"}; + + dst.glslSources.add("compute") + << ComputeSource{CS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; +} + +/*--------------------------------------------------------------------*//*! + * \brief return both result and elapsed time from pipeline creation + *//*--------------------------------------------------------------------*/ +template +TimedResult timePipelineCreation(const DeviceInterface& vk, + const VkDevice device, + const VkPipelineCache cache, + const create_infos_t& createInfos, + pipelines_t& pipelines, + const VkAllocationCallbacks* pAllocator = DE_NULL) +{ + DE_ASSERT(createInfos.size() <= pipelines.size()); + + const auto timeStart = high_resolution_clock::now(); + const auto result = vk.createComputePipelines( + device, cache, static_cast(createInfos.size()), createInfos.data(), pAllocator, pipelines.data()); + const auto elapsed = high_resolution_clock::now() - timeStart; + return {result, elapsed}; +} + +/*--------------------------------------------------------------------*//*! + * \brief Test instance function + *//*--------------------------------------------------------------------*/ +TestStatus testInstance(Context& context, const TestParams& testParameter) +{ + const auto& vk = context.getDeviceInterface(); + const auto device = context.getDevice(); + const auto pipelineCache = createPipelineCache(vk, device, testParameter); + const auto descriptorSetLayout = createDescriptorSetLayout(vk, device, testParameter); + const auto pipelineLayout = createPipelineLayout(vk, device, {descriptorSetLayout.get()}, testParameter); + const auto modules = createShaderModules(vk, device, context.getBinaryCollection(), {"compute"}); + const auto shaderStages = createShaderStages(modules, {VK_SHADER_STAGE_COMPUTE_BIT}); + + // Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE + auto basePipeline = UniquePipeline{}; + + const auto baseCreateInfo = VkComputePipelineCreateInfo{ + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType + DE_NULL, // pNext + VkPipelineCreateFlags{}, // flags + shaderStages[0], // stage + pipelineLayout.get(), // layout + VK_NULL_HANDLE, // basePipelineHandle + deInt32{-1} // basePipelineIndex + }; + + auto results = vector{}; + results.reserve(testParameter.iterations.size()); + + for (const auto& i : testParameter.iterations) + { + const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter); + auto created = vector{}; + created.resize(createInfos.size()); + + const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created); + auto pipelines = wrapHandles(vk, device, created); + + const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators); + if (status.getCode() != QP_TEST_RESULT_PASS) + { + return status; + } + + if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE)) + { + for (auto& pipeline : pipelines) + { + if (*pipeline != VK_NULL_HANDLE) + { + basePipeline = pipeline; + break; + } + } + } + + results.push_back(timedResult.result); + } + + static const StringTemplate PASS_MSG = {"Test Passed. ${0}"}; + return TestStatus::pass(PASS_MSG.format(getResultsString(results))); +} + +} // namespace compute_tests + +using namespace test_common; + +// Disable formatting on this next block for readability +// clang-format off +/*--------------------------------------------------------------------*//*! + * \brief Duplicate single pipeline recreation with explicit caching + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING = +{ + "duplicate_single_recreate_explicit_caching", + "Duplicate single pipeline recreation with explicit caching", + TestParams::EXPLICIT_CACHE, + TestParams::IterationArray + { + TestParams::Iteration{ + // Iteration [0]: Force compilation of pipeline + TestParams::Iteration::SINGLE_NORMAL, + ValidatorArray{ + // Fail if result is not VK_SUCCESS + checkResult, + // Fail if pipeline is not valid + checkPipelineMustBeValid<0> + } + }, + TestParams::Iteration{ + // Iteration [1]: Request compilation of same pipeline without compile + TestParams::Iteration::SINGLE_NOCOMPILE, + ValidatorArray{ + // Warn if result is not VK_SUCCESS + checkResult, + // Warn if pipeline is not valid + checkPipelineMustBeValid<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, + // Warn if pipeline took too long + checkElapsedTime + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Duplicate single pipeline recreation with no explicit cache + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_SINGLE_RECREATE_NO_CACHING = +{ + "duplicate_single_recreate_no_caching", + "Duplicate single pipeline recreation with no explicit cache", + TestParams::NO_CACHE, + TestParams::IterationArray{ + TestParams::Iteration{ + // Iteration [0]: Force compilation of pipeline + TestParams::Iteration::SINGLE_NORMAL, + ValidatorArray{ + // Fail if result is not VK_SUCCESS + checkResult, + // Fail if pipeline is not valid + checkPipelineMustBeValid<0> + } + }, + TestParams::Iteration{ + // Iteration [1]: Request compilation of same pipeline without compile + TestParams::Iteration::SINGLE_NOCOMPILE, + ValidatorArray{ + // Warn if pipeline took too long + checkElapsedTime + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Duplicate single pipeline recreation using derivative pipelines + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_SINGLE_RECREATE_DERIVATIVE = +{ + "duplicate_single_recreate_derivative", + "Duplicate single pipeline recreation using derivative pipelines", + TestParams::DERIVATIVE_HANDLE, + TestParams::IterationArray{ + TestParams::Iteration{ + // Iteration [0]: Force compilation of pipeline + TestParams::Iteration::SINGLE_NORMAL, + ValidatorArray{ + // Fail if result is not VK_SUCCESS + checkResult, + // Fail if pipeline is not valid + checkPipelineMustBeValid<0> + } + }, + TestParams::Iteration{ + // Iteration [1]: Request compilation of same pipeline without compile + TestParams::Iteration::SINGLE_NOCOMPILE, + ValidatorArray{ + // Warn if pipeline took too long + checkElapsedTime + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Single creation of never before seen pipeline without compile + *//*--------------------------------------------------------------------*/ +static constexpr TestParams SINGLE_PIPELINE_NO_COMPILE = +{ + "single_pipeline_no_compile", + "Single creation of never before seen pipeline without compile", + TestParams::NO_CACHE, + TestParams::IterationArray{ + TestParams::Iteration{ + TestParams::Iteration::SINGLE_NOCOMPILE, + ValidatorArray{ + // Warn if pipeline took too long + checkElapsedTime + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Batch creation of duplicate pipelines with explicit caching + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE = +{ + "duplicate_batch_pipelines_explicit_cache", + "Batch creation of duplicate pipelines with explicit caching", + TestParams::EXPLICIT_CACHE, + TestParams::IterationArray{ + TestParams::Iteration{ + TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, + ValidatorArray{ + // Fail if pipeline[1] is not valid + checkPipelineMustBeValid<1>, + // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT + checkResult, + // Warn if pipelines[0] is not VK_NULL_HANDLE + checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, + // Warn if pipelines[2] is not valid + checkPipelineMustBeValid<2, QP_TEST_RESULT_COMPATIBILITY_WARNING> + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Batch creation of duplicate pipelines with no caching + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_BATCH_PIPELINES_NO_CACHE = +{ + "duplicate_batch_pipelines_no_cache", + "Batch creation of duplicate pipelines with no caching", + TestParams::EXPLICIT_CACHE, + TestParams::IterationArray{ + TestParams::Iteration{ + TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, + ValidatorArray{ + // Fail if pipeline[1] is not valid + checkPipelineMustBeValid<1>, + // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT + checkResult, + // Warn if pipelines[0] is not VK_NULL_HANDLE + checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING> + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Batch creation of duplicate pipelines with derivative pipeline index + *//*--------------------------------------------------------------------*/ +static constexpr TestParams DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX = +{ + "duplicate_batch_pipelines_derivative_index", + "Batch creation of duplicate pipelines with derivative pipeline index", + TestParams::DERIVATIVE_INDEX, + TestParams::IterationArray{ + TestParams::Iteration{ + TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, + ValidatorArray{ + // Fail if pipeline[1] is not valid + checkPipelineMustBeValid<1>, + // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT + checkResult, + // Warn if pipelines[0] is not VK_NULL_HANDLE + checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING> + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Batch creation of pipelines with early return + *//*--------------------------------------------------------------------*/ +static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN = +{ + "batch_pipelines_early_return", + "Batch creation of pipelines with early return", + TestParams::NO_CACHE, + TestParams::IterationArray{ + TestParams::Iteration{ + TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE, + ValidatorArray{ + // fail if a valid pipeline follows the early-return failure + checkPipelineNullAfterIndex<0>, + // Warn if return was not immediate + checkElapsedTime, + // Warn if pipelines[0] is not VK_NULL_HANDLE + checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, + // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT + checkResult + } + } + } +}; + +/*--------------------------------------------------------------------*//*! + * \brief Full array of test cases + *//*--------------------------------------------------------------------*/ +static constexpr TestParams TEST_CASES[] = +{ + SINGLE_PIPELINE_NO_COMPILE, + BATCH_PIPELINES_EARLY_RETURN, + DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING, + DUPLICATE_SINGLE_RECREATE_NO_CACHING, + DUPLICATE_SINGLE_RECREATE_DERIVATIVE, + DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE, + DUPLICATE_BATCH_PIPELINES_NO_CACHE, + DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX +}; +// clang-format on + +/*--------------------------------------------------------------------*//*! + * \brief Variadic version of de::newMovePtr + *//*--------------------------------------------------------------------*/ +template +inline de::MovePtr newMovePtr(args_t&&... args) +{ + return de::MovePtr(new T(::std::forward(args)...)); +} + +/*--------------------------------------------------------------------*//*! + * \brief Make test group consisting of graphics pipeline tests + *//*--------------------------------------------------------------------*/ +void addGraphicsPipelineTests(TestCaseGroup& group) +{ + using namespace graphics_tests; + + auto tests = newMovePtr( + group.getTestContext(), "graphics_pipelines", "Test pipeline creation cache control with graphics pipelines"); + + for (const auto& params : TEST_CASES) + { + addFunctionCaseWithPrograms( + tests.get(), params.name, params.description, checkSupport, initPrograms, testInstance, params); + } + + group.addChild(tests.release()); +} + +/*--------------------------------------------------------------------*//*! + * \brief Make test group consisting of compute pipeline tests + *//*--------------------------------------------------------------------*/ +void addComputePipelineTests(TestCaseGroup& group) +{ + using namespace compute_tests; + + auto tests = newMovePtr( + group.getTestContext(), "compute_pipelines", "Test pipeline creation cache control with compute pipelines"); + + for (const auto& params : TEST_CASES) + { + addFunctionCaseWithPrograms( + tests.get(), params.name, params.description, checkSupport, initPrograms, testInstance, params); + } + + group.addChild(tests.release()); +} + +} // namespace + +/*--------------------------------------------------------------------*//*! + * \brief Make pipeline creation cache control test group + *//*--------------------------------------------------------------------*/ +TestCaseGroup* createCacheControlTests(TestContext& testCtx) +{ + auto tests = newMovePtr(testCtx, "creation_cache_control", "pipeline creation cache control tests"); + + addGraphicsPipelineTests(*tests); + addComputePipelineTests(*tests); + + return tests.release(); +} + +} // namespace pipeline + +} // namespace vkt diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.hpp new file mode 100644 index 0000000..c10707a --- /dev/null +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCreationCacheControlTests.hpp @@ -0,0 +1,39 @@ +#ifndef _VKTPIPELINECREATIONCACHECONTROLTESTS_HPP +#define _VKTPIPELINECREATIONCACHECONTROLTESTS_HPP +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2020 The Khronos Group Inc. + * Copyright (c) 2020, Advanced Micro Devices, Inc. + * + * 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 implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *//*! + * \file + * \brief Pipeline Creation Cache Control Tests + *//*--------------------------------------------------------------------*/ + +#include "vktTestCase.hpp" + +namespace vkt +{ +namespace pipeline +{ + +tcu::TestCaseGroup* createCacheControlTests (tcu::TestContext& testCtx); + +} // pipeline +} // vkt + +#endif // _VKTPIPELINECREATIONCACHECONTROLTESTS_HPP diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp index e00f23f..c5b4f77 100644 --- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp @@ -53,6 +53,7 @@ #include "vktPipelineMaxVaryingsTests.hpp" #include "vktPipelineBlendOperationAdvancedTests.hpp" #include "vktPipelineExtendedDynamicStateTests.hpp" +#include "vktPipelineCreationCacheControlTests.hpp" #include "vktTestGroupUtil.hpp" namespace vkt @@ -97,6 +98,7 @@ void createChildren (tcu::TestCaseGroup* pipelineTests) pipelineTests->addChild(createMaxVaryingsTests (testCtx)); pipelineTests->addChild(createBlendOperationAdvancedTests (testCtx)); pipelineTests->addChild(createExtendedDynamicStateTests (testCtx)); + pipelineTests->addChild(createCacheControlTests (testCtx)); } } // anonymous diff --git a/external/vulkancts/modules/vulkan/util/CMakeLists.txt b/external/vulkancts/modules/vulkan/util/CMakeLists.txt index 1c288d9..64e6bcc 100644 --- a/external/vulkancts/modules/vulkan/util/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/util/CMakeLists.txt @@ -7,6 +7,7 @@ set(DEQP_VK_UTIL_SRCS vktDrawUtil.hpp vktExternalMemoryUtil.cpp vktExternalMemoryUtil.hpp + vktConstexprVectorUtil.hpp ) set(DEQP_VK_UTIL_LIBS diff --git a/external/vulkancts/modules/vulkan/util/vktConstexprVectorUtil.hpp b/external/vulkancts/modules/vulkan/util/vktConstexprVectorUtil.hpp new file mode 100644 index 0000000..792d211 --- /dev/null +++ b/external/vulkancts/modules/vulkan/util/vktConstexprVectorUtil.hpp @@ -0,0 +1,87 @@ +#ifndef _VKTCONSTEXPRVECTORUTIL_HPP +#define _VKTCONSTEXPRVECTORUTIL_HPP +/*------------------------------------------------------------------------ + * Vulkan CTS Framework + * ------------------------ + * + * Copyright (c) 2020 The Khronos Group Inc. + * Copyright (c) 2020 Advanced Micro Devices, Inc. + * + * 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 implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/*! + * \file + * \brief Compile time friendly dynamic sized array with maximum capacity + */ +/*--------------------------------------------------------------------*/ + +#include +#include + +namespace vkt +{ +/*--------------------------------------------------------------------*//*! + * \brief Constexpr compatable vector with checked maximum capacity + * + * \note Unlike std::array, size() and max_size() are different values + * This makes behaviour more similar to that of std::vector. + *//*--------------------------------------------------------------------*/ +template +class ConstexprVector +{ +public: + using value_type = _t; + using size_type = ::std::size_t; + using difference_type = ::std::ptrdiff_t; + using const_reference = const value_type&; + using const_pointer = const value_type*; + using const_iterator = const value_type*; + + inline constexpr ConstexprVector() noexcept : values{}, count{0} {}; + + /*--------------------------------------------------------------------*//*! + * MSVC v140 chokes on this if it is a raw variadic template list. + * By providing a single argument lead for type deduction it seems to fix + * things. Marking constructor as explicit since this effectively becomes + * a single argument constructor. + *//*--------------------------------------------------------------------*/ + template + inline constexpr explicit ConstexprVector(const _arg_t& arg1, const _args_t&... args) noexcept : + values{arg1, args...}, + count{sizeof...(_args_t) + 1} + { + static_assert((sizeof...(_args_t) + 1) <= CAPACITY, "Not enough capacity to store values"); + } + + inline constexpr const_reference at(size_type pos) const noexcept { return values[pos]; } + inline constexpr const_reference operator[](size_type pos) const noexcept { return values[pos]; } + inline constexpr const_reference front() const noexcept { return values[0]; } + inline constexpr const_reference back() const noexcept { return values[count - 1]; } + inline constexpr const_pointer data() const noexcept { return values; } + inline constexpr const_iterator begin() const noexcept { return &values[0]; } + inline constexpr const_iterator cbegin() const noexcept { return &values[0]; } + inline constexpr const_iterator end() const noexcept { return &values[count]; } + inline constexpr const_iterator cend() const noexcept { return &values[count]; } + inline constexpr bool empty() const noexcept { return count == 0; } + inline constexpr size_type size() const noexcept { return count; } + inline constexpr size_type max_size() const noexcept { return CAPACITY; } + +private: + value_type values[CAPACITY]; + size_type count; +}; + +} // namespace vkt + +#endif // _VKTCONSTEXPRVECTORUTIL_HPP diff --git a/external/vulkancts/mustpass/master/vk-default.txt b/external/vulkancts/mustpass/master/vk-default.txt index 7264f49..861660a 100644 --- a/external/vulkancts/mustpass/master/vk-default.txt +++ b/external/vulkancts/mustpass/master/vk-default.txt @@ -325556,6 +325556,22 @@ dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_0_depthfail dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_pass dEQP-VK.pipeline.extended_dynamic_state.two_draws_static.stencil_state_face_both_dual_xt_dec_wrap_clear_0_ref_1_depthfail +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.graphics_pipelines.duplicate_batch_pipelines_derivative_index +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.single_pipeline_no_compile +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.batch_pipelines_early_return +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_explicit_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_no_caching +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_single_recreate_derivative +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_explicit_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_no_cache +dEQP-VK.pipeline.creation_cache_control.compute_pipelines.duplicate_batch_pipelines_derivative_index dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d_base_mip dEQP-VK.binding_model.shader_access.primary_cmd_buf.sampler_mutable.no_access.single_descriptor.1d_base_slice diff --git a/external/vulkancts/scripts/src/mandatory_features.txt b/external/vulkancts/scripts/src/mandatory_features.txt index 49a0181..34a3933 100644 --- a/external/vulkancts/scripts/src/mandatory_features.txt +++ b/external/vulkancts/scripts/src/mandatory_features.txt @@ -41,6 +41,7 @@ VkPhysicalDeviceImagelessFramebufferFeaturesKHR FEATURES ( imagelessFramebuff VkPhysicalDeviceVulkan12Features FEATURES ( imagelessFramebuffer ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" ) VkPhysicalDeviceVulkan12Features FEATURES ( uniformBufferStandardLayout ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" ) VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR FEATURES ( separateDepthStencilLayouts ) REQUIREMENTS ( VK_KHR_separate_depth_stencil_layouts ) +VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT FEATURES ( pipelineCreationCacheControl ) REQUIREMENTS ( VK_EXT_pipeline_creation_cache_control ) VkPhysicalDeviceVulkan12Features FEATURES ( separateDepthStencilLayouts ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" ) VkPhysicalDeviceHostQueryResetFeaturesEXT FEATURES ( hostQueryReset ) REQUIREMENTS ( VK_EXT_host_query_reset ) VkPhysicalDeviceVulkan12Features FEATURES ( hostQueryReset ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" ) diff --git a/framework/common/tcuStringTemplate.hpp b/framework/common/tcuStringTemplate.hpp index 31d6a30..8896f47 100644 --- a/framework/common/tcuStringTemplate.hpp +++ b/framework/common/tcuStringTemplate.hpp @@ -5,6 +5,8 @@ * ---------------------------------------- * * Copyright 2014 The Android Open Source Project + * Copyright (c) 2020 The Khronos Group Inc. + * Copyright (c) 2020 Advanced Micro Devices, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +25,8 @@ * \brief String template class. *//*--------------------------------------------------------------------*/ +#include + #include #include @@ -40,6 +44,9 @@ public: std::string specialize (const std::map& params) const; + template + std::string format (args_t&&... args) const; + private: StringTemplate (const StringTemplate&); // not allowed! StringTemplate& operator= (const StringTemplate&); // not allowed! @@ -47,6 +54,43 @@ private: std::string m_template; } DE_WARN_UNUSED_TYPE; +/*--------------------------------------------------------------------*//*! + * Utility to unpack consecutive arguments into a parameter map + *//*--------------------------------------------------------------------*/ +namespace detail +{ +static constexpr const char* TOKENS[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", + "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", + "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", + "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", + "55", "56", "57", "58", "59", "60", "61", "62", "63"}; + +template +inline void unpackArgs(unpacked_t&) {} + +template +inline void unpackArgs(unpacked_t& unpacked, arg_t&& cur, args_t&&... args) +{ + static_assert(ARG_NUM < DE_LENGTH_OF_ARRAY(TOKENS), + "ARG_NUM must be less than DE_LENGTH_OF_ARRAY(TOKENS)"); + unpacked[TOKENS[ARG_NUM]] = de::toString(cur); + unpackArgs(unpacked, ::std::forward(args)...); +} +} // detail + +/*--------------------------------------------------------------------*//*! + * \brief Implementation of specialize() using a variable argument list + *//*--------------------------------------------------------------------*/ +template +std::string StringTemplate::format(args_t&&... args) const +{ + std::map unpacked = {}; + detail::unpackArgs<0>(unpacked, ::std::forward(args)...); + return specialize(unpacked); +} + } // tcu #endif // _TCUSTRINGTEMPLATE_HPP -- 2.7.4