| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2019 Google LLC |
| * Copyright (c) 2019 The Khronos Group 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 Functional tests using amber |
| *//*--------------------------------------------------------------------*/ |
| |
| #include <amber/amber.h> |
| #include "amber/recipe.h" |
| |
| #include <iostream> |
| |
| #include "deDefs.hpp" |
| #include "deUniquePtr.hpp" |
| #include "deFilePath.hpp" |
| #include "vkPrograms.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "vktAmberTestCase.hpp" |
| #include "vktAmberHelper.hpp" |
| #include "tcuResource.hpp" |
| #include "tcuTestLog.hpp" |
| #include "vkSpirVProgram.hpp" |
| #include "vkImageUtil.hpp" |
| |
| namespace vkt |
| { |
| namespace cts_amber |
| { |
| |
| AmberTestCase::AmberTestCase(tcu::TestContext &testCtx, const char *name, const char *description, |
| const std::string &readFilename) |
| : TestCase(testCtx, name) |
| , m_recipe(nullptr) |
| , m_readFilename(readFilename) |
| { |
| (void)description; |
| } |
| |
| AmberTestCase::~AmberTestCase(void) |
| { |
| delete m_recipe; |
| } |
| |
| TestInstance *AmberTestCase::createInstance(Context &ctx) const |
| { |
| return new AmberTestInstance(ctx, m_recipe, nullptr); |
| } |
| |
| static amber::EngineConfig *createEngineConfig(Context &ctx, vk::VkDevice customDevice) |
| { |
| vk::VkDevice dev = customDevice != nullptr ? customDevice : ctx.getDevice(); |
| vk::VkQueue queue; |
| vk::DeviceDriver vk(ctx.getPlatformInterface(), ctx.getInstance(), dev, ctx.getUsedApiVersion(), |
| ctx.getTestContext().getCommandLine()); |
| vk.getDeviceQueue(dev, ctx.getUniversalQueueFamilyIndex(), 0, &queue); |
| |
| amber::EngineConfig *vkConfig = GetVulkanConfig( |
| ctx.getInstance(), ctx.getPhysicalDevice(), dev, &ctx.getDeviceFeatures(), &ctx.getDeviceFeatures2(), |
| &ctx.getDeviceProperties(), &ctx.getDeviceProperties2(), ctx.getInstanceExtensions(), ctx.getDeviceExtensions(), |
| ctx.getUniversalQueueFamilyIndex(), queue, ctx.getInstanceProcAddr()); |
| |
| return vkConfig; |
| } |
| |
| // Returns true if the given feature is supported by the device. |
| // Throws an internal error If the feature is not recognized at all. |
| static bool isFeatureSupported(const vkt::Context &ctx, const std::string &feature) |
| { |
| if (feature == "Storage16BitFeatures.storageBuffer16BitAccess") |
| return ctx.get16BitStorageFeatures().storageBuffer16BitAccess; |
| if (feature == "Float16Int8Features.shaderFloat16") |
| return ctx.getShaderFloat16Int8Features().shaderFloat16; |
| if (feature == "Float16Int8Features.shaderInt8") |
| return ctx.getShaderFloat16Int8Features().shaderInt8; |
| if (feature == "Features.shaderFloat64") |
| return ctx.getDeviceFeatures().shaderFloat64; |
| if (feature == "Features.shaderInt16") |
| return ctx.getDeviceFeatures().shaderInt16; |
| if (feature == "Features.shaderInt64") |
| return ctx.getDeviceFeatures().shaderInt64; |
| if (feature == "Features.depthClamp") |
| return ctx.getDeviceFeatures().depthClamp; |
| if (feature == "Features.tessellationShader") |
| return ctx.getDeviceFeatures().tessellationShader; |
| if (feature == "Features.shaderTessellationAndGeometryPointSize") |
| return ctx.getDeviceFeatures().shaderTessellationAndGeometryPointSize; |
| if (feature == "Features.geometryShader") |
| return ctx.getDeviceFeatures().geometryShader; |
| if (feature == "Features.fragmentStoresAndAtomics") |
| return ctx.getDeviceFeatures().fragmentStoresAndAtomics; |
| if (feature == "Features.vertexPipelineStoresAndAtomics") |
| return ctx.getDeviceFeatures().vertexPipelineStoresAndAtomics; |
| if (feature == "Features.fillModeNonSolid") |
| return ctx.getDeviceFeatures().fillModeNonSolid; |
| if (feature == "Features.shaderStorageImageMultisample") |
| return ctx.getDeviceFeatures().shaderStorageImageMultisample; |
| if (feature == "Features.sampleRateShading") |
| return ctx.getDeviceFeatures().sampleRateShading; |
| if (feature == "VariablePointerFeatures.variablePointersStorageBuffer") |
| return ctx.getVariablePointersFeatures().variablePointersStorageBuffer; |
| if (feature == "VariablePointerFeatures.variablePointers") |
| return ctx.getVariablePointersFeatures().variablePointers; |
| if (feature == "SubgroupSupportedStages.fragment") |
| return (ctx.getSubgroupProperties().supportedStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0; |
| if (feature == "SubgroupSupportedOperations.vote") |
| return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_VOTE_BIT) != 0; |
| if (feature == "SubgroupSupportedOperations.basic") |
| return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_BASIC_BIT) != 0; |
| if (feature == "SubgroupSupportedOperations.ballot") |
| return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0; |
| if (feature == "Storage16BitFeatures.storageBuffer16BitAccess") |
| return ctx.get16BitStorageFeatures().storageBuffer16BitAccess; |
| if (feature == "Storage8BitFeatures.storageBuffer8BitAccess") |
| return ctx.get8BitStorageFeatures().storageBuffer8BitAccess; |
| if (feature == "IndexTypeUint8Features.indexTypeUint8") |
| return ctx.getIndexTypeUint8Features().indexTypeUint8; |
| if (feature == "RayTracingPipelineFeaturesKHR.rayTracingPipeline") |
| return ctx.getRayTracingPipelineFeatures().rayTracingPipeline; |
| if (feature == "AccelerationStructureFeaturesKHR.accelerationStructure") |
| return ctx.getAccelerationStructureFeatures().accelerationStructure; |
| if (feature == "BufferDeviceAddressFeatures.bufferDeviceAddress") |
| return ctx.getBufferDeviceAddressFeatures().bufferDeviceAddress; |
| |
| std::string message = std::string("Unexpected feature name: ") + feature; |
| TCU_THROW(InternalError, message.c_str()); |
| } |
| |
| // Returns true if the given property is supported by the device. |
| // Throws an internal error if the property is not recognized at all. |
| static bool isPropertySupported(const vkt::Context &ctx, const std::string &prop) |
| { |
| if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat16") |
| return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat16; |
| if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat32") |
| return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat32; |
| if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat64") |
| return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat64; |
| if (prop == "FloatControlsProperties.shaderDenormPreserveFloat16") |
| return ctx.getFloatControlsProperties().shaderDenormPreserveFloat16; |
| if (prop == "FloatControlsProperties.shaderDenormPreserveFloat32") |
| return ctx.getFloatControlsProperties().shaderDenormPreserveFloat32; |
| if (prop == "FloatControlsProperties.shaderDenormPreserveFloat64") |
| return ctx.getFloatControlsProperties().shaderDenormPreserveFloat64; |
| if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat16") |
| return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat16; |
| if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat32") |
| return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat32; |
| if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat64") |
| return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat64; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat16") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat16; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat32") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat32; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat64") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat64; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat16") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat16; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat32") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat32; |
| if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat64") |
| return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat64; |
| |
| std::string message = std::string("Unexpected property name: ") + prop; |
| TCU_THROW(InternalError, message.c_str()); |
| } |
| |
| void AmberTestCase::delayedInit(void) |
| { |
| // Make sure the input can be parsed before we use it. |
| if (!parse(m_readFilename)) |
| { |
| std::string message = "Failed to parse Amber file: " + m_readFilename; |
| TCU_THROW(InternalError, message.c_str()); |
| } |
| } |
| |
| void AmberTestCase::checkSupport(Context &ctx) const |
| { |
| // Check for instance and device extensions as declared by the test code. |
| if (m_required_extensions.size()) |
| { |
| std::set<std::string> device_extensions(ctx.getDeviceExtensions().begin(), ctx.getDeviceExtensions().end()); |
| std::set<std::string> instance_extensions(ctx.getInstanceExtensions().begin(), |
| ctx.getInstanceExtensions().end()); |
| std::string missing; |
| for (std::set<std::string>::iterator iter = m_required_extensions.begin(); iter != m_required_extensions.end(); |
| ++iter) |
| { |
| const std::string extension = *iter; |
| if ((device_extensions.count(extension) == 0) && (instance_extensions.count(extension) == 0)) |
| { |
| missing += " " + extension; |
| } |
| } |
| if (missing.size() > 0) |
| { |
| std::string message("Test requires unsupported extensions:"); |
| message += missing; |
| TCU_THROW(NotSupportedError, message.c_str()); |
| } |
| } |
| |
| // Check for required features. Do this after extensions are checked because |
| // some feature checks are only valid when corresponding extensions are enabled. |
| if (m_required_features.size()) |
| { |
| std::string missing; |
| for (std::set<std::string>::iterator iter = m_required_features.begin(); iter != m_required_features.end(); |
| ++iter) |
| { |
| const std::string feature = *iter; |
| if (!isFeatureSupported(ctx, feature)) |
| { |
| missing += " " + feature; |
| } |
| } |
| if (missing.size() > 0) |
| { |
| std::string message("Test requires unsupported features:"); |
| message += missing; |
| TCU_THROW(NotSupportedError, message.c_str()); |
| } |
| } |
| |
| // Check for required properties |
| if (!m_required_properties.empty()) |
| { |
| std::string missing; |
| for (const auto &prop : m_required_properties) |
| { |
| if (!isPropertySupported(ctx, prop)) |
| { |
| missing += " " + prop; |
| } |
| } |
| if (!missing.empty()) |
| { |
| std::string message("Test requires unsupported properties:"); |
| message += missing; |
| TCU_THROW(NotSupportedError, message.c_str()); |
| } |
| } |
| |
| for (auto req : m_imageRequirements) |
| checkImageSupport(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), req); |
| |
| for (auto req : m_bufferRequirements) |
| { |
| vk::VkFormatProperties prop; |
| ctx.getInstanceInterface().getPhysicalDeviceFormatProperties(ctx.getPhysicalDevice(), req.m_format, &prop); |
| |
| if ((req.m_featureFlags & prop.bufferFeatures) != req.m_featureFlags) |
| { |
| TCU_THROW(NotSupportedError, "Buffer format doesn't support required feature flags"); |
| } |
| } |
| |
| if (m_checkSupportCallback) |
| (m_checkSupportCallback)(ctx, m_name); |
| } |
| |
| class Delegate : public amber::Delegate |
| { |
| public: |
| Delegate(tcu::TestContext &testCtx); |
| |
| amber::Result LoadBufferData(const std::string file_name, amber::BufferDataFileType file_type, |
| amber::BufferInfo *buffer) const override; |
| |
| amber::Result LoadFile(const std::string file_name, std::vector<char> *buffer) const override; |
| |
| void Log(const std::string & /*message*/) override |
| { |
| DE_FATAL("amber::Delegate::Log unimplemented"); |
| } |
| bool LogGraphicsCalls(void) const override |
| { |
| return m_logGraphicsCalls; |
| } |
| void SetLogGraphicsCalls(bool log_graphics_calls) |
| { |
| m_logGraphicsCalls = log_graphics_calls; |
| } |
| bool LogExecuteCalls(void) const override |
| { |
| return m_logExecuteCalls; |
| } |
| void SetLogExecuteCalls(bool log_execute_calls) |
| { |
| m_logExecuteCalls = log_execute_calls; |
| } |
| bool LogGraphicsCallsTime(void) const override |
| { |
| return m_logGraphicsCallsTime; |
| } |
| void SetLogGraphicsCallsTime(bool log_graphics_calls_time) |
| { |
| m_logGraphicsCallsTime = log_graphics_calls_time; |
| } |
| uint64_t GetTimestampNs(void) const override |
| { |
| DE_FATAL("amber::Delegate::GetTimestampNs unimplemented"); |
| return 0; |
| } |
| void SetScriptPath(std::string path) |
| { |
| m_path = path; |
| } |
| |
| private: |
| tcu::TestContext &m_testCtx; |
| std::string m_path; |
| bool m_logGraphicsCalls; |
| bool m_logGraphicsCallsTime; |
| bool m_logExecuteCalls; |
| }; |
| |
| Delegate::Delegate(tcu::TestContext &testCtx) |
| : m_testCtx(testCtx) |
| , m_path("") |
| , m_logGraphicsCalls(false) |
| , m_logGraphicsCallsTime(false) |
| , m_logExecuteCalls(false) |
| { |
| } |
| |
| amber::Result Delegate::LoadBufferData(const std::string file_name, amber::BufferDataFileType file_type, |
| amber::BufferInfo *buffer) const |
| { |
| const tcu::Archive &archive = m_testCtx.getArchive(); |
| const de::FilePath filePath = de::FilePath(m_path).join(file_name); |
| de::UniquePtr<tcu::Resource> file(archive.getResource(filePath.getPath())); |
| int numBytes = file->getSize(); |
| std::vector<uint8_t> bytes(numBytes); |
| |
| if (file_type == amber::BufferDataFileType::kPng) |
| return amber::Result("Amber PNG loading unimplemented"); |
| |
| file->read(bytes.data(), numBytes); |
| |
| if (bytes.empty()) |
| return amber::Result("Failed to load buffer data " + file_name); |
| |
| for (uint8_t byte : bytes) |
| { |
| amber::Value value; |
| value.SetIntValue(static_cast<uint64_t>(byte)); |
| buffer->values.push_back(value); |
| } |
| |
| buffer->width = 1; |
| buffer->height = 1; |
| |
| return {}; |
| } |
| |
| amber::Result Delegate::LoadFile(const std::string file_name, std::vector<char> *buffer) const |
| { |
| if (!buffer) |
| { |
| return amber::Result("Buffer pointer is null."); |
| } |
| |
| const tcu::Archive &archive = m_testCtx.getArchive(); |
| const de::FilePath filePath = de::FilePath(m_path).join(file_name); |
| de::UniquePtr<tcu::Resource> file(archive.getResource(filePath.getPath())); |
| int numBytes = file->getSize(); |
| std::vector<uint8_t> bytes(numBytes); |
| |
| file->read(bytes.data(), numBytes); |
| |
| if (bytes.empty()) |
| return amber::Result("Failed to load buffer data " + file_name); |
| |
| // Convert uint8_t vector to char vector |
| buffer->assign(bytes.begin(), bytes.end()); |
| |
| return {}; |
| } |
| |
| bool AmberTestCase::parse(const std::string &readFilename) |
| { |
| std::string script = ShaderSourceProvider::getSource(m_testCtx.getArchive(), readFilename.c_str()); |
| if (script.empty()) |
| return false; |
| |
| Delegate delegate(m_testCtx); |
| delegate.SetScriptPath(de::FilePath(readFilename).getDirName()); |
| |
| m_recipe = new amber::Recipe(); |
| |
| amber::Amber am(&delegate); |
| amber::Result r = am.Parse(script, m_recipe); |
| |
| m_recipe->SetFenceTimeout(~0u); // infinity of miliseconds |
| |
| if (!r.IsSuccess()) |
| { |
| getTestContext().getLog() << tcu::TestLog::Message << "Failed to parse Amber test " << readFilename << ": " |
| << r.Error() << "\n" |
| << tcu::TestLog::EndMessage; |
| // TODO(dneto): Enhance Amber to not require this. |
| m_recipe->SetImpl(nullptr); |
| return false; |
| } |
| return true; |
| } |
| |
| void AmberTestCase::initPrograms(vk::SourceCollections &programCollection) const |
| { |
| std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo(); |
| for (size_t i = 0; i < shaders.size(); ++i) |
| { |
| const amber::ShaderInfo &shader = shaders[i]; |
| |
| vk::SpirvVersion spirvVersion = vk::SPIRV_VERSION_1_0; |
| DE_STATIC_ASSERT(vk::SPIRV_VERSION_LAST == vk::SPIRV_VERSION_1_6 + 1); |
| if (shader.target_env == "spv1.6") |
| spirvVersion = vk::SPIRV_VERSION_1_6; |
| else if (shader.target_env == "spv1.5") |
| spirvVersion = vk::SPIRV_VERSION_1_5; |
| else if (shader.target_env == "spv1.4") |
| spirvVersion = vk::SPIRV_VERSION_1_4; |
| else if (shader.target_env == "spv1.3") |
| spirvVersion = vk::SPIRV_VERSION_1_3; |
| else if (shader.target_env == "spv1.2") |
| spirvVersion = vk::SPIRV_VERSION_1_2; |
| else if (shader.target_env == "spv1.1") |
| spirvVersion = vk::SPIRV_VERSION_1_1; |
| |
| /* Hex encoded shaders do not need to be pre-compiled */ |
| if (shader.format == amber::kShaderFormatSpirvHex) |
| continue; |
| |
| if (shader.format == amber::kShaderFormatSpirvAsm) |
| { |
| programCollection.spirvAsmSources.add(shader.shader_name) << shader.shader_source << m_asm_options; |
| } |
| else if (shader.format == amber::kShaderFormatGlsl) |
| { |
| bool allowSpirv14 = (spirvVersion == vk::SPIRV_VERSION_1_4); |
| |
| switch (shader.type) |
| { |
| case amber::kShaderTypeCompute: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::ComputeSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeGeometry: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::GeometrySource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeFragment: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::FragmentSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeVertex: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::VertexSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeTessellationControl: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::TessellationControlSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeTessellationEvaluation: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::TessellationEvaluationSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14); |
| break; |
| case amber::kShaderTypeRayGeneration: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::RaygenSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeAnyHit: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::AnyHitSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeClosestHit: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::ClosestHitSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeMiss: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::MissSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeIntersection: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::IntersectionSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeCall: |
| programCollection.glslSources.add(shader.shader_name) |
| << glu::CallableSource(shader.shader_source) |
| << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true); |
| break; |
| case amber::kShaderTypeMulti: |
| DE_ASSERT(false && "Multi shaders not supported"); |
| break; |
| default: |
| DE_ASSERT(false && "Unknown shader"); |
| break; |
| } |
| } |
| else |
| { |
| DE_ASSERT(false && "Shader format not supported"); |
| } |
| } |
| } |
| |
| tcu::TestStatus AmberTestInstance::iterate(void) |
| { |
| amber::Amber am(nullptr); |
| amber::Options amber_options; |
| amber::ShaderMap shaderMap; |
| amber::Result r; |
| |
| amber_options.engine = amber::kEngineTypeVulkan; |
| amber_options.config = createEngineConfig(m_context, m_customDevice); |
| amber_options.execution_type = amber::ExecutionType::kExecute; |
| |
| // Amber should not execute any graphic related shaders when using --deqp-compute-only=enable flag |
| if (m_context.getTestContext().getCommandLine().isComputeOnly()) |
| { |
| std::vector<amber::ShaderInfo> shaders_info = m_recipe->GetShaderInfo(); |
| |
| for (amber::ShaderInfo info : shaders_info) |
| { |
| if (info.type != amber::ShaderType::kShaderTypeCompute) |
| { |
| TCU_THROW(NotSupportedError, "Non compute shaders are not allow when using --deqp-compute-only=enable"); |
| } |
| } |
| } |
| |
| // Check for extensions as declared by the Amber script itself. Throw an internal |
| // error if that's more demanding. |
| r = am.AreAllRequirementsSupported(m_recipe, &amber_options); |
| if (!r.IsSuccess()) |
| { |
| // dEQP does not to rely on external code to determine whether |
| // a test is supported. So throw an internal error here instead |
| // of a NotSupportedError. If an Amber test is not supported, then |
| // you must override this method and throw a NotSupported exception |
| // before reach here. |
| TCU_THROW(InternalError, r.Error().c_str()); |
| } |
| |
| std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo(); |
| for (size_t i = 0; i < shaders.size(); ++i) |
| { |
| const amber::ShaderInfo &shader = shaders[i]; |
| |
| if (!m_context.getBinaryCollection().contains(shader.shader_name)) |
| continue; |
| |
| const vk::ProgramBinary &prog = m_context.getBinaryCollection().get(shader.shader_name); |
| |
| prog.setUsed(); |
| |
| size_t len = prog.getSize(); |
| /* This is a compiled spir-v binary which must be made of 4-byte words. We |
| * are moving into a word sized vector so divide by 4 |
| */ |
| std::vector<uint32_t> data; |
| data.resize(len >> 2); |
| deMemcpy(data.data(), prog.getBinary(), len); |
| |
| shaderMap[shader.shader_name] = data; |
| } |
| |
| r = am.ExecuteWithShaderData(m_recipe, &amber_options, shaderMap); |
| if (!r.IsSuccess()) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << r.Error() << "\n" << tcu::TestLog::EndMessage; |
| } |
| |
| delete amber_options.config; |
| |
| return r.IsSuccess() ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail"); |
| } |
| |
| void AmberTestCase::setSpirVAsmBuildOptions(const vk::SpirVAsmBuildOptions &asm_options) |
| { |
| m_asm_options = asm_options; |
| } |
| |
| void AmberTestCase::addRequirement(const std::string &requirement) |
| { |
| if (requirement.find(".") != std::string::npos) |
| m_required_features.insert(requirement); |
| else |
| m_required_extensions.insert(requirement); |
| } |
| |
| void AmberTestCase::addPropertyRequirement(const std::string &requirement) |
| { |
| m_required_properties.insert(requirement); |
| } |
| |
| void AmberTestCase::addImageRequirement(vk::VkImageCreateInfo info) |
| { |
| m_imageRequirements.push_back(info); |
| } |
| |
| void AmberTestCase::addBufferRequirement(BufferRequirement req) |
| { |
| m_bufferRequirements.push_back(req); |
| } |
| |
| bool AmberTestCase::validateRequirements() |
| { |
| if (!parse(m_readFilename)) |
| { |
| std::string message = "Failed to parse Amber file: " + m_readFilename; |
| m_testCtx.getLog() << tcu::TestLog::Message << message << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| // Check if the list of required CTS features and extensions matches the |
| // one in the recipe. Throw InternalError if they do not match. |
| |
| const auto &deviceExtensions = m_recipe->GetRequiredInstanceExtensions(); |
| const auto &instanceExtensions = m_recipe->GetRequiredDeviceExtensions(); |
| auto requiredFeatures = m_recipe->GetRequiredFeatures(); |
| auto requiredProperties = m_recipe->GetRequiredProperties(); |
| |
| for (auto &req : requiredFeatures) |
| { |
| if (req.find(".") == std::string::npos) |
| req = "Features." + req; |
| } |
| |
| std::set<std::string> allRequirements; |
| allRequirements.insert(begin(deviceExtensions), end(deviceExtensions)); |
| allRequirements.insert(begin(instanceExtensions), end(instanceExtensions)); |
| allRequirements.insert(begin(requiredFeatures), end(requiredFeatures)); |
| allRequirements.insert(begin(requiredProperties), end(requiredProperties)); |
| |
| std::set<std::string> ctsRequirements = m_required_features; |
| ctsRequirements.insert(begin(m_required_properties), end(m_required_properties)); |
| ctsRequirements.insert(begin(m_required_extensions), end(m_required_extensions)); |
| |
| if (allRequirements != ctsRequirements) |
| { |
| auto &log = m_testCtx.getLog(); |
| log << tcu::TestLog::Message << "ERROR: CTS and Amber test requirement mismatch." << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "Amber filename: " << m_readFilename << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "CTS requirements:" << tcu::TestLog::EndMessage; |
| for (const auto &ctsReq : ctsRequirements) |
| log << tcu::TestLog::Message << " " << ctsReq << tcu::TestLog::EndMessage; |
| |
| log << tcu::TestLog::Message << "Amber requirements:" << tcu::TestLog::EndMessage; |
| for (const auto &amberReq : allRequirements) |
| log << tcu::TestLog::Message << " " << amberReq << tcu::TestLog::EndMessage; |
| |
| // Repeat message for cerr so it's visible in console log. |
| std::cerr << "ERROR: CTS and Amber test requirement mismatch.\n"; |
| std::cerr << "Amber filename: " << m_readFilename << "\n"; |
| std::cerr << "CTS requirements:\n"; |
| for (const auto &ctsReq : ctsRequirements) |
| std::cerr << " " << ctsReq << "\n"; |
| |
| std::cerr << "Amber requirements:\n"; |
| for (const auto &amberReq : allRequirements) |
| std::cerr << " " << amberReq << "\n"; |
| |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace cts_amber |
| } // namespace vkt |