From 54e49c0a8df943bdbb2ac1b777d9e851dea5c619 Mon Sep 17 00:00:00 2001 From: Jari Komppa Date: Mon, 4 Nov 2019 15:51:27 +0200 Subject: [PATCH] Add index file for amber tests This change adds index file for amber tests, making it possible to add new amber tests without having to recompile the cts binary itself. This change does not affect the tests themselves, just the way they are discovered. Affects: none Components: Vulkan VK-GL-CTS issue: 2086 Change-Id: Iba1d2b6cfe8816360fe520dec90621a71a4d2769 --- .../data/vulkan/amber/graphicsfuzz/index.txt | 70 +++++++++ .../vulkan/amber/vktAmberGraphicsFuzzTests.cpp | 83 +--------- .../modules/vulkan/amber/vktAmberTestCase.hpp | 5 + .../modules/vulkan/amber/vktAmberTestCaseUtil.cpp | 174 +++++++++++++++++++++ 4 files changed, 250 insertions(+), 82 deletions(-) create mode 100644 external/vulkancts/data/vulkan/amber/graphicsfuzz/index.txt diff --git a/external/vulkancts/data/vulkan/amber/graphicsfuzz/index.txt b/external/vulkancts/data/vulkan/amber/graphicsfuzz/index.txt new file mode 100644 index 0000000..f446007 --- /dev/null +++ b/external/vulkancts/data/vulkan/amber/graphicsfuzz/index.txt @@ -0,0 +1,70 @@ +{ "access-new-vector-inside-if-condition.amber", "access-new-vector-inside-if-condition","A shader that accesses a new vector within an if condition" }, +{ "always-false-if-in-do-while.amber", "always-false-if-in-do-while", "A fragment shader with an always false if." }, +{ "always-false-if-with-discard-return.amber", "always-false-if-with-discard-return", "A fragment shader with discard keyword and a return" }, +{ "barrier-in-loop-with-break.amber", "barrier-in-loop-with-break", "A compute shader with a barrier in a loop with a break" }, +{ "call-if-while-switch.amber", "call-if-while-switch", "A fragment shader with a call, if, while, switch" }, +{ "color-write-in-loop.amber", "color-write-in-loop", "A fragment shader that writes to color in a loop" }, +{ "complex-nested-loops-and-call.amber", "complex-nested-loops-and-call", "A fragment shader with complex nested loops, breaks, etc." }, +{ "conditional-return-in-infinite-while.amber", "conditional-return-in-infinite-while", "A shader with conditional return inside an infinite loop" }, +{ "continue-and-merge.amber", "continue-and-merge", "A fragment shader with two nested loops" }, +{ "control-flow-in-function.amber", "control-flow-in-function", "A fragment shader with a lot of control flow" }, +{ "control-flow-switch.amber", "control-flow-switch", "A fragment shader with somewhat complex control flow and a switch" }, +{ "dead-barriers-in-loops.amber", "dead-barriers-in-loops", "A compute shader with dead barriers" }, +{ "dead-struct-init.amber", "dead-struct-init", "A fragment shader that uses struct initializers" }, +{ "disc-and-add-in-func-in-loop.amber", "disc-and-add-in-func-in-loop", "A fragment shader with discard and add in function in loop" }, +{ "discard-continue-return.amber", "discard-continue-return", "A fragment shader with a discard, continue, and return" }, +{ "discard-in-array-manipulating-loop.amber", "discard-in-array-manipulating-loop", "An array-manipulating fragment shader with a discard" }, +{ "do-while-loop-in-conditionals.amber", "do-while-loop-in-conditionals", "A fragment shader with do-while loop in conditional nest" }, +{ "do-while-with-always-true-if.amber", "do-while-with-always-true-if", "A fragment shader with a do while that always returns" }, +{ "early-return-and-barrier.amber", "early-return-and-barrier", "A compute shader with an early return and a barrier" }, +{ "for-condition-always-false.amber", "for-condition-always-false", "A fragment shader that uses a for loop with condition always false" }, +{ "for-loop-with-return.amber", "for-loop-with-return", "A fragment shader with a for loop that loops only once" }, +{ "for-with-ifs-and-return.amber", "for-with-ifs-and-return", "A fragment shader with two ifs and return/continue inside a for loop" }, +{ "fragcoord-control-flow.amber", "fragcoord-control-flow", "A fragment shader that uses FragCoord and somewhat complex control flow" }, +{ "fragcoord-control-flow-2.amber", "fragcoord-control-flow-2", "A fragment shader that uses FragCoord and somewhat complex control flow" }, +{ "if-and-switch.amber", "if-and-switch", "A fragment shader with a switch and some data flow" }, +{ "loop-call-discard.amber", "loop-call-discard", "A fragment shader with nested loops and a function call" }, +{ "loop-dead-if-loop.amber", "loop-dead-if-loop", "A fragment shader with a loop, dead if, and a loop" }, +{ "loop-nested-ifs.amber", "loop-nested-ifs", "A fragment shader with a for loop containing nested ifs" }, +{ "loops-breaks-returns.amber", "loops-breaks-returns", "A compute shader with loops, breaks, returns" }, +{ "loops-ifs-continues-call.amber", "loops-ifs-continues-call", "A fragment shader with nested control flow and a call" }, +{ "mat-array-deep-control-flow.amber", "mat-array-deep-control-flow", "A fragment shader that uses an array of matrices and has deep control flow" }, +{ "mat-array-distance.amber", "mat-array-distance", "A fragment shader that uses an array of matrices and distance" }, +{ "matrices-and-return-in-loop.amber", "matrices-and-return-in-loop", "A fragment shader with matrices and a return in a loop" }, +{ "max-mix-conditional-discard.amber", "max-mix-conditional-discard", "A fragment shader with an expression used in two discard guards" }, +{ "mix-floor-add.amber", "mix-floor-add", "A fragment shader with mix, uintBitsToFloat, and floor" }, +{ "nested-for-loops-with-return.amber", "nested-for-loops-with-return", "A fragment shader with two nested for loops with return" }, +{ "nested-ifs-and-return-in-for-loop.amber", "nested-ifs-and-return-in-for-loop", "A fragment shader with return in nest of ifs, inside loop" }, +{ "nested-loops-switch.amber", "nested-loops-switch", "A fragment shader with nested loops and a switch" }, +{ "pow-vec4.amber", "pow-vec4", "A fragment shader that uses pow" }, +{ "return-before-writing-wrong-color.amber", "return-before-writing-wrong-color", "A fragment shader with return before writing wrong color" }, +{ "return-float-from-while-loop.amber", "return-float-from-while-loop", "A fragment shader with unreachable while loop" }, +{ "return-in-loop-in-function.amber", "return-in-loop-in-function", "A fragment shader with early return from loop in function" }, +{ "returned-boolean-in-vector.amber", "returned-boolean-in-vector", "A fragment shader with returned boolean in vector" }, +{ "similar-nested-ifs.amber", "similar-nested-ifs", "A fragment shader with similar nested ifs and loops" }, +{ "struct-used-as-temporary.amber", "struct-used-as-temporary", "A fragment shader that uses a temporary struct variable" }, +{ "switch-if-discard.amber", "switch-if-discard", "A fragment shader with a switch, if, and discard" }, +{ "switch-with-empty-if-false.amber", "switch-with-empty-if-false", "A fragment shader with always false if in switch statement" }, +{ "swizzle-struct-init-min.amber", "swizzle-struct-init-min", "A fragment shader that uses vector swizzles, struct initializers, and min" }, +{ "two-for-loops-with-barrier-function.amber", "two-for-loops-with-barrier-function", "A compute shader with two barrier functions" }, +{ "two-loops-matrix.amber", "two-loops-matrix", "A fragment shader with two loops and some matrices" }, +{ "two-loops-set-struct.amber", "two-loops-set-struct", "A fragment shader with two loops that write to a struct" }, +{ "two-loops-with-break.amber", "two-loops-with-break", "A fragment shader with two loops with breaks" }, +{ "two-nested-do-whiles.amber", "two-nested-do-whiles", "A fragment shader with nested do while" }, +{ "two-nested-for-loops-with-returns.amber", "two-nested-for-loops-with-returns", "A compute shader with two nested for loops" }, +{ "two-nested-infinite-loops-discard.amber", "two-nested-infinite-loops-discard", "A fragment shader with an always false if function" }, +{ "undefined-integer-in-function.amber", "undefined-integer-in-function", "A fragment shader with nested do while and undefined int" }, +{ "uninitialized-var-decrement-and-add.amber", "uninitialized-var-decrement-and-add", "A fragment shader that uses an uninitialized variable" }, +{ "undefined-assign-in-infinite-loop.amber", "undefined-assign-in-infinite-loop", "A fragment shader with uninitialized read in infinite loop" }, +{ "unreachable-barrier-in-loops.amber", "unreachable-barrier-in-loops", "A compute shader with an unreachable barrier in a loop nest" }, +{ "unreachable-continue-statement.amber", "unreachable-continue-statement", "A fragment shader with unreachable continue statement" }, +{ "unreachable-discard-statement-in-if.amber", "unreachable-discard-statement-in-if", "A fragment shader with discard keyword and a return" }, +{ "unreachable-discard-statement.amber", "unreachable-discard-statement", "A fragment shader with unreachable discard statement" }, +{ "unreachable-loops.amber", "unreachable-loops", "Fragment shader that writes red despite unreachable loops" }, +{ "unreachable-loops-in-switch.amber", "unreachable-loops-in-switch", "A fragment shader with unreachable loops in a switch" }, +{ "unreachable-return-in-loop.amber", "unreachable-return-in-loop", "A fragment shader with an unreachable return in a loop" }, +{ "while-function-always-false.amber", "while-function-always-false", "A fragment shader with an always false while function" }, +{ "while-inside-switch.amber", "while-inside-switch", "A fragment shader that uses a while loop inside a switch" }, +{ "write-before-break.amber", "write-before-break", "Fragment shader that writes red before loop break" }, +{ "write-red-in-loop-nest.amber", "write-red-in-loop-nest", "A fragment shader that writes red in a nest of loops" }, +{ "wrong-color-in-always-false-if.amber", "wrong-color-in-always-false-if", "A fragment shader with wrong color write in false if" }, diff --git a/external/vulkancts/modules/vulkan/amber/vktAmberGraphicsFuzzTests.cpp b/external/vulkancts/modules/vulkan/amber/vktAmberGraphicsFuzzTests.cpp index e3e14b8..93b5035 100644 --- a/external/vulkancts/modules/vulkan/amber/vktAmberGraphicsFuzzTests.cpp +++ b/external/vulkancts/modules/vulkan/amber/vktAmberGraphicsFuzzTests.cpp @@ -38,88 +38,7 @@ void createAmberTests (tcu::TestCaseGroup* group) { tcu::TestContext& testCtx = group->getTestContext(); - static const struct - { - const std::string filename; - const char* name; - const char* description; - } - tests[] = - { - { "access-new-vector-inside-if-condition.amber", "access-new-vector-inside-if-condition","A shader that accesses a new vector within an if condition" }, - { "always-false-if-in-do-while.amber", "always-false-if-in-do-while", "A fragment shader with an always false if." }, - { "always-false-if-with-discard-return.amber", "always-false-if-with-discard-return", "A fragment shader with discard keyword and a return" }, - { "barrier-in-loop-with-break.amber", "barrier-in-loop-with-break", "A compute shader with a barrier in a loop with a break" }, - { "call-if-while-switch.amber", "call-if-while-switch", "A fragment shader with a call, if, while, switch" }, - { "color-write-in-loop.amber", "color-write-in-loop", "A fragment shader that writes to color in a loop" }, - { "complex-nested-loops-and-call.amber", "complex-nested-loops-and-call", "A fragment shader with complex nested loops, breaks, etc." }, - { "conditional-return-in-infinite-while.amber", "conditional-return-in-infinite-while", "A shader with conditional return inside an infinite loop" }, - { "continue-and-merge.amber", "continue-and-merge", "A fragment shader with two nested loops" }, - { "control-flow-in-function.amber", "control-flow-in-function", "A fragment shader with a lot of control flow" }, - { "control-flow-switch.amber", "control-flow-switch", "A fragment shader with somewhat complex control flow and a switch" }, - { "dead-barriers-in-loops.amber", "dead-barriers-in-loops", "A compute shader with dead barriers" }, - { "dead-struct-init.amber", "dead-struct-init", "A fragment shader that uses struct initializers" }, - { "disc-and-add-in-func-in-loop.amber", "disc-and-add-in-func-in-loop", "A fragment shader with discard and add in function in loop" }, - { "discard-continue-return.amber", "discard-continue-return", "A fragment shader with a discard, continue, and return" }, - { "discard-in-array-manipulating-loop.amber", "discard-in-array-manipulating-loop", "An array-manipulating fragment shader with a discard" }, - { "do-while-loop-in-conditionals.amber", "do-while-loop-in-conditionals", "A fragment shader with do-while loop in conditional nest" }, - { "do-while-with-always-true-if.amber", "do-while-with-always-true-if", "A fragment shader with a do while that always returns" }, - { "early-return-and-barrier.amber", "early-return-and-barrier", "A compute shader with an early return and a barrier" }, - { "for-condition-always-false.amber", "for-condition-always-false", "A fragment shader that uses a for loop with condition always false" }, - { "for-loop-with-return.amber", "for-loop-with-return", "A fragment shader with a for loop that loops only once" }, - { "for-with-ifs-and-return.amber", "for-with-ifs-and-return", "A fragment shader with two ifs and return/continue inside a for loop" }, - { "fragcoord-control-flow.amber", "fragcoord-control-flow", "A fragment shader that uses FragCoord and somewhat complex control flow" }, - { "fragcoord-control-flow-2.amber", "fragcoord-control-flow-2", "A fragment shader that uses FragCoord and somewhat complex control flow" }, - { "if-and-switch.amber", "if-and-switch", "A fragment shader with a switch and some data flow" }, - { "loop-call-discard.amber", "loop-call-discard", "A fragment shader with nested loops and a function call" }, - { "loop-dead-if-loop.amber", "loop-dead-if-loop", "A fragment shader with a loop, dead if, and a loop" }, - { "loop-nested-ifs.amber", "loop-nested-ifs", "A fragment shader with a for loop containing nested ifs" }, - { "loops-breaks-returns.amber", "loops-breaks-returns", "A compute shader with loops, breaks, returns" }, - { "loops-ifs-continues-call.amber", "loops-ifs-continues-call", "A fragment shader with nested control flow and a call" }, - { "mat-array-deep-control-flow.amber", "mat-array-deep-control-flow", "A fragment shader that uses an array of matrices and has deep control flow" }, - { "mat-array-distance.amber", "mat-array-distance", "A fragment shader that uses an array of matrices and distance" }, - { "matrices-and-return-in-loop.amber", "matrices-and-return-in-loop", "A fragment shader with matrices and a return in a loop" }, - { "max-mix-conditional-discard.amber", "max-mix-conditional-discard", "A fragment shader with an expression used in two discard guards" }, - { "mix-floor-add.amber", "mix-floor-add", "A fragment shader with mix, uintBitsToFloat, and floor" }, - { "nested-for-loops-with-return.amber", "nested-for-loops-with-return", "A fragment shader with two nested for loops with return" }, - { "nested-ifs-and-return-in-for-loop.amber", "nested-ifs-and-return-in-for-loop", "A fragment shader with return in nest of ifs, inside loop" }, - { "nested-loops-switch.amber", "nested-loops-switch", "A fragment shader with nested loops and a switch" }, - { "pow-vec4.amber", "pow-vec4", "A fragment shader that uses pow" }, - { "return-before-writing-wrong-color.amber", "return-before-writing-wrong-color", "A fragment shader with return before writing wrong color" }, - { "return-float-from-while-loop.amber", "return-float-from-while-loop", "A fragment shader with unreachable while loop" }, - { "return-in-loop-in-function.amber", "return-in-loop-in-function", "A fragment shader with early return from loop in function" }, - { "returned-boolean-in-vector.amber", "returned-boolean-in-vector", "A fragment shader with returned boolean in vector" }, - { "similar-nested-ifs.amber", "similar-nested-ifs", "A fragment shader with similar nested ifs and loops" }, - { "struct-used-as-temporary.amber", "struct-used-as-temporary", "A fragment shader that uses a temporary struct variable" }, - { "switch-if-discard.amber", "switch-if-discard", "A fragment shader with a switch, if, and discard" }, - { "switch-with-empty-if-false.amber", "switch-with-empty-if-false", "A fragment shader with always false if in switch statement" }, - { "swizzle-struct-init-min.amber", "swizzle-struct-init-min", "A fragment shader that uses vector swizzles, struct initializers, and min" }, - { "two-for-loops-with-barrier-function.amber", "two-for-loops-with-barrier-function", "A compute shader with two barrier functions" }, - { "two-loops-matrix.amber", "two-loops-matrix", "A fragment shader with two loops and some matrices" }, - { "two-loops-set-struct.amber", "two-loops-set-struct", "A fragment shader with two loops that write to a struct" }, - { "two-loops-with-break.amber", "two-loops-with-break", "A fragment shader with two loops with breaks" }, - { "two-nested-do-whiles.amber", "two-nested-do-whiles", "A fragment shader with nested do while" }, - { "two-nested-for-loops-with-returns.amber", "two-nested-for-loops-with-returns", "A compute shader with two nested for loops" }, - { "two-nested-infinite-loops-discard.amber", "two-nested-infinite-loops-discard", "A fragment shader with an always false if function" }, - { "undefined-integer-in-function.amber", "undefined-integer-in-function", "A fragment shader with nested do while and undefined int" }, - { "uninitialized-var-decrement-and-add.amber", "uninitialized-var-decrement-and-add", "A fragment shader that uses an uninitialized variable" }, - { "undefined-assign-in-infinite-loop.amber", "undefined-assign-in-infinite-loop", "A fragment shader with uninitialized read in infinite loop" }, - { "unreachable-barrier-in-loops.amber", "unreachable-barrier-in-loops", "A compute shader with an unreachable barrier in a loop nest" }, - { "unreachable-continue-statement.amber", "unreachable-continue-statement", "A fragment shader with unreachable continue statement" }, - { "unreachable-discard-statement-in-if.amber", "unreachable-discard-statement-in-if", "A fragment shader with discard keyword and a return" }, - { "unreachable-discard-statement.amber", "unreachable-discard-statement", "A fragment shader with unreachable discard statement" }, - { "unreachable-loops.amber", "unreachable-loops", "Fragment shader that writes red despite unreachable loops" }, - { "unreachable-loops-in-switch.amber", "unreachable-loops-in-switch", "A fragment shader with unreachable loops in a switch" }, - { "unreachable-return-in-loop.amber", "unreachable-return-in-loop", "A fragment shader with an unreachable return in a loop" }, - { "while-function-always-false.amber", "while-function-always-false", "A fragment shader with an always false while function" }, - { "while-inside-switch.amber", "while-inside-switch", "A fragment shader that uses a while loop inside a switch" }, - { "write-before-break.amber", "write-before-break", "Fragment shader that writes red before loop break" }, - { "write-red-in-loop-nest.amber", "write-red-in-loop-nest", "A fragment shader that writes red in a nest of loops" }, - { "wrong-color-in-always-false-if.amber", "wrong-color-in-always-false-if", "A fragment shader with wrong color write in false if" }, - }; - - for (size_t i = 0; i < sizeof tests / sizeof tests[0]; i++) - group->addChild(createAmberTestCase(testCtx, tests[i].name, tests[i].description, "graphicsfuzz", tests[i].filename)); + createAmberTestsFromIndexFile(testCtx, group, "index.txt", "graphicsfuzz"); } } // anonymous diff --git a/external/vulkancts/modules/vulkan/amber/vktAmberTestCase.hpp b/external/vulkancts/modules/vulkan/amber/vktAmberTestCase.hpp index 8a04c9c..8027d29 100644 --- a/external/vulkancts/modules/vulkan/amber/vktAmberTestCase.hpp +++ b/external/vulkancts/modules/vulkan/amber/vktAmberTestCase.hpp @@ -118,6 +118,11 @@ AmberTestCase* createAmberTestCase (tcu::TestContext& testCtx, const std::string& filename, const std::vector requirements = std::vector()); +void createAmberTestsFromIndexFile (tcu::TestContext& testCtx, + tcu::TestCaseGroup* group, + const std::string filename, + const char* category); + } // cts_amber } // vkt diff --git a/external/vulkancts/modules/vulkan/amber/vktAmberTestCaseUtil.cpp b/external/vulkancts/modules/vulkan/amber/vktAmberTestCaseUtil.cpp index d585441..01553da 100644 --- a/external/vulkancts/modules/vulkan/amber/vktAmberTestCaseUtil.cpp +++ b/external/vulkancts/modules/vulkan/amber/vktAmberTestCaseUtil.cpp @@ -27,6 +27,180 @@ namespace vkt namespace cts_amber { +class AmberIndexFileParser +{ + char* m_buf; + size_t m_idx; + size_t m_len; + static const int m_fieldLen = 256; + char m_scratch[m_fieldLen]; + char m_filenameField[m_fieldLen]; + char m_testnameField[m_fieldLen]; + char m_descField[m_fieldLen]; + + bool isWhitespace (char c) + { + if (c == ' ' || + c == '\t' || + c == '\r' || + c == '\n') + { + return true; + } + return false; + } + + void skipWhitespace (void) + { + while (m_idx < m_len && isWhitespace(m_buf[m_idx])) + m_idx++; + } + + void accept (char c) + { + if (m_buf[m_idx] == c) + m_idx++; + } + + void expect (char c) + { + if (m_buf[m_idx] != c || m_idx >= m_len) + TCU_THROW(ResourceError, "Error parsing amber index file"); + + m_idx++; + } + + void captureString (char* field) + { + int i = 0; + + while (m_idx < m_len && i < m_fieldLen && m_buf[m_idx] != '"') + { + field[i] = m_buf[m_idx]; + i++; + m_idx++; + } + + field[i] = 0; + m_idx++; + } + + char* loadFile (const char* filename, size_t& len) + { + FILE* f = fopen(filename, "rb"); + + if (f == 0) + { + std::string error("Unable to open index file "); + error.append(filename); + TCU_THROW(ResourceError, error.c_str()); + } + + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + char* buf = new char[len + 1]; + + if (fread(buf, 1, len, f) != len) + { + delete[] buf; + fclose(f); + std::string error("File i/o error reading index file "); + error.append(filename); + TCU_THROW(ResourceError, error.c_str()); + } + + buf[len] = 0; + fclose(f); + return buf; + } + +public: + AmberIndexFileParser (const char* filename, const char* category) + { + std::string indexFilename("vulkan/amber/"); + indexFilename.append(category); + indexFilename.append("/"); + indexFilename.append(filename); + + m_buf = loadFile(indexFilename.c_str(), m_len); + m_idx = 0; + } + + ~AmberIndexFileParser (void) + { + delete[] m_buf; + } + + AmberTestCase* parse (const char* category, tcu::TestContext& testCtx) + { + // Format: + // {"filename","test name","description"[,requirement[,requirement[,requirement..]]]}[,] + // Things inside [] are optional. Whitespace is allowed everywhere. + // + // For example, test without requirements might be: + // {"testname.amber","test name","test description"}, + + if (m_idx < m_len) + { + skipWhitespace(); + expect('{'); + skipWhitespace(); + expect('"'); + captureString(m_filenameField); + skipWhitespace(); + expect(','); + skipWhitespace(); + expect('"'); + captureString(m_testnameField); + skipWhitespace(); + expect(','); + skipWhitespace(); + expect('"'); + captureString(m_descField); + skipWhitespace(); + + std::string testFilename("vulkan/amber/"); + testFilename.append(category); + testFilename.append("/"); + testFilename.append(m_filenameField); + AmberTestCase *testCase = new AmberTestCase(testCtx, m_testnameField, m_descField, testFilename); + + while (m_idx < m_len && m_buf[m_idx] == ',') + { + accept(','); + skipWhitespace(); + expect('"'); + captureString(m_scratch); + skipWhitespace(); + testCase->addRequirement(m_scratch); + } + + expect('}'); + skipWhitespace(); + accept(','); + skipWhitespace(); + return testCase; + } + return 0; + } +}; + +void createAmberTestsFromIndexFile (tcu::TestContext& testCtx, tcu::TestCaseGroup* group, const std::string filename, const char* category) +{ + AmberTestCase* testCase = 0; + AmberIndexFileParser parser(filename.c_str(), category); + + do + { + testCase = parser.parse(category, testCtx); + if (testCase) + { + group->addChild(testCase); + } + } while (testCase); +} + AmberTestCase* createAmberTestCase (tcu::TestContext& testCtx, const char* name, const char* description, -- 2.7.4