From: Jason Ekstrand Date: Tue, 6 Dec 2016 14:27:56 +0000 (+0100) Subject: Add OpSMod and OpSRem tests X-Git-Tag: upstream/0.1.0~558^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e47e81cda3ab7215d6089f4f5f631fa4f4385e10;p=platform%2Fupstream%2FVK-GL-CTS.git Add OpSMod and OpSRem tests New tests: - dEQP-VK.spirv_assembly.instruction.compute.opsrem.positive - dEQP-VK.spirv_assembly.instruction.compute.opsrem.all - dEQP-VK.spirv_assembly.instruction.compute.opsmod.positive - dEQP-VK.spirv_assembly.instruction.compute.opsmod.all - dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_* - dEQP-VK.spirv_assembly.instruction.graphics.srem.all_* - dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_* - dEQP-VK.spirv_assembly.instruction.graphics.smod.all_* Fixes #520 Change-Id: I16fe1e920960b7537ef097952e48dcdcc9141246 --- diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt index 28d3f69..0cfe1f6 100644 --- a/android/cts/master/vk-master.txt +++ b/android/cts/master/vk-master.txt @@ -94754,6 +94754,10 @@ dEQP-VK.spirv_assembly.instruction.compute.opquantize.flush_to_zero dEQP-VK.spirv_assembly.instruction.compute.opquantize.exact dEQP-VK.spirv_assembly.instruction.compute.opquantize.rounded dEQP-VK.spirv_assembly.instruction.compute.opfrem.all +dEQP-VK.spirv_assembly.instruction.compute.opsrem.positive +dEQP-VK.spirv_assembly.instruction.compute.opsrem.all +dEQP-VK.spirv_assembly.instruction.compute.opsmod.positive +dEQP-VK.spirv_assembly.instruction.compute.opsmod.all dEQP-VK.spirv_assembly.instruction.compute.sconvert.int16_to_int32 dEQP-VK.spirv_assembly.instruction.compute.sconvert.int16_to_int64 dEQP-VK.spirv_assembly.instruction.compute.sconvert.int32_to_int64 @@ -95639,6 +95643,26 @@ dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_tessc dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_tesse dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_geom dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_frag +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_vert +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_tessc +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_tesse +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_geom +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_frag +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_vert +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_tessc +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_tesse +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_geom +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_frag +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_vert +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_tessc +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_tesse +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_geom +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_frag +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_vert +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_tessc +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_tesse +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_geom +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_frag dEQP-VK.glsl.arrays.constructor.float3_vertex dEQP-VK.glsl.arrays.constructor.float3_fragment dEQP-VK.glsl.arrays.constructor.float4_vertex diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp index 8a560ad..b2247ca 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp @@ -404,7 +404,7 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void) if (m_shaderSpec.verifyIO) { if (!(*m_shaderSpec.verifyIO)(m_shaderSpec.inputs, outputAllocs, m_shaderSpec.outputs, m_context.getTestContext().getLog())) - return tcu::TestStatus::fail("Output doesn't match with expected"); + return tcu::TestStatus(m_shaderSpec.failResult, m_shaderSpec.failMessage); } else { @@ -412,11 +412,11 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void) { const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx]; if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes())) - return tcu::TestStatus::fail("Output doesn't match with expected"); + return tcu::TestStatus(m_shaderSpec.failResult, m_shaderSpec.failMessage); } } - return tcu::TestStatus::pass("Ouput match with expected"); + return tcu::TestStatus::pass("Output match with expected"); } class ConvertTestInstance : public SpvAsmComputeShaderInstance diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp index 4c6b644..1f0551d 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp @@ -95,16 +95,20 @@ struct ComputeShaderSpec std::vector outputs; tcu::IVec3 numWorkGroups; std::vector specConstants; + qpTestResult failResult; + std::string failMessage; // If null, a default verification will be performed by comparing the memory pointed to by outputAllocations // and the contents of expectedOutputs. Otherwise the function pointed to by verifyIO will be called. // If true is returned, then the test case is assumed to have passed, if false is returned, then the test - // case is assumed to have failed. + // case is assumed to have failed. Exact meaning of failure can be customized with failResult. bool (*verifyIO)(const std::vector& inputs, const std::vector& outputAllocations, const std::vector& expectedOutputs, tcu::TestLog& log); - ComputeShaderSpec() + + ComputeShaderSpec (void) : entryPoint ("main") + , failResult (QP_TEST_RESULT_FAIL) + , failMessage ("Output doesn't match with expected") , verifyIO (DE_NULL) {} - }; } // SpirVAssembly diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp index 3887f80..1df4a02 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp @@ -3,6 +3,7 @@ * ------------------------ * * Copyright (c) 2015 Google Inc. + * Copyright (c) 2016 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. @@ -47,7 +48,6 @@ #include "deUniquePtr.hpp" #include "tcuStringTemplate.hpp" -#include #include "vktSpvAsmComputeShaderCase.hpp" #include "vktSpvAsmComputeShaderTestUtil.hpp" #include "vktTestCaseUtil.hpp" @@ -57,6 +57,7 @@ #include #include #include +#include namespace vkt { @@ -95,6 +96,27 @@ static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* ds typedPtr[offset + ndx] = randomScalar(rnd, minValue, maxValue); } +// Filter is a function that returns true if a value should pass, false otherwise. +template +static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, FilterT filter, int offset = 0) +{ + T* const typedPtr = (T*)dst; + T value; + for (int ndx = 0; ndx < numValues; ndx++) + { + do + value = randomScalar(rnd, minValue, maxValue); + while (!filter(value)); + + typedPtr[offset + ndx] = value; + } +} + +inline bool filterNotZero (const deInt32 value) +{ + return value != 0; +} + static void floorAll (vector& values) { for (size_t i = 0; i < values.size(); i++) @@ -840,6 +862,212 @@ tcu::TestCaseGroup* createOpFRemGroup (tcu::TestContext& testCtx) return group.release(); } +tcu::TestCaseGroup* createOpSRemGroup (tcu::TestContext& testCtx) +{ + de::MovePtr group (new tcu::TestCaseGroup(testCtx, "opsrem", "Test the OpSRem instruction")); + de::Random rnd (deStringHash(group->getName())); + const int numElements = 200; + + const struct CaseParams + { + const char* name; + const char* failMessage; // customized status message + qpTestResult failResult; // override status on failure + int op1Min, op1Max; // operand ranges + int op2Min, op2Max; + } cases[] = + { + { "positive", "Output doesn't match with expected", QP_TEST_RESULT_FAIL, 0, 65536, 0, 100 }, + { "all", "Inconsistent results, but within specification", QP_TEST_RESULT_PASS, -65536, 65536, -100, 100 }, // see below + }; + // If either operand is negative the result is undefined. Some implementations may still return correct values. + + for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) + { + const CaseParams& params = cases[caseNdx]; + ComputeShaderSpec spec; + vector inputInts1 (numElements, 0); + vector inputInts2 (numElements, 0); + vector outputInts (numElements, 0); + + fillRandomScalars(rnd, params.op1Min, params.op1Max, &inputInts1[0], numElements); + fillRandomScalars(rnd, params.op2Min, params.op2Max, &inputInts2[0], numElements, filterNotZero); + + for (int ndx = 0; ndx < numElements; ++ndx) + { + // The return value of std::fmod() has the same sign as its first operand, which is how OpFRem spec'd. + outputInts[ndx] = inputInts1[ndx] % inputInts2[ndx]; + } + + spec.assembly = + string(s_ShaderPreamble) + + + "OpName %main \"main\"\n" + "OpName %id \"gl_GlobalInvocationID\"\n" + + "OpDecorate %id BuiltIn GlobalInvocationId\n" + + "OpDecorate %buf BufferBlock\n" + "OpDecorate %indata1 DescriptorSet 0\n" + "OpDecorate %indata1 Binding 0\n" + "OpDecorate %indata2 DescriptorSet 0\n" + "OpDecorate %indata2 Binding 1\n" + "OpDecorate %outdata DescriptorSet 0\n" + "OpDecorate %outdata Binding 2\n" + "OpDecorate %i32arr ArrayStride 4\n" + "OpMemberDecorate %buf 0 Offset 0\n" + + + string(s_CommonTypes) + + + "%buf = OpTypeStruct %i32arr\n" + "%bufptr = OpTypePointer Uniform %buf\n" + "%indata1 = OpVariable %bufptr Uniform\n" + "%indata2 = OpVariable %bufptr Uniform\n" + "%outdata = OpVariable %bufptr Uniform\n" + + "%id = OpVariable %uvec3ptr Input\n" + "%zero = OpConstant %i32 0\n" + + "%main = OpFunction %void None %voidf\n" + "%label = OpLabel\n" + "%idval = OpLoad %uvec3 %id\n" + "%x = OpCompositeExtract %u32 %idval 0\n" + "%inloc1 = OpAccessChain %i32ptr %indata1 %zero %x\n" + "%inval1 = OpLoad %i32 %inloc1\n" + "%inloc2 = OpAccessChain %i32ptr %indata2 %zero %x\n" + "%inval2 = OpLoad %i32 %inloc2\n" + "%rem = OpSRem %i32 %inval1 %inval2\n" + "%outloc = OpAccessChain %i32ptr %outdata %zero %x\n" + " OpStore %outloc %rem\n" + " OpReturn\n" + " OpFunctionEnd\n"; + + spec.inputs.push_back (BufferSp(new Int32Buffer(inputInts1))); + spec.inputs.push_back (BufferSp(new Int32Buffer(inputInts2))); + spec.outputs.push_back (BufferSp(new Int32Buffer(outputInts))); + spec.numWorkGroups = IVec3(numElements, 1, 1); + spec.failResult = params.failResult; + spec.failMessage = params.failMessage; + + group->addChild(new SpvAsmComputeShaderCase(testCtx, params.name, "", spec)); + } + + return group.release(); +} + +tcu::TestCaseGroup* createOpSModGroup (tcu::TestContext& testCtx) +{ + de::MovePtr group (new tcu::TestCaseGroup(testCtx, "opsmod", "Test the OpSMod instruction")); + de::Random rnd (deStringHash(group->getName())); + const int numElements = 200; + + const struct CaseParams + { + const char* name; + const char* failMessage; // customized status message + qpTestResult failResult; // override status on failure + int op1Min, op1Max; // operand ranges + int op2Min, op2Max; + } cases[] = + { + { "positive", "Output doesn't match with expected", QP_TEST_RESULT_FAIL, 0, 65536, 0, 100 }, + { "all", "Inconsistent results, but within specification", QP_TEST_RESULT_PASS, -65536, 65536, -100, 100 }, // see below + }; + // If either operand is negative the result is undefined. Some implementations may still return correct values. + + for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) + { + const CaseParams& params = cases[caseNdx]; + + ComputeShaderSpec spec; + vector inputInts1 (numElements, 0); + vector inputInts2 (numElements, 0); + vector outputInts (numElements, 0); + + fillRandomScalars(rnd, params.op1Min, params.op1Max, &inputInts1[0], numElements); + fillRandomScalars(rnd, params.op2Min, params.op2Max, &inputInts2[0], numElements, filterNotZero); + + for (int ndx = 0; ndx < numElements; ++ndx) + { + deInt32 rem = inputInts1[ndx] % inputInts2[ndx]; + if (rem == 0) + { + outputInts[ndx] = 0; + } + else if ((inputInts1[ndx] >= 0) == (inputInts2[ndx] >= 0)) + { + // They have the same sign + outputInts[ndx] = rem; + } + else + { + // They have opposite sign. The remainder operation takes the + // sign inputInts1[ndx] but OpSMod is supposed to take ths sign + // of inputInts2[ndx]. Adding inputInts2[ndx] will ensure that + // the result has the correct sign and that it is still + // congruent to inputInts1[ndx] modulo inputInts2[ndx] + // + // See also http://mathforum.org/library/drmath/view/52343.html + outputInts[ndx] = rem + inputInts2[ndx]; + } + } + + spec.assembly = + string(s_ShaderPreamble) + + + "OpName %main \"main\"\n" + "OpName %id \"gl_GlobalInvocationID\"\n" + + "OpDecorate %id BuiltIn GlobalInvocationId\n" + + "OpDecorate %buf BufferBlock\n" + "OpDecorate %indata1 DescriptorSet 0\n" + "OpDecorate %indata1 Binding 0\n" + "OpDecorate %indata2 DescriptorSet 0\n" + "OpDecorate %indata2 Binding 1\n" + "OpDecorate %outdata DescriptorSet 0\n" + "OpDecorate %outdata Binding 2\n" + "OpDecorate %i32arr ArrayStride 4\n" + "OpMemberDecorate %buf 0 Offset 0\n" + + + string(s_CommonTypes) + + + "%buf = OpTypeStruct %i32arr\n" + "%bufptr = OpTypePointer Uniform %buf\n" + "%indata1 = OpVariable %bufptr Uniform\n" + "%indata2 = OpVariable %bufptr Uniform\n" + "%outdata = OpVariable %bufptr Uniform\n" + + "%id = OpVariable %uvec3ptr Input\n" + "%zero = OpConstant %i32 0\n" + + "%main = OpFunction %void None %voidf\n" + "%label = OpLabel\n" + "%idval = OpLoad %uvec3 %id\n" + "%x = OpCompositeExtract %u32 %idval 0\n" + "%inloc1 = OpAccessChain %i32ptr %indata1 %zero %x\n" + "%inval1 = OpLoad %i32 %inloc1\n" + "%inloc2 = OpAccessChain %i32ptr %indata2 %zero %x\n" + "%inval2 = OpLoad %i32 %inloc2\n" + "%rem = OpSMod %i32 %inval1 %inval2\n" + "%outloc = OpAccessChain %i32ptr %outdata %zero %x\n" + " OpStore %outloc %rem\n" + " OpReturn\n" + " OpFunctionEnd\n"; + + spec.inputs.push_back (BufferSp(new Int32Buffer(inputInts1))); + spec.inputs.push_back (BufferSp(new Int32Buffer(inputInts2))); + spec.outputs.push_back (BufferSp(new Int32Buffer(outputInts))); + spec.numWorkGroups = IVec3(numElements, 1, 1); + spec.failResult = params.failResult; + spec.failMessage = params.failMessage; + + group->addChild(new SpvAsmComputeShaderCase(testCtx, params.name, "", spec)); + } + + return group.release(); +} + // Copy contents in the input buffer to the output buffer. tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx) { @@ -3496,12 +3724,16 @@ struct InstanceContext StageToSpecConstantMap specConstants; bool hasTessellation; VkShaderStageFlagBits requiredStages; + qpTestResult failResult; + string failMessageTemplate; //!< ${reason} in the template will be replaced with a detailed failure message InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map& testCodeFragments_, const StageToSpecConstantMap& specConstants_) : testCodeFragments (testCodeFragments_) , specConstants (specConstants_) , hasTessellation (false) , requiredStages (static_cast(0)) + , failResult (QP_TEST_RESULT_FAIL) + , failMessageTemplate ("${reason}") { inputColors[0] = inputs[0]; inputColors[1] = inputs[1]; @@ -3515,11 +3747,13 @@ struct InstanceContext } InstanceContext (const InstanceContext& other) - : moduleMap (other.moduleMap) - , testCodeFragments (other.testCodeFragments) - , specConstants (other.specConstants) - , hasTessellation (other.hasTessellation) - , requiredStages (other.requiredStages) + : moduleMap (other.moduleMap) + , testCodeFragments (other.testCodeFragments) + , specConstants (other.specConstants) + , hasTessellation (other.hasTessellation) + , requiredStages (other.requiredStages) + , failResult (other.failResult) + , failMessageTemplate (other.failMessageTemplate) { inputColors[0] = other.inputColors[0]; inputColors[1] = other.inputColors[1]; @@ -3531,6 +3765,13 @@ struct InstanceContext outputColors[2] = other.outputColors[2]; outputColors[3] = other.outputColors[3]; } + + string getSpecializedFailMessage (const string& failureReason) + { + map parameters; + parameters["reason"] = failureReason; + return StringTemplate(failMessageTemplate).specialize(parameters); + } }; // A description of a shader to be used for a single stage of the graphics pipeline. @@ -3581,7 +3822,13 @@ void getInvertedDefaultColors (RGBA (&colors)[4]) // by setting up the mapping of modules to their contained shaders and stages. // The inputs and expected outputs are given by inputColors and outputColors template -InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map& testCodeFragments, const StageToSpecConstantMap& specConstants) +InstanceContext createInstanceContext (const ShaderElement (&elements)[N], + const RGBA (&inputColors)[4], + const RGBA (&outputColors)[4], + const map& testCodeFragments, + const StageToSpecConstantMap& specConstants, + const qpTestResult failResult = QP_TEST_RESULT_FAIL, + const string& failMessageTemplate = string()) { InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants); for (size_t i = 0; i < N; ++i) @@ -3589,18 +3836,25 @@ InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage)); ctx.requiredStages = static_cast(ctx.requiredStages | elements[i].stage); } + ctx.failResult = failResult; + if (!failMessageTemplate.empty()) + ctx.failMessageTemplate = failMessageTemplate; return ctx; } template -inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map& testCodeFragments) +inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], + RGBA (&inputColors)[4], + const RGBA (&outputColors)[4], + const map& testCodeFragments) { return createInstanceContext(elements, inputColors, outputColors, testCodeFragments, StageToSpecConstantMap()); } // The same as createInstanceContext above, but with default colors. template -InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const map& testCodeFragments) +InstanceContext createInstanceContext (const ShaderElement (&elements)[N], + const map& testCodeFragments) { RGBA defaultColors[4]; getDefaultColors(defaultColors); @@ -3641,6 +3895,7 @@ void createPipelineShaderStages (const DeviceInterface& vk, const VkDevice vkDev \ "%f32 = OpTypeFloat 32\n" \ "%v3f32 = OpTypeVector %f32 3\n" \ + "%v4i32 = OpTypeVector %i32 4\n" \ "%v4f32 = OpTypeVector %f32 4\n" \ "%v4bool = OpTypeVector %bool 4\n" \ \ @@ -5589,24 +5844,31 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan const RGBA threshold(1, 1, 1, 1); const RGBA upperLeft(pixelBuffer.getPixel(1, 1)); if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold)) - return TestStatus::fail("Upper left corner mismatch"); + return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper left corner mismatch")); const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1)); if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold)) - return TestStatus::fail("Upper right corner mismatch"); + return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper right corner mismatch")); const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1)); if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold)) - return TestStatus::fail("Lower left corner mismatch"); + return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower left corner mismatch")); const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1)); if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold)) - return TestStatus::fail("Lower right corner mismatch"); + return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower right corner mismatch")); return TestStatus::pass("Rendered output matches input"); } -void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map& testCodeFragments, const vector& specConstants, tcu::TestCaseGroup* tests) +void createTestsForAllStages (const std::string& name, + const RGBA (&inputColors)[4], + const RGBA (&outputColors)[4], + const map& testCodeFragments, + const vector& specConstants, + tcu::TestCaseGroup* tests, + const qpTestResult failResult = QP_TEST_RESULT_FAIL, + const string& failMessageTemplate = string()) { const ShaderElement vertFragPipelineStages[] = { @@ -5633,33 +5895,39 @@ void createTestsForAllStages (const std::string& name, const RGBA (&inputColors) specConstantMap[VK_SHADER_STAGE_VERTEX_BIT] = specConstants; addFunctionCaseWithPrograms(tests, name + "_vert", "", addShaderCodeCustomVertex, runAndVerifyDefaultPipeline, - createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap)); + createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap, failResult, failMessageTemplate)); specConstantMap.clear(); specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants; addFunctionCaseWithPrograms(tests, name + "_tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline, - createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap)); + createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap, failResult, failMessageTemplate)); specConstantMap.clear(); specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants; addFunctionCaseWithPrograms(tests, name + "_tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline, - createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap)); + createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap, failResult, failMessageTemplate)); specConstantMap.clear(); specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants; addFunctionCaseWithPrograms(tests, name + "_geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline, - createInstanceContext(geomPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap)); + createInstanceContext(geomPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap, failResult, failMessageTemplate)); specConstantMap.clear(); specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants; addFunctionCaseWithPrograms(tests, name + "_frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline, - createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap)); + createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap, failResult, failMessageTemplate)); } -inline void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map& testCodeFragments, tcu::TestCaseGroup* tests) +inline void createTestsForAllStages (const string& name, + const RGBA (&inputColors)[4], + const RGBA (&outputColors)[4], + const map& testCodeFragments, + tcu::TestCaseGroup* tests, + const qpTestResult failResult = QP_TEST_RESULT_FAIL, + const string& failMessageTemplate = string()) { vector noSpecConstants; - createTestsForAllStages(name, inputColors, outputColors, testCodeFragments, noSpecConstants, tests); + createTestsForAllStages(name, inputColors, outputColors, testCodeFragments, noSpecConstants, tests, failResult, failMessageTemplate); } } // anonymous @@ -7916,6 +8184,172 @@ tcu::TestCaseGroup* createFRemTests(tcu::TestContext& testCtx) return testGroup.release(); } +// Test for the OpSRem instruction. +tcu::TestCaseGroup* createSRemTests(tcu::TestContext& testCtx) +{ + de::MovePtr testGroup(new tcu::TestCaseGroup(testCtx, "srem", "OpSRem")); + map fragments; + + fragments["pre_main"] = + "%c_f32_255 = OpConstant %f32 255.0\n" + "%c_i32_128 = OpConstant %i32 128\n" + "%c_i32_255 = OpConstant %i32 255\n" + "%c_v4f32_255 = OpConstantComposite %v4f32 %c_f32_255 %c_f32_255 %c_f32_255 %c_f32_255 \n" + "%c_v4f32_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 \n" + "%c_v4i32_128 = OpConstantComposite %v4i32 %c_i32_128 %c_i32_128 %c_i32_128 %c_i32_128 \n"; + + // The test does the following. + // ivec4 ints = int(param1 * 255.0 + 0.5) - 128; + // ivec4 result = ivec4(srem(ints.x, ints.y), srem(ints.y, ints.z), srem(ints.z, ints.x), 255); + // return float(result + 128) / 255.0; + fragments["testfun"] = + "%test_code = OpFunction %v4f32 None %v4f32_function\n" + "%param1 = OpFunctionParameter %v4f32\n" + "%label_testfun = OpLabel\n" + "%div255 = OpFMul %v4f32 %param1 %c_v4f32_255\n" + "%add0_5 = OpFAdd %v4f32 %div255 %c_v4f32_0_5\n" + "%uints_in = OpConvertFToS %v4i32 %add0_5\n" + "%ints_in = OpISub %v4i32 %uints_in %c_v4i32_128\n" + "%x_in = OpCompositeExtract %i32 %ints_in 0\n" + "%y_in = OpCompositeExtract %i32 %ints_in 1\n" + "%z_in = OpCompositeExtract %i32 %ints_in 2\n" + "%x_out = OpSRem %i32 %x_in %y_in\n" + "%y_out = OpSRem %i32 %y_in %z_in\n" + "%z_out = OpSRem %i32 %z_in %x_in\n" + "%ints_out = OpCompositeConstruct %v4i32 %x_out %y_out %z_out %c_i32_255\n" + "%ints_offset = OpIAdd %v4i32 %ints_out %c_v4i32_128\n" + "%f_ints_offset = OpConvertSToF %v4f32 %ints_offset\n" + "%float_out = OpFDiv %v4f32 %f_ints_offset %c_v4f32_255\n" + "OpReturnValue %float_out\n" + "OpFunctionEnd\n"; + + const struct CaseParams + { + const char* name; + const char* failMessageTemplate; // customized status message + qpTestResult failResult; // override status on failure + int operands[4][3]; // four (x, y, z) vectors of operands + int results[4][3]; // four (x, y, z) vectors of results + } cases[] = + { + { + "positive", + "${reason}", + QP_TEST_RESULT_FAIL, + { { 5, 12, 17 }, { 5, 5, 7 }, { 75, 8, 81 }, { 25, 60, 100 } }, // operands + { { 5, 12, 2 }, { 0, 5, 2 }, { 3, 8, 6 }, { 25, 60, 0 } }, // results + }, + { + "all", + "Inconsistent results, but within specification: ${reason}", + QP_TEST_RESULT_PASS, // negative operands, not required by the spec + { { 5, 12, -17 }, { -5, -5, 7 }, { 75, 8, -81 }, { 25, -60, 100 } }, // operands + { { 5, 12, -2 }, { 0, -5, 2 }, { 3, 8, -6 }, { 25, -60, 0 } }, // results + }, + }; + // If either operand is negative the result is undefined. Some implementations may still return correct values. + + for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) + { + const CaseParams& params = cases[caseNdx]; + RGBA inputColors[4]; + RGBA outputColors[4]; + + for (int i = 0; i < 4; ++i) + { + inputColors [i] = RGBA(params.operands[i][0] + 128, params.operands[i][1] + 128, params.operands[i][2] + 128, 255); + outputColors[i] = RGBA(params.results [i][0] + 128, params.results [i][1] + 128, params.results [i][2] + 128, 255); + } + + createTestsForAllStages(params.name, inputColors, outputColors, fragments, testGroup.get(), params.failResult, params.failMessageTemplate); + } + + return testGroup.release(); +} + +// Test for the OpSMod instruction. +tcu::TestCaseGroup* createSModTests(tcu::TestContext& testCtx) +{ + de::MovePtr testGroup(new tcu::TestCaseGroup(testCtx, "smod", "OpSMod")); + map fragments; + + fragments["pre_main"] = + "%c_f32_255 = OpConstant %f32 255.0\n" + "%c_i32_128 = OpConstant %i32 128\n" + "%c_i32_255 = OpConstant %i32 255\n" + "%c_v4f32_255 = OpConstantComposite %v4f32 %c_f32_255 %c_f32_255 %c_f32_255 %c_f32_255 \n" + "%c_v4f32_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 \n" + "%c_v4i32_128 = OpConstantComposite %v4i32 %c_i32_128 %c_i32_128 %c_i32_128 %c_i32_128 \n"; + + // The test does the following. + // ivec4 ints = int(param1 * 255.0 + 0.5) - 128; + // ivec4 result = ivec4(smod(ints.x, ints.y), smod(ints.y, ints.z), smod(ints.z, ints.x), 255); + // return float(result + 128) / 255.0; + fragments["testfun"] = + "%test_code = OpFunction %v4f32 None %v4f32_function\n" + "%param1 = OpFunctionParameter %v4f32\n" + "%label_testfun = OpLabel\n" + "%div255 = OpFMul %v4f32 %param1 %c_v4f32_255\n" + "%add0_5 = OpFAdd %v4f32 %div255 %c_v4f32_0_5\n" + "%uints_in = OpConvertFToS %v4i32 %add0_5\n" + "%ints_in = OpISub %v4i32 %uints_in %c_v4i32_128\n" + "%x_in = OpCompositeExtract %i32 %ints_in 0\n" + "%y_in = OpCompositeExtract %i32 %ints_in 1\n" + "%z_in = OpCompositeExtract %i32 %ints_in 2\n" + "%x_out = OpSMod %i32 %x_in %y_in\n" + "%y_out = OpSMod %i32 %y_in %z_in\n" + "%z_out = OpSMod %i32 %z_in %x_in\n" + "%ints_out = OpCompositeConstruct %v4i32 %x_out %y_out %z_out %c_i32_255\n" + "%ints_offset = OpIAdd %v4i32 %ints_out %c_v4i32_128\n" + "%f_ints_offset = OpConvertSToF %v4f32 %ints_offset\n" + "%float_out = OpFDiv %v4f32 %f_ints_offset %c_v4f32_255\n" + "OpReturnValue %float_out\n" + "OpFunctionEnd\n"; + + const struct CaseParams + { + const char* name; + const char* failMessageTemplate; // customized status message + qpTestResult failResult; // override status on failure + int operands[4][3]; // four (x, y, z) vectors of operands + int results[4][3]; // four (x, y, z) vectors of results + } cases[] = + { + { + "positive", + "${reason}", + QP_TEST_RESULT_FAIL, + { { 5, 12, 17 }, { 5, 5, 7 }, { 75, 8, 81 }, { 25, 60, 100 } }, // operands + { { 5, 12, 2 }, { 0, 5, 2 }, { 3, 8, 6 }, { 25, 60, 0 } }, // results + }, + { + "all", + "Inconsistent results, but within specification: ${reason}", + QP_TEST_RESULT_PASS, // negative operands, not required by the spec + { { 5, 12, -17 }, { -5, -5, 7 }, { 75, 8, -81 }, { 25, -60, 100 } }, // operands + { { 5, -5, 3 }, { 0, 2, -3 }, { 3, -73, 69 }, { -35, 40, 0 } }, // results + }, + }; + // If either operand is negative the result is undefined. Some implementations may still return correct values. + + for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) + { + const CaseParams& params = cases[caseNdx]; + RGBA inputColors[4]; + RGBA outputColors[4]; + + for (int i = 0; i < 4; ++i) + { + inputColors [i] = RGBA(params.operands[i][0] + 128, params.operands[i][1] + 128, params.operands[i][2] + 128, 255); + outputColors[i] = RGBA(params.results [i][0] + 128, params.results [i][1] + 128, params.results [i][2] + 128, 255); + } + + createTestsForAllStages(params.name, inputColors, outputColors, fragments, testGroup.get(), params.failResult, params.failMessageTemplate); + } + + return testGroup.release(); +} + enum IntegerType { INTEGER_TYPE_SIGNED_16, @@ -8962,6 +9396,8 @@ tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx) computeTests->addChild(createOpUnreachableGroup(testCtx)); computeTests ->addChild(createOpQuantizeToF16Group(testCtx)); computeTests ->addChild(createOpFRemGroup(testCtx)); + computeTests->addChild(createOpSRemGroup(testCtx)); + computeTests->addChild(createOpSModGroup(testCtx)); computeTests->addChild(createSConvertTests(testCtx)); computeTests->addChild(createUConvertTests(testCtx)); computeTests->addChild(createOpCompositeInsertGroup(testCtx)); @@ -9019,6 +9455,8 @@ tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx) graphicsTests->addChild(createBarrierTests(testCtx)); graphicsTests->addChild(createDecorationGroupTests(testCtx)); graphicsTests->addChild(createFRemTests(testCtx)); + graphicsTests->addChild(createSRemTests(testCtx)); + graphicsTests->addChild(createSModTests(testCtx)); instructionTests->addChild(computeTests.release()); instructionTests->addChild(graphicsTests.release()); diff --git a/external/vulkancts/mustpass/1.0.2/vk-default.txt b/external/vulkancts/mustpass/1.0.2/vk-default.txt index 9eb9ab6..6c6519e 100644 --- a/external/vulkancts/mustpass/1.0.2/vk-default.txt +++ b/external/vulkancts/mustpass/1.0.2/vk-default.txt @@ -89502,6 +89502,10 @@ dEQP-VK.spirv_assembly.instruction.compute.opquantize.flush_to_zero dEQP-VK.spirv_assembly.instruction.compute.opquantize.exact dEQP-VK.spirv_assembly.instruction.compute.opquantize.rounded dEQP-VK.spirv_assembly.instruction.compute.opfrem.all +dEQP-VK.spirv_assembly.instruction.compute.opsrem.positive +dEQP-VK.spirv_assembly.instruction.compute.opsrem.all +dEQP-VK.spirv_assembly.instruction.compute.opsmod.positive +dEQP-VK.spirv_assembly.instruction.compute.opsmod.all dEQP-VK.spirv_assembly.instruction.compute.sconvert.int16_to_int32 dEQP-VK.spirv_assembly.instruction.compute.sconvert.int16_to_int64 dEQP-VK.spirv_assembly.instruction.compute.sconvert.int32_to_int64 @@ -90387,6 +90391,26 @@ dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_tessc dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_tesse dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_geom dEQP-VK.spirv_assembly.instruction.graphics.frem.frem_frag +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_vert +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_tessc +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_tesse +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_geom +dEQP-VK.spirv_assembly.instruction.graphics.srem.positive_frag +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_vert +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_tessc +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_tesse +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_geom +dEQP-VK.spirv_assembly.instruction.graphics.srem.all_frag +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_vert +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_tessc +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_tesse +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_geom +dEQP-VK.spirv_assembly.instruction.graphics.smod.positive_frag +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_vert +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_tessc +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_tesse +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_geom +dEQP-VK.spirv_assembly.instruction.graphics.smod.all_frag dEQP-VK.glsl.arrays.constructor.float3_vertex dEQP-VK.glsl.arrays.constructor.float3_fragment dEQP-VK.glsl.arrays.constructor.float4_vertex