1/*-------------------------------------------------------------------------
2 * Vulkan CTS Framework
3 * --------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief SPIR-V assembly to binary.
22 *//*--------------------------------------------------------------------*/
23
24#include "vkSpirVAsm.hpp"
25#include "vkSpirVProgram.hpp"
26#include "deClock.h"
27
28#include <algorithm>
29
30#if defined(DEQP_HAVE_SPIRV_TOOLS)
31#	include "spirv-tools/libspirv.h"
32#endif
33
34namespace vk
35{
36
37using std::string;
38using std::vector;
39
40#if defined(DEQP_HAVE_SPIRV_TOOLS)
41
42static const spv_target_env s_defaultEnvironment = SPV_ENV_VULKAN_1_0;
43
44bool assembleSpirV (const SpirVAsmSource* program, std::vector<deUint32>* dst, SpirVProgramInfo* buildInfo)
45{
46	const spv_context	context		= spvContextCreate(s_defaultEnvironment);
47	spv_binary			binary		= DE_NULL;
48	spv_diagnostic		diagnostic	= DE_NULL;
49
50	if (!context)
51		throw std::bad_alloc();
52
53	try
54	{
55		const std::string&	spvSource			= program->source;
56		const deUint64		compileStartTime	= deGetMicroseconds();
57		const spv_result_t	compileOk			= spvTextToBinary(context, spvSource.c_str(), spvSource.size(), &binary, &diagnostic);
58
59		buildInfo->source			= spvSource;
60		buildInfo->infoLog			= diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
61		buildInfo->compileTimeUs	= deGetMicroseconds() - compileStartTime;
62		buildInfo->compileOk		= (compileOk == SPV_SUCCESS);
63
64		if (buildInfo->compileOk)
65		{
66			DE_ASSERT(binary->wordCount > 0);
67			dst->resize(binary->wordCount);
68			std::copy(&binary->code[0], &binary->code[0] + binary->wordCount, dst->begin());
69		}
70
71		spvBinaryDestroy(binary);
72		spvDiagnosticDestroy(diagnostic);
73		spvContextDestroy(context);
74
75		return compileOk == SPV_SUCCESS;
76	}
77	catch (...)
78	{
79		spvBinaryDestroy(binary);
80		spvDiagnosticDestroy(diagnostic);
81		spvContextDestroy(context);
82
83		throw;
84	}
85}
86
87void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst)
88{
89	const spv_context	context		= spvContextCreate(s_defaultEnvironment);
90	spv_text			text		= DE_NULL;
91	spv_diagnostic		diagnostic	= DE_NULL;
92
93	if (!context)
94		throw std::bad_alloc();
95
96	try
97	{
98		const spv_result_t	result	= spvBinaryToText(context, binary, binarySizeInWords, 0, &text, &diagnostic);
99
100		if (result != SPV_SUCCESS)
101			TCU_THROW(InternalError, "Disassembling SPIR-V failed");
102
103		*dst << text->str;
104
105		spvTextDestroy(text);
106		spvDiagnosticDestroy(diagnostic);
107		spvContextDestroy(context);
108	}
109	catch (...)
110	{
111		spvTextDestroy(text);
112		spvDiagnosticDestroy(diagnostic);
113		spvContextDestroy(context);
114
115		throw;
116	}
117}
118
119bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog)
120{
121	const spv_context	context		= spvContextCreate(s_defaultEnvironment);
122	spv_diagnostic		diagnostic	= DE_NULL;
123
124	try
125	{
126		spv_const_binary_t	cbinary		= { binary, binarySizeInWords };
127		const spv_result_t	valid		= spvValidate(context, &cbinary, &diagnostic);
128
129		if (diagnostic)
130			*infoLog << diagnostic->error;
131
132		spvDiagnosticDestroy(diagnostic);
133		spvContextDestroy(context);
134
135		return valid == SPV_SUCCESS;
136	}
137	catch (...)
138	{
139		spvDiagnosticDestroy(diagnostic);
140		spvContextDestroy(context);
141
142		throw;
143	}
144}
145
146#else // defined(DEQP_HAVE_SPIRV_TOOLS)
147
148bool assembleSpirV (const SpirVAsmSource*, std::vector<deUint32>*, SpirVProgramInfo*)
149{
150	TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
151}
152
153void disassembleSpirV (size_t, const deUint32*, std::ostream*)
154{
155	TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
156}
157
158bool validateSpirV (size_t, const deUint32*, std::ostream*)
159{
160	TCU_THROW(NotSupportedError, "SPIR-V validation not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
161}
162
163#endif
164
165} // vk
166