1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 Intel Corporation
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 Functional tests using vkrunner
22  *//*--------------------------------------------------------------------*/
23 
24 #include <assert.h>
25 #if defined(DEQP_HAVE_VKRUNNER)
26 #include <vkrunner/vkrunner.h>
27 #endif
28 
29 #include "vktVkRunnerTestCase.hpp"
30 #include "tcuTestLog.hpp"
31 
32 namespace vkt
33 {
34 namespace vkrunner
35 {
36 
37 #if defined(DEQP_HAVE_VKRUNNER)
38 static const char *
39 vr_stage_name[VR_SHADER_STAGE_N_STAGES] = {
40 	"vertex",
41 	"tess_ctrl",
42 	"tess_eval",
43 	"geometry",
44 	"fragment",
45 	"compute",
46 };
47 #endif
48 
49 #if defined(DEQP_HAVE_VKRUNNER)
errorCb(const char * message,void * user_data)50 static void errorCb(const char* message,
51 					void* user_data)
52 {
53 	VkRunnerTestCase* test = (VkRunnerTestCase*) user_data;
54 
55 	test->getTestContext().getLog()
56 		<< tcu::TestLog::Message
57 		<< message
58 		<< "\n"
59 		<< tcu::TestLog::EndMessage;
60 }
61 #endif
62 
VkRunnerTestCase(tcu::TestContext & testCtx,const char * categoryname,const char * filename,const char * name,const char * description)63 VkRunnerTestCase::VkRunnerTestCase (tcu::TestContext&	testCtx,
64 									const char*		categoryname,
65 									const char*		filename,
66 									const char*		name,
67 									const char*		description)
68 	: TestCase(testCtx, name, description)
69 {
70 #if defined(DEQP_HAVE_VKRUNNER)
71 	m_testCaseData.categoryname = categoryname;
72 	m_testCaseData.filename = filename;
73 	m_testCaseData.num_shaders = 0;
74 	m_testCaseData.script = DE_NULL;
75 	m_testCaseData.shaders = DE_NULL;
76 
77 	std::string readFilename("vulkan/vkrunner/");
78 	readFilename.append(m_testCaseData.categoryname);
79 	readFilename.append("/");
80 	readFilename.append(m_testCaseData.filename);
81 	m_testCaseData.source = vr_source_from_file(readFilename.c_str());
82 #else
83 	(void) categoryname;
84 	(void) filename;
85 #endif
86 }
87 
~VkRunnerTestCase(void)88 VkRunnerTestCase::~VkRunnerTestCase (void)
89 {
90 #if defined(DEQP_HAVE_VKRUNNER)
91 	if (m_testCaseData.num_shaders)
92 	{
93 		for (int i = 0; i < m_testCaseData.num_shaders; i++)
94 		{
95 			/* shaders[i]->source were allocated by VkRunner. We don't need them anymore. */
96 			deFree(m_testCaseData.shaders[i].source);
97 		}
98 		deFree(m_testCaseData.shaders);
99 	}
100 	if (m_testCaseData.script)
101 		vr_script_free(m_testCaseData.script);
102 	if (m_testCaseData.source)
103 		vr_source_free(m_testCaseData.source);
104 #endif
105 }
106 
addTokenReplacement(const char * token,const char * replacement)107 void VkRunnerTestCase::addTokenReplacement(const char *token,
108 									  const char *replacement)
109 {
110 #if defined(DEQP_HAVE_VKRUNNER)
111 	vr_source_add_token_replacement(m_testCaseData.source,
112 									token,
113 									replacement);
114 #else
115 	(void) token;
116 	(void) replacement;
117 #endif
118 }
119 
getShaders()120 bool VkRunnerTestCase::getShaders()
121 {
122 #if defined(DEQP_HAVE_VKRUNNER)
123 	/* Create a temporary vr_config to log shader_test parsing errors to test's log file */
124 	struct vr_config *config = vr_config_new();
125 	vr_config_set_user_data(config, this);
126 	vr_config_set_error_cb(config, errorCb);
127 	m_testCaseData.script = vr_script_load(config, m_testCaseData.source);
128 
129 	if (m_testCaseData.script == DE_NULL)
130 	{
131 		/* Parser returned an error or shader_test file doesn't exist */
132 		vr_config_free(config);
133 		return false;
134 	}
135 
136 	m_testCaseData.num_shaders = vr_script_get_num_shaders(m_testCaseData.script);
137 	m_testCaseData.shaders = (struct vr_script_shader_code *)
138 		malloc(sizeof(struct vr_script_shader_code)*m_testCaseData.num_shaders);
139 	vr_script_get_shaders(m_testCaseData.script,
140 							m_testCaseData.source,
141 							m_testCaseData.shaders);
142 	vr_config_free(config);
143 	return true;
144 #else
145 	return false;
146 #endif
147 }
148 
createInstance(Context & ctx) const149 TestInstance* VkRunnerTestCase::createInstance(Context& ctx) const
150 {
151 	if (m_testCaseData.script == DE_NULL)
152 		TCU_THROW(InternalError, "Could not find script file");
153 
154 	return new VkRunnerTestInstance(ctx, m_testCaseData);
155 }
156 
initPrograms(vk::SourceCollections & programCollection) const157 void VkRunnerTestCase::initPrograms(vk::SourceCollections& programCollection) const
158 {
159 #if defined(DEQP_HAVE_VKRUNNER)
160 	int num_shader[VR_SHADER_STAGE_N_STAGES] = {0};
161 
162 	for (int i = 0; i < m_testCaseData.num_shaders; i++)
163 	{
164 		num_shader[m_testCaseData.shaders[i].stage]++;
165 		if (num_shader[m_testCaseData.shaders[i].stage] > 1)
166 			TCU_THROW(InternalError, "Multiple shaders per stage are not currently supported");
167 
168 		/* We ignore the SPIR-V shaders in binary form */
169 		if (m_testCaseData.shaders[i].source_type == VR_SCRIPT_SOURCE_TYPE_GLSL)
170 		{
171 			switch (m_testCaseData.shaders[i].stage)
172 			{
173 			case VR_SHADER_STAGE_VERTEX:
174 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::VertexSource(m_testCaseData.shaders[i].source);
175 				break;
176 			case VR_SHADER_STAGE_TESS_CTRL:
177 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::TessellationControlSource(m_testCaseData.shaders[i].source);
178 				break;
179 			case VR_SHADER_STAGE_TESS_EVAL:
180 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::TessellationEvaluationSource(m_testCaseData.shaders[i].source);
181 				break;
182 			case VR_SHADER_STAGE_GEOMETRY:
183 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::GeometrySource(m_testCaseData.shaders[i].source);
184 				break;
185 			case VR_SHADER_STAGE_FRAGMENT:
186 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::FragmentSource(m_testCaseData.shaders[i].source);
187 				break;
188 			case VR_SHADER_STAGE_COMPUTE:
189 				programCollection.glslSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << glu::ComputeSource(m_testCaseData.shaders[i].source);
190 				break;
191 			default:
192 				assert(0 && "Shader type is not supported");
193 			}
194 		} else if (m_testCaseData.shaders[i].source_type == VR_SCRIPT_SOURCE_TYPE_SPIRV)
195 		{
196 			programCollection.spirvAsmSources.add(vr_stage_name[m_testCaseData.shaders[i].stage]) << m_testCaseData.shaders[i].source;
197 		}
198 	}
199 #else
200 	(void) programCollection;
201 #endif
202 }
203 
iterate(void)204 tcu::TestStatus VkRunnerTestInstance::iterate (void)
205 {
206 #if defined(DEQP_HAVE_VKRUNNER)
207 	/* Get the compiled version of the text-based shaders and replace them */
208 	for (int stage = 0; stage < VR_SHADER_STAGE_N_STAGES; stage++)
209 	{
210 		std::string name(vr_stage_name[stage]);
211 		if (!m_context.getBinaryCollection().contains(name))
212 			continue;
213 		size_t source_length = m_context.getBinaryCollection().get(name).getSize();
214 		unsigned *source = (unsigned *) deMalloc(source_length);
215 		deMemcpy(source,
216 			   m_context.getBinaryCollection().get(name).getBinary(),
217 			   source_length);
218 		vr_script_replace_shaders_stage_binary(m_testCaseData.script,
219 											   (enum vr_shader_stage)stage,
220 											   source_length,
221 											   source);
222 		deFree(source);
223 	}
224 
225 	/* Replace text-based shaders by their binary equivalent and execute the test */
226 	vr_result res = vr_executor_execute_script(m_context.getExecutor(), m_testCaseData.script);
227 
228 	switch (res)
229 	{
230 	case VR_RESULT_FAIL:
231 		return tcu::TestStatus::fail("Fail");
232 	case VR_RESULT_PASS:
233 		return tcu::TestStatus::pass("Pass");
234 	case VR_RESULT_SKIP:
235 		return tcu::TestStatus::incomplete();
236 	}
237 
238 	return tcu::TestStatus::fail("Fail");
239 #else
240 	return tcu::TestStatus::fail("Not built with VkRunner support");
241 #endif
242 }
243 
244 } // vkrunner
245 } // vkt
246