• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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