1 /*
2  * Copyright © 2020 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author:
24  *    Eleni Maria Stea <estea@igalia.com>
25  *    Juan A. Suarez Romero <jasuarez@igalia.com>
26  */
27 
28 #include <piglit-util-gl.h>
29 #include "interop.h"
30 #include "params.h"
31 #include "helpers.h"
32 
33 PIGLIT_GL_TEST_CONFIG_BEGIN
34 
35 config.supports_gl_compat_version = 30;
36 config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
37 config.khr_no_error_support = PIGLIT_HAS_ERRORS;
38 
39 PIGLIT_GL_TEST_CONFIG_END
40 
41 static GLenum gl_target = GL_TEXTURE_2D;
42 
43 static struct vk_ctx vk_core;
44 static struct vk_image_props vk_img_props;
45 static struct vk_image_obj vk_img_obj;
46 static GLuint gl_mem_obj;
47 static GLuint gl_tex;
48 static GLuint gl_fbo;
49 static GLuint gl_rbo;
50 
51 static int gl_prog_flt;
52 static int gl_prog_int;
53 static int gl_prog_uint;
54 
55 static const char vs[] =
56 	"#version 130\n"
57 	"in vec4 piglit_vertex;\n"
58 	"in vec2 piglit_texcoord;\n"
59 	"out vec2 tex_coords;\n"
60 	"void main()\n"
61 	"{\n"
62 	"    gl_Position = piglit_vertex;\n"
63 	"    tex_coords = piglit_texcoord;\n" "}\n";
64 
65 /* we want this shader to work with most color formats
66  * so we subtract the expected and the sampled color
67  * if the colors match, all the components will be 0
68  * and their sum (res.x) will be 0. We pass the negative
69  * of the subtraction result to step that is going to
70  * return 0 or non 0 depending on the result (edge = 0)
71  * and we use mix to select between red if there's no match
72  * and green if there's match for the output color */
73 
74 #define MAKE_FS(SAMPLER, VEC4)				                \
75 	"#version 130\n"						\
76 	"in vec2 tex_coords;\n"						\
77 	"uniform " #SAMPLER " tex; \n"					\
78 	"uniform " #VEC4 " expected_color;\n"                           \
79 	"out vec4 color;\n"						\
80 	"void main() \n"                                                \
81 	"{\n"                                                           \
82 	"    " #VEC4 " sampled_color = texture(tex, tex_coords);\n"     \
83 	"    " #VEC4 " res = " #VEC4 " (abs(expected_color - sampled_color));\n"    \
84 	"    res.x += res.y + res.z + res.w;\n"                         \
85 	"    color = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), step(0, -float(res.x)));\n" \
86 	"}\n"
87 
88 static const char *fs[] = {
89 	MAKE_FS(sampler2D, vec4),
90 	MAKE_FS(isampler2D, ivec4),
91 	MAKE_FS(usampler2D, uvec4),
92 };
93 
94 #undef MAKE_FS
95 
96 static float exp_color_flt[4];
97 static int exp_color_int[4];
98 static unsigned int exp_color_uint[4];
99 
100 static enum piglit_result
101 run_subtest(int case_num);
102 
103 static bool
104 vk_init(void);
105 
106 static bool
107 gl_init(void);
108 
109 static bool
110 vk_set_image_props(uint32_t w, uint32_t h,
111 		   uint32_t depth,
112 		   uint32_t num_samples,
113 		   uint32_t num_levels, VkFormat format,
114 		   VkImageTiling tiling, VkImageUsageFlagBits usage);
115 
116 static bool
117 gl_draw_texture(enum fragment_type fs_type, uint32_t w, uint32_t h);
118 
119 static void
120 gl_cleanup(void);
121 
122 static void
123 cleanup(void);
124 
125 void
piglit_init(int argc,char ** argv)126 piglit_init(int argc, char **argv)
127 {
128 	/* From the EXT_external_objects spec:
129 	 *
130 	 *   "GL_EXT_memory_object requires ARB_texture_storage or a
131 	 *   version of OpenGL or OpenGL ES that incorporates it."
132 	 */
133 	piglit_require_extension("GL_ARB_texture_storage");
134 	piglit_require_extension("GL_EXT_memory_object");
135 	piglit_require_extension("GL_EXT_memory_object_fd");
136 
137 	atexit(cleanup);
138 
139 	if (!vk_init())
140 		piglit_report_result(PIGLIT_SKIP);
141 
142 	if (!gl_init())
143 		piglit_report_result(PIGLIT_SKIP);
144 }
145 
146 enum piglit_result
piglit_display()147 piglit_display()
148 {
149 	enum piglit_result piglit_test_state = PIGLIT_SKIP;
150 	enum piglit_result piglit_subtest_state;
151 	int c;
152 
153 	for (c = 0; c < ARRAY_SIZE(vk_gl_format); c++) {
154 		piglit_subtest_state = run_subtest(c);
155 		piglit_merge_result(&piglit_test_state, piglit_subtest_state);
156 	}
157 
158 	return piglit_test_state;
159 }
160 
161 /* static functions */
162 
163 static enum piglit_result
run_subtest(int case_num)164 run_subtest(int case_num)
165 {
166 	bool result = false;
167 	enum piglit_result subtest_result;
168 	const float color_prb[] = { 0.0, 1.0, 0.0, 1.0 };
169 	GLint loc = -1;
170 
171 	/* We don't set the usage flags as the purpose of this test is to test different formats
172 	 * We will check different combinations of usage/tiling mode in another test */
173 	if (!vk_set_image_props(piglit_width, piglit_height, d,
174 				num_samples, num_levels,
175 			        vk_gl_format[case_num].vkformat,
176 				vk_gl_format[case_num].tiling, 0)) {
177 		piglit_report_subtest_result(PIGLIT_SKIP,
178 					     "%s: Unsupported image format.",
179 					     vk_gl_format[case_num].name);
180 		return PIGLIT_SKIP;
181 	}
182 
183 	if (!vk_create_ext_image(&vk_core, &vk_img_props, &vk_img_obj)) {
184 		piglit_report_subtest_result(PIGLIT_FAIL,
185 					     "%s: Failed to create external Vulkan image.",
186 					     vk_gl_format[case_num].name);
187 		return PIGLIT_FAIL;
188 	}
189 
190 	/* call function that generates a texture in image props */
191 	if (!gl_create_mem_obj_from_vk_mem(&vk_core, &vk_img_obj.mobj,
192 					   &gl_mem_obj)) {
193 		piglit_report_subtest_result(PIGLIT_FAIL,
194 					     "%s: Failed to create GL memory object from Vulkan memory.",
195 					     vk_gl_format[case_num].name);
196 		vk_destroy_ext_image(&vk_core, &vk_img_obj);
197 		return PIGLIT_FAIL;
198 	}
199 
200 	if (!gl_gen_tex_from_mem_obj(&vk_img_props, vk_gl_format[case_num].glformat,
201 				     gl_mem_obj, 0,
202 				     &gl_tex)) {
203 		piglit_report_subtest_result(PIGLIT_FAIL,
204 					     "%s: Failed to create texture from GL memory object.",
205 					     vk_gl_format[case_num].name);
206 		vk_destroy_ext_image(&vk_core, &vk_img_obj);
207 		gl_cleanup();
208 		return PIGLIT_FAIL;
209 	}
210 
211 	if (!gl_draw_texture(vk_gl_format[case_num].fs_type, vk_img_props.w, vk_img_props.h)) {
212 		piglit_report_subtest_result(PIGLIT_FAIL,
213 					     "%s: Failed to initialize OpenGL FBO/RBO",
214 					     vk_gl_format[case_num].name);
215 		vk_destroy_ext_image(&vk_core, &vk_img_obj);
216 		gl_cleanup();
217 		return PIGLIT_FAIL;
218 	}
219 
220 	switch(vk_gl_format[case_num].fs_type) {
221 	case INT_FS:
222 	{
223 		glUseProgram(gl_prog_int);
224 
225 		if ((loc = glGetUniformLocation(gl_prog_int, "expected_color")) == -1) {
226 			fprintf(stderr, "Failed to get int expected color location.\n");
227 			vk_destroy_ext_image(&vk_core, &vk_img_obj);
228 			return PIGLIT_FAIL;
229 		}
230 
231 		exp_color_int[0] = pow(2, vk_gl_format[case_num].rbits) / 2 - 1;
232 		exp_color_int[1] = pow(2, vk_gl_format[case_num].gbits) / 2 - 1;
233 		exp_color_int[2] = 0;
234 		exp_color_int[3] = pow(2, vk_gl_format[case_num].abits) / 2 - 1;
235 
236 		glUniform4iv(loc, 1, exp_color_int);
237 	} break;
238 	case UINT_FS:
239 	{
240 		glUseProgram(gl_prog_uint);
241 
242 		if ((loc = glGetUniformLocation(gl_prog_uint, "expected_color")) == -1) {
243 			fprintf(stderr, "Failed to get uint expected color location.\n");
244 			vk_destroy_ext_image(&vk_core, &vk_img_obj);
245 			return PIGLIT_FAIL;
246 		}
247 
248 		exp_color_uint[0] = pow(2, vk_gl_format[case_num].rbits) - 1;
249 		exp_color_uint[1] = pow(2, vk_gl_format[case_num].gbits) - 1;
250 		exp_color_uint[2] = 0;
251 		exp_color_uint[3] = pow(2, vk_gl_format[case_num].abits) - 1;
252 
253 		glUniform4uiv(loc, 1, exp_color_uint);
254 	} break;
255 	case FLOAT_FS:
256 	{
257 		glUseProgram(gl_prog_flt);
258 
259 		if ((loc = glGetUniformLocation(gl_prog_flt, "expected_color")) == -1) {
260 			fprintf(stderr, "Failed to get float expected color location.\n");
261 			vk_destroy_ext_image(&vk_core, &vk_img_obj);
262 			return PIGLIT_FAIL;
263 		}
264 
265 		exp_color_flt[0] = 1.0;
266 		exp_color_flt[1] = 1.0;
267 		exp_color_flt[2] = 0.0;
268 		exp_color_flt[3] = 1.0;
269 
270 		glUniform4fv(loc, 1, exp_color_flt);
271 	} break;
272 	default:
273 		fprintf(stderr, "Invalid format. Shouldn't reach.\n");
274 		vk_destroy_ext_image(&vk_core, &vk_img_obj);
275 		gl_cleanup();
276 		return PIGLIT_FAIL;
277 	};
278 
279 
280 	glClear(GL_COLOR_BUFFER_BIT);
281 	glBindTexture(gl_target, gl_tex);
282 
283 	piglit_draw_rect_tex(-1, -1,
284 			     2.0 * vk_img_props.w / piglit_width,
285 			     2.0 * vk_img_props.h / piglit_height,
286 			     0, 0, 1, 1);
287 
288 	result = piglit_probe_pixel_rgba((float)piglit_width / 2.0,
289 					 (float)piglit_height / 2.0,
290 					 color_prb);
291 
292 	subtest_result = result ? PIGLIT_PASS : PIGLIT_FAIL;
293 
294 	piglit_report_subtest_result(subtest_result, "%s", vk_gl_format[case_num].name);
295 
296 	piglit_present_results();
297 
298 	vk_destroy_ext_image(&vk_core, &vk_img_obj);
299 	gl_cleanup();
300 
301 	return subtest_result;
302 }
303 
304 static bool
vk_init(void)305 vk_init(void)
306 {
307 	if (!vk_init_ctx(&vk_core)) {
308 		fprintf(stderr, "Failed to initialize Vulkan\n");
309 		return false;
310 	}
311 
312 	if (!vk_check_gl_compatibility(&vk_core)) {
313 		fprintf(stderr, "Mismatch in driver/device UUID\n");
314 		return false;
315 	}
316 
317 	return true;
318 }
319 
320 static bool
vk_set_image_props(uint32_t w,uint32_t h,uint32_t d,uint32_t num_samples,uint32_t num_levels,VkFormat format,VkImageTiling tiling,VkImageUsageFlagBits usage)321 vk_set_image_props(uint32_t w, uint32_t h, uint32_t d,
322 		   uint32_t num_samples, uint32_t num_levels,
323 		   VkFormat format, VkImageTiling tiling,
324 		   VkImageUsageFlagBits usage)
325 {
326 	VkImageLayout in_layout = VK_IMAGE_LAYOUT_UNDEFINED;
327 	VkImageLayout end_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
328 	uint32_t num_layers = 1;
329 
330 	return vk_fill_ext_image_props(&vk_core, w, h, d,
331 				       num_samples, num_levels,
332 				       num_layers,
333 				       format, tiling, usage,
334 				       in_layout, end_layout,
335 				       &vk_img_props);
336 }
337 
338 static bool
gl_draw_texture(enum fragment_type fs_type,uint32_t w,uint32_t h)339 gl_draw_texture(enum fragment_type fs_type, uint32_t w, uint32_t h)
340 {
341 	glBindTexture(gl_target, gl_tex);
342 
343 	glBindFramebuffer(GL_FRAMEBUFFER, gl_fbo);
344 	glBindRenderbuffer(GL_RENDERBUFFER, gl_rbo);
345 
346 	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
347 			      w, h);
348 	glBindRenderbuffer(GL_RENDERBUFFER, 0);
349 	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
350 				  GL_DEPTH_STENCIL_ATTACHMENT,
351 				  GL_RENDERBUFFER, gl_rbo);
352 
353 	glFramebufferTexture2D(GL_FRAMEBUFFER,
354 			       GL_COLOR_ATTACHMENT0,
355 			       gl_target, gl_tex, 0);
356 
357 	if (!check_bound_fbo_status())
358 		return false;
359 
360 	glClearColor(1.0, 1.0, 0.0, 1.0);
361 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
362 	glEnable(GL_DEPTH_TEST);
363 
364 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
365 
366 	glDisable(GL_DEPTH_TEST);
367 	glClearColor(0.0, 0.0, 1.0, 1.0);
368 	glClear(GL_COLOR_BUFFER_BIT);
369 
370 	return glGetError() == GL_NO_ERROR;
371 }
372 
373 static void
gl_cleanup(void)374 gl_cleanup(void)
375 {
376 	glBindTexture(gl_get_target(&vk_img_props), 0);
377 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
378 	glUseProgram(0);
379 
380 	glDeleteTextures(1, &gl_tex);
381 	glDeleteMemoryObjectsEXT(1, &gl_mem_obj);
382 }
383 
384 static void
cleanup(void)385 cleanup(void)
386 {
387 	vk_cleanup_ctx(&vk_core);
388 	gl_cleanup();
389 
390 	glDeleteRenderbuffers(1, &gl_rbo);
391 	glDeleteFramebuffers(1, &gl_fbo);
392 
393 	glDeleteProgram(gl_prog_flt);
394 	glDeleteProgram(gl_prog_int);
395 	glDeleteProgram(gl_prog_uint);
396 }
397 
398 static bool
gl_init(void)399 gl_init(void)
400 {
401 	gl_prog_flt = piglit_build_simple_program(vs, fs[0]);
402 	gl_prog_int = piglit_build_simple_program(vs, fs[1]);
403 	gl_prog_uint = piglit_build_simple_program(vs, fs[2]);
404 
405 	glGenFramebuffers(1, &gl_fbo);
406 	glGenRenderbuffers(1, &gl_rbo);
407 
408 	glUseProgram(0);
409 
410 	return glGetError() == GL_NO_ERROR;
411 }
412