blob: 38650f5c98ac68890caa5ecd4ea9b4473d8bfcf3 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2020 Google LLC
* Copyright (c) 2020 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 Test new features in VK_KHR_shader_terminate_invocation
*//*--------------------------------------------------------------------*/
#include <string>
#include <vector>
#include <amber/amber.h>
#include "tcuDefs.hpp"
#include "vkDefs.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktAmberTestCase.hpp"
#include "vktSpvAsmTerminateInvocationTests.hpp"
#include "vktTestGroupUtil.hpp"
namespace vkt
{
namespace SpirVAssembly
{
namespace
{
struct Case
{
Case(const char* b, const char* d, bool v) : basename(b), description(d), spv1p3(v), requirements() { }
Case(const char* b, const char* d, bool v, const std::vector<std::string>& e) : basename(b), description(d), spv1p3(v), requirements(e) { }
const char *basename;
const char *description;
bool spv1p3;
// Additional Vulkan requirements, if any.
std::vector<std::string> requirements;
};
struct CaseGroup
{
CaseGroup(const char* the_data_dir) : data_dir(the_data_dir) { }
void add(const char* basename, const char* description, bool spv1p3)
{
cases.push_back(Case(basename, description, spv1p3));
}
void add(const char* basename, const char* description, bool spv1p3, const std::vector<std::string>& requirements)
{
cases.push_back(Case(basename, description, spv1p3, requirements));
}
const char* data_dir;
std::vector<Case> cases;
};
void addTestsForAmberFiles (tcu::TestCaseGroup* tests, CaseGroup group)
{
tcu::TestContext& testCtx = tests->getTestContext();
const std::string data_dir(group.data_dir);
const std::string category = data_dir;
std::vector<Case> cases(group.cases);
for (unsigned i = 0; i < cases.size() ; ++i)
{
deUint32 vulkan_version = cases[i].spv1p3 ? VK_MAKE_VERSION(1, 1, 0) : VK_MAKE_VERSION(1, 0, 0);
vk::SpirvVersion spirv_version = cases[i].spv1p3 ? vk::SPIRV_VERSION_1_3 : vk::SPIRV_VERSION_1_0;
vk::SpirVAsmBuildOptions asm_options(vulkan_version, spirv_version);
const std::string file = std::string(cases[i].basename) + ".amber";
cts_amber::AmberTestCase *testCase = cts_amber::createAmberTestCase(testCtx,
cases[i].basename,
cases[i].description,
category.c_str(),
file);
DE_ASSERT(testCase != DE_NULL);
testCase->addRequirement("VK_KHR_shader_terminate_invocation");
const std::vector<std::string>& reqmts = cases[i].requirements;
for (size_t r = 0; r < reqmts.size() ; ++r)
{
testCase->addRequirement(reqmts[r]);
}
testCase->setSpirVAsmBuildOptions(asm_options);
tests->addChild(testCase);
}
}
} // anonymous
tcu::TestCaseGroup* createTerminateInvocationGroup(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> terminateTests(new tcu::TestCaseGroup(testCtx, "terminate_invocation", "VK_KHR_shader_terminate_invocation tests"));
const char* data_data = "spirv_assembly/instruction/terminate_invocation";
std::vector<std::string> Stores;
Stores.push_back("Features.fragmentStoresAndAtomics");
std::vector<std::string> VarPtr;
VarPtr.push_back("VariablePointerFeatures.variablePointersStorageBuffer");
VarPtr.push_back("Features.fragmentStoresAndAtomics");
std::vector<std::string> Vote;
Vote.push_back("SubgroupSupportedOperations.vote");
Vote.push_back("SubgroupSupportedStages.fragment");
std::vector<std::string> Ballot;
Ballot.push_back("SubgroupSupportedOperations.ballot");
Ballot.push_back("SubgroupSupportedStages.fragment");
CaseGroup group(data_data);
group.add("no_output_write", "no write to after calling terminate invocation", false);
group.add("no_output_write_before_terminate", "no write to output despite occurring before terminate invocation", false);
group.add("no_ssbo_store", "no store to SSBO when it occurs after terminate invocation", false, Stores);
group.add("no_ssbo_atomic", "no atomic update to SSBO when it occurs after terminate invocation", false, Stores);
group.add("ssbo_store_before_terminate", "ssbo store commits when it occurs before terminate invocation", false, Stores);
group.add("no_image_store", "no image write when it occurs after terminate invocation", false, Stores);
group.add("no_image_atomic", "no image atomic updates when it occurs after terminate invocation", false, Stores);
group.add("no_null_pointer_load", "null pointer should not be accessed by a load in a terminated invocation", false, VarPtr);
group.add("no_null_pointer_store", "null pointer should not be accessed by a store in a terminated invocation", false, VarPtr);
group.add("no_out_of_bounds_load", "out of bounds pointer should not be accessed by a load in a terminated invocation", false, VarPtr);
group.add("no_out_of_bounds_store", "out of bounds pointer should not be accessed by a store in a terminated invocation", false, VarPtr);
group.add("no_out_of_bounds_atomic", "out of bounds pointer should not be accessed by an atomic in a terminated invocation", false, VarPtr);
group.add("terminate_loop", "\"inifinite\" loop that calls terminate invocation", false);
group.add("subgroup_ballot", "checks that terminated invocations don't participate in the ballot", true, Ballot);
group.add("subgroup_vote", "checks that a subgroup all does not include any terminated invocations", true, Vote);
terminateTests->addChild(createTestGroup(testCtx, "terminate", "Terminate Invocation", addTestsForAmberFiles, group));
return terminateTests.release();
}
} // SpirVAssembly
} // vkt