1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Google LLC
6 * Copyright (c) 2019 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Functional tests using amber
23 *//*--------------------------------------------------------------------*/
24
25 #include <amber/amber.h>
26 #include "amber/recipe.h"
27
28 #include <iostream>
29
30 #include "deDefs.hpp"
31 #include "deUniquePtr.hpp"
32 #include "deFilePath.hpp"
33 #include "vkPrograms.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "tcuTestLog.hpp"
36 #include "vktAmberTestCase.hpp"
37 #include "vktAmberHelper.hpp"
38 #include "tcuResource.hpp"
39 #include "tcuTestLog.hpp"
40 #include "vkSpirVProgram.hpp"
41 #include "vkImageUtil.hpp"
42
43 namespace vkt
44 {
45 namespace cts_amber
46 {
47
AmberTestCase(tcu::TestContext & testCtx,const char * name,const char * description,const std::string & readFilename)48 AmberTestCase::AmberTestCase(tcu::TestContext &testCtx, const char *name, const char *description,
49 const std::string &readFilename)
50 : TestCase(testCtx, name)
51 , m_recipe(nullptr)
52 , m_readFilename(readFilename)
53 {
54 (void)description;
55 }
56
~AmberTestCase(void)57 AmberTestCase::~AmberTestCase(void)
58 {
59 delete m_recipe;
60 }
61
createInstance(Context & ctx) const62 TestInstance *AmberTestCase::createInstance(Context &ctx) const
63 {
64 return new AmberTestInstance(ctx, m_recipe, nullptr);
65 }
66
createEngineConfig(Context & ctx,vk::VkDevice customDevice)67 static amber::EngineConfig *createEngineConfig(Context &ctx, vk::VkDevice customDevice)
68 {
69 vk::VkDevice dev = customDevice != nullptr ? customDevice : ctx.getDevice();
70 vk::VkQueue queue;
71 vk::DeviceDriver vk(ctx.getPlatformInterface(), ctx.getInstance(), dev, ctx.getUsedApiVersion(),
72 ctx.getTestContext().getCommandLine());
73 vk.getDeviceQueue(dev, ctx.getUniversalQueueFamilyIndex(), 0, &queue);
74
75 amber::EngineConfig *vkConfig = GetVulkanConfig(
76 ctx.getInstance(), ctx.getPhysicalDevice(), dev, &ctx.getDeviceFeatures(), &ctx.getDeviceFeatures2(),
77 &ctx.getDeviceProperties(), &ctx.getDeviceProperties2(), ctx.getInstanceExtensions(), ctx.getDeviceExtensions(),
78 ctx.getUniversalQueueFamilyIndex(), queue, ctx.getInstanceProcAddr());
79
80 return vkConfig;
81 }
82
83 // Returns true if the given feature is supported by the device.
84 // Throws an internal error If the feature is not recognized at all.
isFeatureSupported(const vkt::Context & ctx,const std::string & feature)85 static bool isFeatureSupported(const vkt::Context &ctx, const std::string &feature)
86 {
87 if (feature == "Storage16BitFeatures.storageBuffer16BitAccess")
88 return ctx.get16BitStorageFeatures().storageBuffer16BitAccess;
89 if (feature == "Float16Int8Features.shaderFloat16")
90 return ctx.getShaderFloat16Int8Features().shaderFloat16;
91 if (feature == "Float16Int8Features.shaderInt8")
92 return ctx.getShaderFloat16Int8Features().shaderInt8;
93 if (feature == "Features.shaderFloat64")
94 return ctx.getDeviceFeatures().shaderFloat64;
95 if (feature == "Features.shaderInt16")
96 return ctx.getDeviceFeatures().shaderInt16;
97 if (feature == "Features.shaderInt64")
98 return ctx.getDeviceFeatures().shaderInt64;
99 if (feature == "Features.depthClamp")
100 return ctx.getDeviceFeatures().depthClamp;
101 if (feature == "Features.tessellationShader")
102 return ctx.getDeviceFeatures().tessellationShader;
103 if (feature == "Features.shaderTessellationAndGeometryPointSize")
104 return ctx.getDeviceFeatures().shaderTessellationAndGeometryPointSize;
105 if (feature == "Features.geometryShader")
106 return ctx.getDeviceFeatures().geometryShader;
107 if (feature == "Features.fragmentStoresAndAtomics")
108 return ctx.getDeviceFeatures().fragmentStoresAndAtomics;
109 if (feature == "Features.vertexPipelineStoresAndAtomics")
110 return ctx.getDeviceFeatures().vertexPipelineStoresAndAtomics;
111 if (feature == "Features.fillModeNonSolid")
112 return ctx.getDeviceFeatures().fillModeNonSolid;
113 if (feature == "Features.shaderStorageImageMultisample")
114 return ctx.getDeviceFeatures().shaderStorageImageMultisample;
115 if (feature == "Features.sampleRateShading")
116 return ctx.getDeviceFeatures().sampleRateShading;
117 if (feature == "VariablePointerFeatures.variablePointersStorageBuffer")
118 return ctx.getVariablePointersFeatures().variablePointersStorageBuffer;
119 if (feature == "VariablePointerFeatures.variablePointers")
120 return ctx.getVariablePointersFeatures().variablePointers;
121 if (feature == "SubgroupSupportedStages.fragment")
122 return (ctx.getSubgroupProperties().supportedStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
123 if (feature == "SubgroupSupportedOperations.vote")
124 return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_VOTE_BIT) != 0;
125 if (feature == "SubgroupSupportedOperations.basic")
126 return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
127 if (feature == "SubgroupSupportedOperations.ballot")
128 return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0;
129 if (feature == "Storage16BitFeatures.storageBuffer16BitAccess")
130 return ctx.get16BitStorageFeatures().storageBuffer16BitAccess;
131 if (feature == "Storage8BitFeatures.storageBuffer8BitAccess")
132 return ctx.get8BitStorageFeatures().storageBuffer8BitAccess;
133 if (feature == "IndexTypeUint8Features.indexTypeUint8")
134 return ctx.getIndexTypeUint8Features().indexTypeUint8;
135 if (feature == "RayTracingPipelineFeaturesKHR.rayTracingPipeline")
136 return ctx.getRayTracingPipelineFeatures().rayTracingPipeline;
137 if (feature == "AccelerationStructureFeaturesKHR.accelerationStructure")
138 return ctx.getAccelerationStructureFeatures().accelerationStructure;
139 if (feature == "BufferDeviceAddressFeatures.bufferDeviceAddress")
140 return ctx.getBufferDeviceAddressFeatures().bufferDeviceAddress;
141
142 std::string message = std::string("Unexpected feature name: ") + feature;
143 TCU_THROW(InternalError, message.c_str());
144 }
145
146 // Returns true if the given property is supported by the device.
147 // Throws an internal error if the property is not recognized at all.
isPropertySupported(const vkt::Context & ctx,const std::string & prop)148 static bool isPropertySupported(const vkt::Context &ctx, const std::string &prop)
149 {
150 if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat16")
151 return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat16;
152 if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat32")
153 return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat32;
154 if (prop == "FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat64")
155 return ctx.getFloatControlsProperties().shaderSignedZeroInfNanPreserveFloat64;
156 if (prop == "FloatControlsProperties.shaderDenormPreserveFloat16")
157 return ctx.getFloatControlsProperties().shaderDenormPreserveFloat16;
158 if (prop == "FloatControlsProperties.shaderDenormPreserveFloat32")
159 return ctx.getFloatControlsProperties().shaderDenormPreserveFloat32;
160 if (prop == "FloatControlsProperties.shaderDenormPreserveFloat64")
161 return ctx.getFloatControlsProperties().shaderDenormPreserveFloat64;
162 if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat16")
163 return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat16;
164 if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat32")
165 return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat32;
166 if (prop == "FloatControlsProperties.shaderDenormFlushToZeroFloat64")
167 return ctx.getFloatControlsProperties().shaderDenormFlushToZeroFloat64;
168 if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat16")
169 return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat16;
170 if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat32")
171 return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat32;
172 if (prop == "FloatControlsProperties.shaderRoundingModeRTEFloat64")
173 return ctx.getFloatControlsProperties().shaderRoundingModeRTEFloat64;
174 if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat16")
175 return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat16;
176 if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat32")
177 return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat32;
178 if (prop == "FloatControlsProperties.shaderRoundingModeRTZFloat64")
179 return ctx.getFloatControlsProperties().shaderRoundingModeRTZFloat64;
180
181 std::string message = std::string("Unexpected property name: ") + prop;
182 TCU_THROW(InternalError, message.c_str());
183 }
184
delayedInit(void)185 void AmberTestCase::delayedInit(void)
186 {
187 // Make sure the input can be parsed before we use it.
188 if (!parse(m_readFilename))
189 {
190 std::string message = "Failed to parse Amber file: " + m_readFilename;
191 TCU_THROW(InternalError, message.c_str());
192 }
193 }
194
checkSupport(Context & ctx) const195 void AmberTestCase::checkSupport(Context &ctx) const
196 {
197 // Check for instance and device extensions as declared by the test code.
198 if (m_required_extensions.size())
199 {
200 std::set<std::string> device_extensions(ctx.getDeviceExtensions().begin(), ctx.getDeviceExtensions().end());
201 std::set<std::string> instance_extensions(ctx.getInstanceExtensions().begin(),
202 ctx.getInstanceExtensions().end());
203 std::string missing;
204 for (std::set<std::string>::iterator iter = m_required_extensions.begin(); iter != m_required_extensions.end();
205 ++iter)
206 {
207 const std::string extension = *iter;
208 if ((device_extensions.count(extension) == 0) && (instance_extensions.count(extension) == 0))
209 {
210 missing += " " + extension;
211 }
212 }
213 if (missing.size() > 0)
214 {
215 std::string message("Test requires unsupported extensions:");
216 message += missing;
217 TCU_THROW(NotSupportedError, message.c_str());
218 }
219 }
220
221 // Check for required features. Do this after extensions are checked because
222 // some feature checks are only valid when corresponding extensions are enabled.
223 if (m_required_features.size())
224 {
225 std::string missing;
226 for (std::set<std::string>::iterator iter = m_required_features.begin(); iter != m_required_features.end();
227 ++iter)
228 {
229 const std::string feature = *iter;
230 if (!isFeatureSupported(ctx, feature))
231 {
232 missing += " " + feature;
233 }
234 }
235 if (missing.size() > 0)
236 {
237 std::string message("Test requires unsupported features:");
238 message += missing;
239 TCU_THROW(NotSupportedError, message.c_str());
240 }
241 }
242
243 // Check for required properties
244 if (!m_required_properties.empty())
245 {
246 std::string missing;
247 for (const auto &prop : m_required_properties)
248 {
249 if (!isPropertySupported(ctx, prop))
250 {
251 missing += " " + prop;
252 }
253 }
254 if (!missing.empty())
255 {
256 std::string message("Test requires unsupported properties:");
257 message += missing;
258 TCU_THROW(NotSupportedError, message.c_str());
259 }
260 }
261
262 for (auto req : m_imageRequirements)
263 checkImageSupport(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), req);
264
265 for (auto req : m_bufferRequirements)
266 {
267 vk::VkFormatProperties prop;
268 ctx.getInstanceInterface().getPhysicalDeviceFormatProperties(ctx.getPhysicalDevice(), req.m_format, &prop);
269
270 if ((req.m_featureFlags & prop.bufferFeatures) != req.m_featureFlags)
271 {
272 TCU_THROW(NotSupportedError, "Buffer format doesn't support required feature flags");
273 }
274 }
275
276 if (m_checkSupportCallback)
277 (m_checkSupportCallback)(ctx, m_name);
278 }
279
280 class Delegate : public amber::Delegate
281 {
282 public:
283 Delegate(tcu::TestContext &testCtx);
284
285 amber::Result LoadBufferData(const std::string file_name, amber::BufferDataFileType file_type,
286 amber::BufferInfo *buffer) const override;
287
288 amber::Result LoadFile(const std::string file_name, std::vector<char> *buffer) const override;
289
Log(const std::string &)290 void Log(const std::string & /*message*/) override
291 {
292 DE_FATAL("amber::Delegate::Log unimplemented");
293 }
LogGraphicsCalls(void) const294 bool LogGraphicsCalls(void) const override
295 {
296 return m_logGraphicsCalls;
297 }
SetLogGraphicsCalls(bool log_graphics_calls)298 void SetLogGraphicsCalls(bool log_graphics_calls)
299 {
300 m_logGraphicsCalls = log_graphics_calls;
301 }
LogExecuteCalls(void) const302 bool LogExecuteCalls(void) const override
303 {
304 return m_logExecuteCalls;
305 }
SetLogExecuteCalls(bool log_execute_calls)306 void SetLogExecuteCalls(bool log_execute_calls)
307 {
308 m_logExecuteCalls = log_execute_calls;
309 }
LogGraphicsCallsTime(void) const310 bool LogGraphicsCallsTime(void) const override
311 {
312 return m_logGraphicsCallsTime;
313 }
SetLogGraphicsCallsTime(bool log_graphics_calls_time)314 void SetLogGraphicsCallsTime(bool log_graphics_calls_time)
315 {
316 m_logGraphicsCallsTime = log_graphics_calls_time;
317 }
GetTimestampNs(void) const318 uint64_t GetTimestampNs(void) const override
319 {
320 DE_FATAL("amber::Delegate::GetTimestampNs unimplemented");
321 return 0;
322 }
SetScriptPath(std::string path)323 void SetScriptPath(std::string path)
324 {
325 m_path = path;
326 }
327
328 private:
329 tcu::TestContext &m_testCtx;
330 std::string m_path;
331 bool m_logGraphicsCalls;
332 bool m_logGraphicsCallsTime;
333 bool m_logExecuteCalls;
334 };
335
Delegate(tcu::TestContext & testCtx)336 Delegate::Delegate(tcu::TestContext &testCtx)
337 : m_testCtx(testCtx)
338 , m_path("")
339 , m_logGraphicsCalls(false)
340 , m_logGraphicsCallsTime(false)
341 , m_logExecuteCalls(false)
342 {
343 }
344
LoadBufferData(const std::string file_name,amber::BufferDataFileType file_type,amber::BufferInfo * buffer) const345 amber::Result Delegate::LoadBufferData(const std::string file_name, amber::BufferDataFileType file_type,
346 amber::BufferInfo *buffer) const
347 {
348 const tcu::Archive &archive = m_testCtx.getArchive();
349 const de::FilePath filePath = de::FilePath(m_path).join(file_name);
350 de::UniquePtr<tcu::Resource> file(archive.getResource(filePath.getPath()));
351 int numBytes = file->getSize();
352 std::vector<uint8_t> bytes(numBytes);
353
354 if (file_type == amber::BufferDataFileType::kPng)
355 return amber::Result("Amber PNG loading unimplemented");
356
357 file->read(bytes.data(), numBytes);
358
359 if (bytes.empty())
360 return amber::Result("Failed to load buffer data " + file_name);
361
362 for (uint8_t byte : bytes)
363 {
364 amber::Value value;
365 value.SetIntValue(static_cast<uint64_t>(byte));
366 buffer->values.push_back(value);
367 }
368
369 buffer->width = 1;
370 buffer->height = 1;
371
372 return {};
373 }
374
LoadFile(const std::string file_name,std::vector<char> * buffer) const375 amber::Result Delegate::LoadFile(const std::string file_name, std::vector<char> *buffer) const
376 {
377 if (!buffer)
378 {
379 return amber::Result("Buffer pointer is null.");
380 }
381
382 const tcu::Archive &archive = m_testCtx.getArchive();
383 const de::FilePath filePath = de::FilePath(m_path).join(file_name);
384 de::UniquePtr<tcu::Resource> file(archive.getResource(filePath.getPath()));
385 int numBytes = file->getSize();
386 std::vector<uint8_t> bytes(numBytes);
387
388 file->read(bytes.data(), numBytes);
389
390 if (bytes.empty())
391 return amber::Result("Failed to load buffer data " + file_name);
392
393 // Convert uint8_t vector to char vector
394 buffer->assign(bytes.begin(), bytes.end());
395
396 return {};
397 }
398
parse(const std::string & readFilename)399 bool AmberTestCase::parse(const std::string &readFilename)
400 {
401 std::string script = ShaderSourceProvider::getSource(m_testCtx.getArchive(), readFilename.c_str());
402 if (script.empty())
403 return false;
404
405 Delegate delegate(m_testCtx);
406 delegate.SetScriptPath(de::FilePath(readFilename).getDirName());
407
408 m_recipe = new amber::Recipe();
409
410 amber::Amber am(&delegate);
411 amber::Result r = am.Parse(script, m_recipe);
412
413 m_recipe->SetFenceTimeout(~0u); // infinity of miliseconds
414
415 if (!r.IsSuccess())
416 {
417 getTestContext().getLog() << tcu::TestLog::Message << "Failed to parse Amber test " << readFilename << ": "
418 << r.Error() << "\n"
419 << tcu::TestLog::EndMessage;
420 // TODO(dneto): Enhance Amber to not require this.
421 m_recipe->SetImpl(nullptr);
422 return false;
423 }
424 return true;
425 }
426
initPrograms(vk::SourceCollections & programCollection) const427 void AmberTestCase::initPrograms(vk::SourceCollections &programCollection) const
428 {
429 std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
430 for (size_t i = 0; i < shaders.size(); ++i)
431 {
432 const amber::ShaderInfo &shader = shaders[i];
433
434 vk::SpirvVersion spirvVersion = vk::SPIRV_VERSION_1_0;
435 DE_STATIC_ASSERT(vk::SPIRV_VERSION_LAST == vk::SPIRV_VERSION_1_6 + 1);
436 if (shader.target_env == "spv1.6")
437 spirvVersion = vk::SPIRV_VERSION_1_6;
438 else if (shader.target_env == "spv1.5")
439 spirvVersion = vk::SPIRV_VERSION_1_5;
440 else if (shader.target_env == "spv1.4")
441 spirvVersion = vk::SPIRV_VERSION_1_4;
442 else if (shader.target_env == "spv1.3")
443 spirvVersion = vk::SPIRV_VERSION_1_3;
444 else if (shader.target_env == "spv1.2")
445 spirvVersion = vk::SPIRV_VERSION_1_2;
446 else if (shader.target_env == "spv1.1")
447 spirvVersion = vk::SPIRV_VERSION_1_1;
448
449 /* Hex encoded shaders do not need to be pre-compiled */
450 if (shader.format == amber::kShaderFormatSpirvHex)
451 continue;
452
453 if (shader.format == amber::kShaderFormatSpirvAsm)
454 {
455 programCollection.spirvAsmSources.add(shader.shader_name) << shader.shader_source << m_asm_options;
456 }
457 else if (shader.format == amber::kShaderFormatGlsl)
458 {
459 bool allowSpirv14 = (spirvVersion == vk::SPIRV_VERSION_1_4);
460
461 switch (shader.type)
462 {
463 case amber::kShaderTypeCompute:
464 programCollection.glslSources.add(shader.shader_name)
465 << glu::ComputeSource(shader.shader_source)
466 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
467 break;
468 case amber::kShaderTypeGeometry:
469 programCollection.glslSources.add(shader.shader_name)
470 << glu::GeometrySource(shader.shader_source)
471 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
472 break;
473 case amber::kShaderTypeFragment:
474 programCollection.glslSources.add(shader.shader_name)
475 << glu::FragmentSource(shader.shader_source)
476 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
477 break;
478 case amber::kShaderTypeVertex:
479 programCollection.glslSources.add(shader.shader_name)
480 << glu::VertexSource(shader.shader_source)
481 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
482 break;
483 case amber::kShaderTypeTessellationControl:
484 programCollection.glslSources.add(shader.shader_name)
485 << glu::TessellationControlSource(shader.shader_source)
486 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
487 break;
488 case amber::kShaderTypeTessellationEvaluation:
489 programCollection.glslSources.add(shader.shader_name)
490 << glu::TessellationEvaluationSource(shader.shader_source)
491 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, allowSpirv14);
492 break;
493 case amber::kShaderTypeRayGeneration:
494 programCollection.glslSources.add(shader.shader_name)
495 << glu::RaygenSource(shader.shader_source)
496 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
497 break;
498 case amber::kShaderTypeAnyHit:
499 programCollection.glslSources.add(shader.shader_name)
500 << glu::AnyHitSource(shader.shader_source)
501 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
502 break;
503 case amber::kShaderTypeClosestHit:
504 programCollection.glslSources.add(shader.shader_name)
505 << glu::ClosestHitSource(shader.shader_source)
506 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
507 break;
508 case amber::kShaderTypeMiss:
509 programCollection.glslSources.add(shader.shader_name)
510 << glu::MissSource(shader.shader_source)
511 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
512 break;
513 case amber::kShaderTypeIntersection:
514 programCollection.glslSources.add(shader.shader_name)
515 << glu::IntersectionSource(shader.shader_source)
516 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
517 break;
518 case amber::kShaderTypeCall:
519 programCollection.glslSources.add(shader.shader_name)
520 << glu::CallableSource(shader.shader_source)
521 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, true);
522 break;
523 case amber::kShaderTypeMulti:
524 DE_ASSERT(false && "Multi shaders not supported");
525 break;
526 default:
527 DE_ASSERT(false && "Unknown shader");
528 break;
529 }
530 }
531 else
532 {
533 DE_ASSERT(false && "Shader format not supported");
534 }
535 }
536 }
537
iterate(void)538 tcu::TestStatus AmberTestInstance::iterate(void)
539 {
540 amber::Amber am(nullptr);
541 amber::Options amber_options;
542 amber::ShaderMap shaderMap;
543 amber::Result r;
544
545 amber_options.engine = amber::kEngineTypeVulkan;
546 amber_options.config = createEngineConfig(m_context, m_customDevice);
547 amber_options.execution_type = amber::ExecutionType::kExecute;
548
549 // Amber should not execute any graphic related shaders when using --deqp-compute-only=enable flag
550 if (m_context.getTestContext().getCommandLine().isComputeOnly())
551 {
552 std::vector<amber::ShaderInfo> shaders_info = m_recipe->GetShaderInfo();
553
554 for (amber::ShaderInfo info : shaders_info)
555 {
556 if (info.type != amber::ShaderType::kShaderTypeCompute)
557 {
558 TCU_THROW(NotSupportedError, "Non compute shaders are not allow when using --deqp-compute-only=enable");
559 }
560 }
561 }
562
563 // Check for extensions as declared by the Amber script itself. Throw an internal
564 // error if that's more demanding.
565 r = am.AreAllRequirementsSupported(m_recipe, &amber_options);
566 if (!r.IsSuccess())
567 {
568 // dEQP does not to rely on external code to determine whether
569 // a test is supported. So throw an internal error here instead
570 // of a NotSupportedError. If an Amber test is not supported, then
571 // you must override this method and throw a NotSupported exception
572 // before reach here.
573 TCU_THROW(InternalError, r.Error().c_str());
574 }
575
576 std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
577 for (size_t i = 0; i < shaders.size(); ++i)
578 {
579 const amber::ShaderInfo &shader = shaders[i];
580
581 if (!m_context.getBinaryCollection().contains(shader.shader_name))
582 continue;
583
584 const vk::ProgramBinary &prog = m_context.getBinaryCollection().get(shader.shader_name);
585
586 prog.setUsed();
587
588 size_t len = prog.getSize();
589 /* This is a compiled spir-v binary which must be made of 4-byte words. We
590 * are moving into a word sized vector so divide by 4
591 */
592 std::vector<uint32_t> data;
593 data.resize(len >> 2);
594 deMemcpy(data.data(), prog.getBinary(), len);
595
596 shaderMap[shader.shader_name] = data;
597 }
598
599 r = am.ExecuteWithShaderData(m_recipe, &amber_options, shaderMap);
600 if (!r.IsSuccess())
601 {
602 m_context.getTestContext().getLog() << tcu::TestLog::Message << r.Error() << "\n" << tcu::TestLog::EndMessage;
603 }
604
605 delete amber_options.config;
606
607 return r.IsSuccess() ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
608 }
609
setSpirVAsmBuildOptions(const vk::SpirVAsmBuildOptions & asm_options)610 void AmberTestCase::setSpirVAsmBuildOptions(const vk::SpirVAsmBuildOptions &asm_options)
611 {
612 m_asm_options = asm_options;
613 }
614
addRequirement(const std::string & requirement)615 void AmberTestCase::addRequirement(const std::string &requirement)
616 {
617 if (requirement.find(".") != std::string::npos)
618 m_required_features.insert(requirement);
619 else
620 m_required_extensions.insert(requirement);
621 }
622
addPropertyRequirement(const std::string & requirement)623 void AmberTestCase::addPropertyRequirement(const std::string &requirement)
624 {
625 m_required_properties.insert(requirement);
626 }
627
addImageRequirement(vk::VkImageCreateInfo info)628 void AmberTestCase::addImageRequirement(vk::VkImageCreateInfo info)
629 {
630 m_imageRequirements.push_back(info);
631 }
632
addBufferRequirement(BufferRequirement req)633 void AmberTestCase::addBufferRequirement(BufferRequirement req)
634 {
635 m_bufferRequirements.push_back(req);
636 }
637
validateRequirements()638 bool AmberTestCase::validateRequirements()
639 {
640 if (!parse(m_readFilename))
641 {
642 std::string message = "Failed to parse Amber file: " + m_readFilename;
643 m_testCtx.getLog() << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
644 return false;
645 }
646
647 // Check if the list of required CTS features and extensions matches the
648 // one in the recipe. Throw InternalError if they do not match.
649
650 const auto &deviceExtensions = m_recipe->GetRequiredInstanceExtensions();
651 const auto &instanceExtensions = m_recipe->GetRequiredDeviceExtensions();
652 auto requiredFeatures = m_recipe->GetRequiredFeatures();
653 auto requiredProperties = m_recipe->GetRequiredProperties();
654
655 for (auto &req : requiredFeatures)
656 {
657 if (req.find(".") == std::string::npos)
658 req = "Features." + req;
659 }
660
661 std::set<std::string> allRequirements;
662 allRequirements.insert(begin(deviceExtensions), end(deviceExtensions));
663 allRequirements.insert(begin(instanceExtensions), end(instanceExtensions));
664 allRequirements.insert(begin(requiredFeatures), end(requiredFeatures));
665 allRequirements.insert(begin(requiredProperties), end(requiredProperties));
666
667 std::set<std::string> ctsRequirements = m_required_features;
668 ctsRequirements.insert(begin(m_required_properties), end(m_required_properties));
669 ctsRequirements.insert(begin(m_required_extensions), end(m_required_extensions));
670
671 if (allRequirements != ctsRequirements)
672 {
673 auto &log = m_testCtx.getLog();
674 log << tcu::TestLog::Message << "ERROR: CTS and Amber test requirement mismatch." << tcu::TestLog::EndMessage;
675 log << tcu::TestLog::Message << "Amber filename: " << m_readFilename << tcu::TestLog::EndMessage;
676 log << tcu::TestLog::Message << "CTS requirements:" << tcu::TestLog::EndMessage;
677 for (const auto &ctsReq : ctsRequirements)
678 log << tcu::TestLog::Message << " " << ctsReq << tcu::TestLog::EndMessage;
679
680 log << tcu::TestLog::Message << "Amber requirements:" << tcu::TestLog::EndMessage;
681 for (const auto &amberReq : allRequirements)
682 log << tcu::TestLog::Message << " " << amberReq << tcu::TestLog::EndMessage;
683
684 // Repeat message for cerr so it's visible in console log.
685 std::cerr << "ERROR: CTS and Amber test requirement mismatch.\n";
686 std::cerr << "Amber filename: " << m_readFilename << "\n";
687 std::cerr << "CTS requirements:\n";
688 for (const auto &ctsReq : ctsRequirements)
689 std::cerr << " " << ctsReq << "\n";
690
691 std::cerr << "Amber requirements:\n";
692 for (const auto &amberReq : allRequirements)
693 std::cerr << " " << amberReq << "\n";
694
695 return false;
696 }
697 return true;
698 }
699
700 } // namespace cts_amber
701 } // namespace vkt
702