blob: 1cefc3fceb1214bcc4264a8dc393adad9b25b55e [file] [log] [blame]
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001// VK tests
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06002//
3// Copyright (C) 2014 LunarG, Inc.
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included
13// in all copies or substantial portions of the 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
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -060023#include "vktestframework.h"
24#include "vkrenderframework.h"
Cody Northrop5a95b472015-06-03 13:01:54 -060025#include "SPIRV/GlslangToSpv.h"
26#include "SPIRV/SPVRemapper.h"
Tony Barbour4ab45422014-12-10 17:00:20 -070027#include <limits.h>
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060028#include <math.h>
Chia-I Wuec664fa2014-12-02 11:54:24 +080029#include <wand/MagickWand.h>
Chia-I Wuf8693382015-04-16 22:02:10 +080030#include <xcb/xcb.h>
Ian Elliott1a3845b2015-07-06 14:33:04 -060031#include "vk_wsi_swapchain.h"
32#include "vk_wsi_device_swapchain.h"
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060033
Tony Barbour3d69c9e2015-05-20 16:53:31 -060034#if defined(PATH_MAX) && !defined(MAX_PATH)
35#define MAX_PATH PATH_MAX
36#endif
37
Tony Barbour6a3faf02015-07-23 10:36:18 -060038#ifdef _WIN32
39#define ERR_EXIT(err_msg, err_class) \
40 do { \
41 MessageBox(NULL, err_msg, err_class, MB_OK); \
42 exit(1); \
43 } while (0)
44#else // _WIN32
45
46#define ERR_EXIT(err_msg, err_class) \
47 do { \
48 printf(err_msg); \
49 fflush(stdout); \
50 exit(1); \
51 } while (0)
52#endif // _WIN32
53
54#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
55{ \
56 m_fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
57 if (m_fp##entrypoint == NULL) { \
58 ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint, \
59 "vkGetInstanceProcAddr Failure"); \
60 } \
61}
62
63#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
64{ \
65 m_fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \
66 if (m_fp##entrypoint == NULL) { \
67 ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint, \
68 "vkGetDeviceProcAddr Failure"); \
69 } \
70}
71
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060072// Command-line options
73enum TOptions {
74 EOptionNone = 0x000,
75 EOptionIntermediate = 0x001,
76 EOptionSuppressInfolog = 0x002,
77 EOptionMemoryLeakMode = 0x004,
78 EOptionRelaxedErrors = 0x008,
79 EOptionGiveWarnings = 0x010,
80 EOptionLinkProgram = 0x020,
81 EOptionMultiThreaded = 0x040,
82 EOptionDumpConfig = 0x080,
83 EOptionDumpReflection = 0x100,
84 EOptionSuppressWarnings = 0x200,
85 EOptionDumpVersions = 0x400,
Cody Northrop3bfd27c2015-03-17 15:55:58 -060086 EOptionSpv = 0x800,
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060087 EOptionDefaultDesktop = 0x1000,
88};
89
Tony Barbour6a3faf02015-07-23 10:36:18 -060090typedef struct _SwapChainBuffers {
91 VkImage image;
92 VkCmdBuffer cmd;
93 VkAttachmentView view;
94} SwapChainBuffers;
95
Chia-I Wuf8693382015-04-16 22:02:10 +080096class TestFrameworkVkPresent
97{
98public:
99 TestFrameworkVkPresent(vk_testing::Device &device);
100
101 void Run();
Jon Ashburn07daee72015-05-21 18:13:33 -0600102 void InitPresentFramework(std::list<VkTestImageRecord> &imagesIn, VkInstance inst);
Chia-I Wuf8693382015-04-16 22:02:10 +0800103 void CreateMyWindow();
104 void CreateSwapChain();
105 void TearDown();
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600106#ifdef _WIN32
107 static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
108#endif
109
Chia-I Wuf8693382015-04-16 22:02:10 +0800110
111protected:
112 vk_testing::Device &m_device;
113 vk_testing::Queue &m_queue;
Dana Jansens233a0ea2015-07-30 13:04:16 -0700114 vk_testing::CmdPool m_cmdpool;
Chia-I Wuf8693382015-04-16 22:02:10 +0800115 vk_testing::CmdBuffer m_cmdbuf;
116
117private:
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600118#ifdef _WIN32
119 HINSTANCE m_connection; // hInstance - Windows Instance
120 HWND m_window; // hWnd - window handle
121
122#else
Chia-I Wuf8693382015-04-16 22:02:10 +0800123 xcb_connection_t *m_connection;
124 xcb_screen_t *m_screen;
125 xcb_window_t m_window;
126 xcb_intern_atom_reply_t *m_atom_wm_delete_window;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600127 VkPlatformHandleXcbWSI m_platform_handle_xcb;
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600128#endif
Courtney Goeltzenleuchterd6079ec2015-04-22 10:09:35 -0600129 std::list<VkTestImageRecord> m_images;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600130 uint32_t m_present_queue_node_index;
Chia-I Wuf8693382015-04-16 22:02:10 +0800131
Tony Barbour6a3faf02015-07-23 10:36:18 -0600132 PFN_vkGetPhysicalDeviceSurfaceSupportWSI m_fpGetPhysicalDeviceSurfaceSupportWSI;
133 PFN_vkGetSurfaceInfoWSI m_fpGetSurfaceInfoWSI;
Jon Ashburn07daee72015-05-21 18:13:33 -0600134 PFN_vkCreateSwapChainWSI m_fpCreateSwapChainWSI;
135 PFN_vkDestroySwapChainWSI m_fpDestroySwapChainWSI;
136 PFN_vkGetSwapChainInfoWSI m_fpGetSwapChainInfoWSI;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600137 PFN_vkAcquireNextImageWSI m_fpAcquireNextImageWSI;
Jon Ashburn07daee72015-05-21 18:13:33 -0600138 PFN_vkQueuePresentWSI m_fpQueuePresentWSI;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600139 VkSurfaceDescriptionWindowWSI m_surface_description;
140 size_t m_swapChainImageCount;
Chia-I Wuf8693382015-04-16 22:02:10 +0800141 VkSwapChainWSI m_swap_chain;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600142 SwapChainBuffers *m_buffers;
143 VkFormat m_format;
144
145 uint32_t m_current_buffer;
Chia-I Wuf8693382015-04-16 22:02:10 +0800146
147 bool m_quit;
148 bool m_pause;
149
Tony Barbour7ea6aa22015-05-22 09:44:58 -0600150 int m_width;
151 int m_height;
Chia-I Wuf8693382015-04-16 22:02:10 +0800152
153 std::list<VkTestImageRecord>::iterator m_display_image;
154
155 void Display();
156 void HandleEvent(xcb_generic_event_t *event);
157};
158
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600159#ifndef _WIN32
160
161#include <errno.h>
162
163int fopen_s(
164 FILE** pFile,
165 const char* filename,
166 const char* mode
167)
168{
169 if (!pFile || !filename || !mode) {
170 return EINVAL;
171 }
172
173 FILE* f = fopen(filename, mode);
174 if (! f) {
175 if (errno != 0) {
176 return errno;
177 } else {
178 return ENOENT;
179 }
180 }
181 *pFile = f;
182
183 return 0;
184}
185
186#endif
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600187
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600188
189
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600190// Set up environment for GLSL compiler
191// Must be done once per process
192void TestEnvironment::SetUp()
193{
Cody Northrop3bfd27c2015-03-17 15:55:58 -0600194 // Initialize GLSL to SPV compiler utility
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600195 glslang::InitializeProcess();
Chia-I Wub76e0fa2014-12-28 14:27:28 +0800196
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600197 vk_testing::set_error_callback(test_error_callback);
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600198}
199
200void TestEnvironment::TearDown()
201{
202 glslang::FinalizeProcess();
203}
204
Tony Barbour6918cd52015-04-09 12:58:51 -0600205VkTestFramework::VkTestFramework() :
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600206 m_compile_options( 0 ),
207 m_num_shader_strings( 0 )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600208{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600209
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600210}
211
Tony Barbour6918cd52015-04-09 12:58:51 -0600212VkTestFramework::~VkTestFramework()
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600213{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600214
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600215}
216
217// Define all the static elements
Cody Northropa3673cf2015-06-09 13:00:45 -0600218bool VkTestFramework::m_show_images = false;
219bool VkTestFramework::m_save_images = false;
220bool VkTestFramework::m_compare_images = false;
221bool VkTestFramework::m_use_glsl = false;
222bool VkTestFramework::m_canonicalize_spv = false;
223bool VkTestFramework::m_strip_spv = false;
Cody Northrop5a95b472015-06-03 13:01:54 -0600224bool VkTestFramework::m_do_everything_spv = false;
Tony Barbour6918cd52015-04-09 12:58:51 -0600225int VkTestFramework::m_width = 0;
226int VkTestFramework::m_height = 0;
227std::list<VkTestImageRecord> VkTestFramework::m_images;
228std::list<VkTestImageRecord>::iterator VkTestFramework::m_display_image;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600229int m_display_image_idx = 0;
230
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600231bool VkTestFramework::optionMatch(const char* option, char* optionLine)
232{
233 if (strncmp(option, optionLine, strlen(option)) == 0)
234 return true;
235 else
236 return false;
237}
238
Tony Barbour6918cd52015-04-09 12:58:51 -0600239void VkTestFramework::InitArgs(int *argc, char *argv[])
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600240{
241 int i, n;
242
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600243 for (i=1, n=1; i< *argc; i++) {
244 if (optionMatch("--show-images", argv[i]))
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600245 m_show_images = true;
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600246 else if (optionMatch("--save-images", argv[i]))
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600247 m_save_images = true;
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600248 else if (optionMatch("--no-SPV", argv[i]))
249 m_use_glsl = true;
250 else if (optionMatch("--strip-SPV", argv[i]))
251 m_strip_spv = true;
252 else if (optionMatch("--canonicalize-SPV", argv[i]))
253 m_canonicalize_spv = true;
254 else if (optionMatch("--compare-images", argv[i]))
Tony Barbour247bf372014-10-30 14:29:04 -0600255 m_compare_images = true;
Tony Barbour247bf372014-10-30 14:29:04 -0600256
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600257 else if (optionMatch("--help", argv[i]) ||
258 optionMatch("-h", argv[i])) {
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700259 printf("\nOther options:\n");
260 printf("\t--show-images\n"
261 "\t\tDisplay test images in viewer after tests complete.\n");
262 printf("\t--save-images\n"
263 "\t\tSave tests images as ppm files in current working directory.\n"
264 "\t\tUsed to generate golden images for compare-images.\n");
265 printf("\t--compare-images\n"
266 "\t\tCompare test images to 'golden' image in golden folder.\n"
Tony Barboura98d3932014-12-11 09:52:49 -0700267 "\t\tAlso saves the generated test image in current working\n"
268 "\t\t\tdirectory but only if the image is different from the golden\n"
269 "\t\tSetting RENDERTEST_GOLDEN_DIR environment variable can specify\n"
270 "\t\t\tdifferent directory for golden images\n"
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700271 "\t\tSignal test failure if different.\n");
Cody Northrop3bfd27c2015-03-17 15:55:58 -0600272 printf("\t--no-SPV\n"
273 "\t\tUse built-in GLSL compiler rather than SPV code path.\n");
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600274 printf("\t--strip-SPV\n"
Cody Northropa9bad9c2015-07-13 12:48:41 -0600275 "\t\tStrip SPIR-V debug information (line numbers, names, etc).\n");
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600276 printf("\t--canonicalize-SPV\n"
Cody Northropa9bad9c2015-07-13 12:48:41 -0600277 "\t\tRemap SPIR-V ids before submission to aid compression.\n");
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600278 exit(0);
279 } else {
280 printf("\nUnrecognized option: %s\n", argv[i]);
281 printf("\nUse --help or -h for option list.\n");
Tony Barbour4ab45422014-12-10 17:00:20 -0700282 exit(0);
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700283 }
284
Cody Northrop50a2a4b2015-06-03 16:49:20 -0600285 /*
286 * Since the above "consume" inputs, update argv
287 * so that it contains the trimmed list of args for glutInit
288 */
289
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600290 argv[n] = argv[i];
291 n++;
292 }
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600293}
294
Tony Barbour6918cd52015-04-09 12:58:51 -0600295void VkTestFramework::WritePPM( const char *basename, VkImageObj *image )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600296{
297 string filename;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600298 VkResult err;
Tony Barbour7ea6aa22015-05-22 09:44:58 -0600299 uint32_t x, y;
Tony Barbour6918cd52015-04-09 12:58:51 -0600300 VkImageObj displayImage(image->device());
Tony Barbour4c97d7a2015-04-22 15:10:33 -0600301 VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
Tony Barbour84d448c2015-04-02 14:02:33 -0600302
Tony Barboure65788f2015-07-21 17:01:42 -0600303 displayImage.init(image->extent().width, image->extent().height, image->format(), VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT, VK_IMAGE_TILING_LINEAR, reqs);
Tony Barbour84d448c2015-04-02 14:02:33 -0600304 displayImage.CopyImage(*image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600305
306 filename.append(basename);
307 filename.append(".ppm");
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600308
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600309 const VkImageSubresource sr = {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600310 VK_IMAGE_ASPECT_COLOR, 0, 0
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600311 };
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600312 VkSubresourceLayout sr_layout;
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600313
Tony Barbour59a47322015-06-24 16:06:58 -0600314 err = vkGetImageSubresourceLayout(image->device()->device(), displayImage.image(), &sr, &sr_layout);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600315 ASSERT_VK_SUCCESS( err );
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600316
Tony Barbour84d448c2015-04-02 14:02:33 -0600317 char *ptr;
Chia-I Wu681d7a02015-07-03 13:44:34 +0800318 ptr = (char *) displayImage.MapMemory();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600319 ptr += sr_layout.offset;
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600320 ofstream file (filename.c_str(), ios::binary);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600321 ASSERT_TRUE(file.is_open()) << "Unable to open file: " << filename;
322
323 file << "P6\n";
Tony Barbour84d448c2015-04-02 14:02:33 -0600324 file << displayImage.width() << "\n";
325 file << displayImage.height() << "\n";
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600326 file << 255 << "\n";
327
Tony Barbour84d448c2015-04-02 14:02:33 -0600328 for (y = 0; y < displayImage.height(); y++) {
Tony Barboura53a6942015-02-25 11:25:11 -0700329 const int *row = (const int *) ptr;
330 int swapped;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600331
Tony Barbourd1c35722015-04-16 15:59:00 -0600332 if (displayImage.format() == VK_FORMAT_B8G8R8A8_UNORM)
Tony Barboura53a6942015-02-25 11:25:11 -0700333 {
Tony Barbour84d448c2015-04-02 14:02:33 -0600334 for (x = 0; x < displayImage.width(); x++) {
Tony Barboura53a6942015-02-25 11:25:11 -0700335 swapped = (*row & 0xff00ff00) | (*row & 0x000000ff) << 16 | (*row & 0x00ff0000) >> 16;
336 file.write((char *) &swapped, 3);
337 row++;
338 }
339 }
Tony Barbourd1c35722015-04-16 15:59:00 -0600340 else if (displayImage.format() == VK_FORMAT_R8G8B8A8_UNORM)
Tony Barboura53a6942015-02-25 11:25:11 -0700341 {
Tony Barbour84d448c2015-04-02 14:02:33 -0600342 for (x = 0; x < displayImage.width(); x++) {
Tony Barboura53a6942015-02-25 11:25:11 -0700343 file.write((char *) row, 3);
344 row++;
345 }
346 }
347 else {
348 printf("Unrecognized image format - will not write image files");
349 break;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600350 }
351
352 ptr += sr_layout.rowPitch;
353 }
354
355 file.close();
Chia-I Wu681d7a02015-07-03 13:44:34 +0800356 displayImage.UnmapMemory();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600357}
358
Tony Barbour6918cd52015-04-09 12:58:51 -0600359void VkTestFramework::Compare(const char *basename, VkImageObj *image )
Tony Barbour247bf372014-10-30 14:29:04 -0600360{
361
362 MagickWand *magick_wand_1;
363 MagickWand *magick_wand_2;
364 MagickWand *compare_wand;
365 MagickBooleanType status;
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600366 char testimage[256],golden[MAX_PATH+256],golddir[MAX_PATH] = "./golden";
Tony Barbour247bf372014-10-30 14:29:04 -0600367 double differenz;
368
Tony Barbour4ab45422014-12-10 17:00:20 -0700369 if (getenv("RENDERTEST_GOLDEN_DIR"))
370 {
371 strcpy(golddir,getenv("RENDERTEST_GOLDEN_DIR"));
372 }
373
Tony Barbour247bf372014-10-30 14:29:04 -0600374 MagickWandGenesis();
375 magick_wand_1=NewMagickWand();
376 sprintf(testimage,"%s.ppm",basename);
377 status=MagickReadImage(magick_wand_1,testimage);
Tony Barbour7ea6aa22015-05-22 09:44:58 -0600378 ASSERT_EQ(status, MagickTrue) << "Unable to open file: " << testimage;
Tony Barbour247bf372014-10-30 14:29:04 -0600379
380
381 MagickWandGenesis();
382 magick_wand_2=NewMagickWand();
Tony Barbour4ab45422014-12-10 17:00:20 -0700383 sprintf(golden,"%s/%s.ppm",golddir,basename);
Tony Barbour247bf372014-10-30 14:29:04 -0600384 status=MagickReadImage(magick_wand_2,golden);
Tony Barbour7ea6aa22015-05-22 09:44:58 -0600385 ASSERT_EQ(status, MagickTrue) << "Unable to open file: " << golden;
Tony Barbour247bf372014-10-30 14:29:04 -0600386
Tony Barbour247bf372014-10-30 14:29:04 -0600387 compare_wand=MagickCompareImages(magick_wand_1,magick_wand_2, MeanAbsoluteErrorMetric, &differenz);
388 if (differenz != 0.0)
389 {
390 char difference[256];
391
392 sprintf(difference,"%s-diff.ppm",basename);
393 status = MagickWriteImage(compare_wand, difference);
394 ASSERT_TRUE(differenz == 0.0) << "Image comparison failed - diff file written";
395 }
396 DestroyMagickWand(compare_wand);
397
398 DestroyMagickWand(magick_wand_1);
399 DestroyMagickWand(magick_wand_2);
400 MagickWandTerminus();
Courtney Goeltzenleuchterfcda72d2014-12-05 15:41:02 -0700401
402 if (differenz == 0.0)
403 {
404 /*
405 * If test image and golden image match, we do not need to
406 * keep around the test image.
407 */
408 remove(testimage);
409 }
Tony Barbour247bf372014-10-30 14:29:04 -0600410}
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600411
Tony Barbour6918cd52015-04-09 12:58:51 -0600412void VkTestFramework::Show(const char *comment, VkImageObj *image)
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600413{
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600414 VkResult err;
Courtney Goeltzenleuchterfcf43ab2015-04-29 10:53:31 -0600415 VkSubresourceLayout sr_layout;
416 char *ptr;
417 VkTestImageRecord record;
Courtney Goeltzenleuchterfcf43ab2015-04-29 10:53:31 -0600418 VkImageObj displayImage(image->device());
419 VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
420
Cody Northropc9a69912015-06-18 17:05:15 -0600421 displayImage.init(image->extent().width, image->extent().height, image->format(), VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT, VK_IMAGE_TILING_LINEAR, reqs);
422
Courtney Goeltzenleuchterfcf43ab2015-04-29 10:53:31 -0600423 displayImage.CopyImage(*image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600424
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600425 const VkImageSubresource sr = {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600426 VK_IMAGE_ASPECT_COLOR, 0, 0
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600427 };
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600428
Tony Barbour59a47322015-06-24 16:06:58 -0600429 err = vkGetImageSubresourceLayout(displayImage.device()->device(), displayImage.image(), &sr, &sr_layout);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600430 ASSERT_VK_SUCCESS( err );
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600431
Chia-I Wu681d7a02015-07-03 13:44:34 +0800432 ptr = (char *) displayImage.MapMemory();
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600433 ASSERT_VK_SUCCESS( err );
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600434
435 ptr += sr_layout.offset;
436
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600437 record.m_title.append(comment);
Courtney Goeltzenleuchterfcf43ab2015-04-29 10:53:31 -0600438 record.m_width = displayImage.width();
439 record.m_height = displayImage.height();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600440 // TODO: Need to make this more robust to handle different image formats
Tony-LunarG399dfca2015-05-19 14:08:26 -0600441 record.m_data_size = displayImage.width() * displayImage.height() * 4;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600442 record.m_data = malloc(record.m_data_size);
443 memcpy(record.m_data, ptr, record.m_data_size);
444 m_images.push_back(record);
445 m_display_image = --m_images.end();
446
Chia-I Wu681d7a02015-07-03 13:44:34 +0800447 displayImage.UnmapMemory();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600448}
449
Tony Barbour6918cd52015-04-09 12:58:51 -0600450void VkTestFramework::RecordImages(vector<VkImageObj *> images)
Tony Barbour247bf372014-10-30 14:29:04 -0600451{
Courtney Goeltzenleuchtere5f0e6c2015-04-02 14:17:44 -0600452 for (int32_t i = 0; i < images.size(); i++) {
453 RecordImage(images[i]);
Tony Barbour247bf372014-10-30 14:29:04 -0600454 }
455}
456
Tony Barbour6918cd52015-04-09 12:58:51 -0600457void VkTestFramework::RecordImage(VkImageObj * image)
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600458{
459 const ::testing::TestInfo* const test_info =
460 ::testing::UnitTest::GetInstance()->current_test_info();
Tony Barbour247bf372014-10-30 14:29:04 -0600461 ostringstream filestream;
462 string filename;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600463
Tony Barbour247bf372014-10-30 14:29:04 -0600464 m_width = 40;
465
466 if (strcmp(test_info->name(), m_testName.c_str())) {
467 filestream << test_info->name();
468 m_testName.assign(test_info->name());
Tony Barboura0e2ee82014-11-18 17:02:36 -0700469 m_frameNum = 2;
470 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600471 }
472 else {
473 filestream << test_info->name() << "-" << m_frameNum;
474 m_frameNum++;
Tony Barboura0e2ee82014-11-18 17:02:36 -0700475 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600476 }
477
Tony Barbour247bf372014-10-30 14:29:04 -0600478 // ToDo - scrub string for bad characters
479
480 if (m_save_images || m_compare_images) {
481 WritePPM(filename.c_str(), image);
482 if (m_compare_images) {
483 Compare(filename.c_str(), image);
484 }
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600485 }
486
487 if (m_show_images) {
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600488 Show(test_info->name(), image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600489 }
490}
491
Chia-I Wuf8693382015-04-16 22:02:10 +0800492TestFrameworkVkPresent::TestFrameworkVkPresent(vk_testing::Device &device) :
493 m_device(device),
Courtney Goeltzenleuchterb4337c12015-03-05 16:47:18 -0700494 m_queue(*m_device.graphics_queues()[0]),
Dana Jansens233a0ea2015-07-30 13:04:16 -0700495 m_cmdpool(m_device, vk_testing::CmdPool::create_info(m_device.graphics_queue_node_index_)),
496 m_cmdbuf(m_device, vk_testing::CmdBuffer::create_info(m_cmdpool.handle()))
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600497{
Tony Barbour96db8822015-02-25 12:28:39 -0700498 m_quit = false;
499 m_pause = false;
500 m_width = 0;
501 m_height = 0;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600502}
503
Tony Barbour6918cd52015-04-09 12:58:51 -0600504void TestFrameworkVkPresent::Display()
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600505{
Tony Barbourf20f87b2015-04-22 09:02:32 -0600506 VkResult U_ASSERT_ONLY err;
Tony-LunarG399dfca2015-05-19 14:08:26 -0600507 vk_testing::Buffer buf;
508 void *dest_ptr;
509
Tony Barbour6a3faf02015-07-23 10:36:18 -0600510 VkSemaphore presentCompleteSemaphore;
511 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {};
512 presentCompleteSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
513 presentCompleteSemaphoreCreateInfo.pNext = NULL;
514 presentCompleteSemaphoreCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
515
516
517 err = vkCreateSemaphore(m_device.handle(),
518 &presentCompleteSemaphoreCreateInfo,
519 &presentCompleteSemaphore);
520 assert(!err);
521
522 // Get the index of the next available swapchain image:
523 err = m_fpAcquireNextImageWSI(m_device.handle(), m_swap_chain,
524 UINT64_MAX,
525 presentCompleteSemaphore,
526 &m_current_buffer);
527 // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
528 // return codes
529 assert(!err);
530
531 // Wait for the present complete semaphore to be signaled to ensure
532 // that the image won't be rendered to until the presentation
533 // engine has fully released ownership to the application, and it is
534 // okay to render to the image.
535 vkQueueWaitSemaphore(m_queue.handle(), presentCompleteSemaphore);
Tony-LunarG399dfca2015-05-19 14:08:26 -0600536
537 VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
Cody Northrop7fb43862015-06-22 14:56:14 -0600538 buf.init_as_src(m_device, (VkDeviceSize)m_display_image->m_data_size, flags);
Chia-I Wu681d7a02015-07-03 13:44:34 +0800539 dest_ptr = buf.memory().map();
Tony-LunarG399dfca2015-05-19 14:08:26 -0600540 memcpy(dest_ptr, m_display_image->m_data, m_display_image->m_data_size);
Chia-I Wu681d7a02015-07-03 13:44:34 +0800541 buf.memory().unmap();
Tony-LunarG399dfca2015-05-19 14:08:26 -0600542
543 m_cmdbuf.begin();
544
545 VkBufferImageCopy region = {};
546 region.imageExtent.height = m_display_image->m_height;
547 region.imageExtent.width = m_display_image->m_width;
548 region.imageExtent.depth = 1;
549
Chia-I Wube2b9172015-07-03 11:49:42 +0800550 vkCmdCopyBufferToImage(m_cmdbuf.handle(),
Chia-I Wu681d7a02015-07-03 13:44:34 +0800551 buf.handle(),
Tony Barbour6a3faf02015-07-23 10:36:18 -0600552 m_buffers[m_current_buffer].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
Tony-LunarG399dfca2015-05-19 14:08:26 -0600553 1, &region);
554 m_cmdbuf.end();
555
556 VkCmdBuffer cmdBufs[1];
Chia-I Wube2b9172015-07-03 11:49:42 +0800557 cmdBufs[0] = m_cmdbuf.handle();
Tony-LunarG399dfca2015-05-19 14:08:26 -0600558
Tony Barbour67e99152015-07-10 14:10:27 -0600559 VkFence nullFence = { VK_NULL_HANDLE };
560 vkQueueSubmit(m_queue.handle(), 1, cmdBufs, nullFence);
Tony-LunarG399dfca2015-05-19 14:08:26 -0600561 m_queue.wait();
Tony Barbour96db8822015-02-25 12:28:39 -0700562
Chia-I Wuf8693382015-04-16 22:02:10 +0800563 VkPresentInfoWSI present = {};
Ian Elliott1a3845b2015-07-06 14:33:04 -0600564 present.sType = VK_STRUCTURE_TYPE_QUEUE_PRESENT_INFO_WSI;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600565 present.pNext = NULL;
566 present.swapChainCount = 1;
567 present.swapChains = & m_swap_chain;
568 present.imageIndices = &m_current_buffer;
Tony Barbour96db8822015-02-25 12:28:39 -0700569
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600570#ifndef _WIN32
Chia-I Wuf8693382015-04-16 22:02:10 +0800571 xcb_change_property (m_connection,
Tony Barbour96db8822015-02-25 12:28:39 -0700572 XCB_PROP_MODE_REPLACE,
573 m_window,
574 XCB_ATOM_WM_NAME,
575 XCB_ATOM_STRING,
576 8,
577 m_display_image->m_title.size(),
578 m_display_image->m_title.c_str());
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600579#endif
Jon Ashburn07daee72015-05-21 18:13:33 -0600580
Chia-I Wudf12ffd2015-07-03 10:53:18 +0800581 err = m_fpQueuePresentWSI(m_queue.handle(), &present);
Tony Barbour96db8822015-02-25 12:28:39 -0700582 assert(!err);
583
584 m_queue.wait();
Tony-LunarG399dfca2015-05-19 14:08:26 -0600585 m_current_buffer = (m_current_buffer + 1) % 2;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600586}
587
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600588#ifdef _WIN32
Tony-LunarG399dfca2015-05-19 14:08:26 -0600589# define PREVIOUSLY_DOWN 1<<29
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600590// MS-Windows event handling function:
591LRESULT CALLBACK TestFrameworkVkPresent::WndProc(HWND hWnd,
592 UINT uMsg,
593 WPARAM wParam,
594 LPARAM lParam)
595{
596
597 switch(uMsg)
598 {
599 case WM_CLOSE:
600 PostQuitMessage(0);
601 break;
602
603 case WM_PAINT:
604 {
605 TestFrameworkVkPresent* me = reinterpret_cast<TestFrameworkVkPresent*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
606 if (me) {
Tony-LunarG399dfca2015-05-19 14:08:26 -0600607 SetWindowText(hWnd, me->m_display_image->m_title.c_str());
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600608 me->Display();
609 }
610 }
Tony-LunarG399dfca2015-05-19 14:08:26 -0600611 break;
612
613 case WM_KEYDOWN:
614 {
615 if (lParam & (PREVIOUSLY_DOWN)){
616 break;
617 }
618 // To be able to be a CALLBACK, WndProc had to be static, so it doesn't get a this pointer. When we created
619 // the window, we put the this pointer into the window's user data so we could get it back now
620 TestFrameworkVkPresent* me = reinterpret_cast<TestFrameworkVkPresent*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
621 switch (wParam)
622 {
623 case VK_ESCAPE: me->m_quit = true;
624 break;
625
626 case VK_LEFT: // left arrow key
627 if (me->m_display_image == me->m_images.begin()) {
628 me->m_display_image = --me->m_images.end();
629 }
630 else {
631 --me->m_display_image;
632 }
633 break;
634
635 case VK_RIGHT: // right arrow key
636 ++me->m_display_image;
637 if (me->m_display_image == me->m_images.end()) {
638 me->m_display_image = me->m_images.begin();
639 }
640 break;
641
642 default:
643 break;
644 }
645 SetWindowText(hWnd, me->m_display_image->m_title.c_str());
646 me->Display();
647 }
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600648 }
649 return (DefWindowProc(hWnd, uMsg, wParam, lParam));
650}
651
652void TestFrameworkVkPresent::Run()
653{
654 MSG msg; // message
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600655
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600656 /* main message loop*/
Tony-LunarG399dfca2015-05-19 14:08:26 -0600657 while(! m_quit) {
658 GetMessage(&msg, m_window, 0, 0);
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600659 if (msg.message == WM_QUIT) {
Tony-LunarG399dfca2015-05-19 14:08:26 -0600660 m_quit = true; //if found, quit app
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600661 } else {
662 /* Translate and dispatch to event queue*/
663 TranslateMessage(&msg);
664 DispatchMessage(&msg);
665 }
666 }
667}
668
669#else
Tony Barbour6918cd52015-04-09 12:58:51 -0600670void TestFrameworkVkPresent::HandleEvent(xcb_generic_event_t *event)
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600671{
Tony Barbour0dd968a2015-04-02 15:48:24 -0600672 uint8_t event_code = event->response_type & 0x7f;
Tony Barbour96db8822015-02-25 12:28:39 -0700673 switch (event_code) {
674 case XCB_EXPOSE:
675 Display(); // TODO: handle resize
676 break;
677 case XCB_CLIENT_MESSAGE:
678 if((*(xcb_client_message_event_t*)event).data.data32[0] ==
679 (m_atom_wm_delete_window)->atom) {
680 m_quit = true;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600681 }
682 break;
Tony Barbour96db8822015-02-25 12:28:39 -0700683 case XCB_KEY_RELEASE:
684 {
685 const xcb_key_release_event_t *key =
686 (const xcb_key_release_event_t *) event;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600687
Tony Barbour96db8822015-02-25 12:28:39 -0700688 switch (key->detail) {
689 case 0x9: // Escape
690 m_quit = true;
691 break;
692 case 0x71: // left arrow key
693 if (m_display_image == m_images.begin()) {
694 m_display_image = --m_images.end();
695 } else {
696 --m_display_image;
697 }
698 break;
699 case 0x72: // right arrow key
700 ++m_display_image;
701 if (m_display_image == m_images.end()) {
702 m_display_image = m_images.begin();
703 }
704 break;
705 case 0x41:
706 m_pause = !m_pause;
707 break;
708 }
709 Display();
710 }
711 break;
712 default:
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600713 break;
714 }
Tony Barbour96db8822015-02-25 12:28:39 -0700715}
716
Tony Barbour6918cd52015-04-09 12:58:51 -0600717void TestFrameworkVkPresent::Run()
Tony Barbour96db8822015-02-25 12:28:39 -0700718{
Chia-I Wuf8693382015-04-16 22:02:10 +0800719 xcb_flush(m_connection);
Tony Barbour96db8822015-02-25 12:28:39 -0700720
721 while (! m_quit) {
722 xcb_generic_event_t *event;
723
724 if (m_pause) {
Chia-I Wuf8693382015-04-16 22:02:10 +0800725 event = xcb_wait_for_event(m_connection);
Tony Barbour96db8822015-02-25 12:28:39 -0700726 } else {
Chia-I Wuf8693382015-04-16 22:02:10 +0800727 event = xcb_poll_for_event(m_connection);
Tony Barbour96db8822015-02-25 12:28:39 -0700728 }
729 if (event) {
730 HandleEvent(event);
731 free(event);
732 }
733 }
734}
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600735#endif // _WIN32
Tony Barbour96db8822015-02-25 12:28:39 -0700736
Chia-I Wuf8693382015-04-16 22:02:10 +0800737void TestFrameworkVkPresent::CreateSwapChain()
Tony Barbour96db8822015-02-25 12:28:39 -0700738{
Tony Barbourf20f87b2015-04-22 09:02:32 -0600739 VkResult U_ASSERT_ONLY err;
Tony Barbour96db8822015-02-25 12:28:39 -0700740
Tony-LunarG399dfca2015-05-19 14:08:26 -0600741 m_display_image = m_images.begin();
742 m_current_buffer = 0;
743
Tony Barbour6a3faf02015-07-23 10:36:18 -0600744 // Construct the WSI surface description:
745 m_surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI;
746 m_surface_description.pNext = NULL;
Ian Elliott1a3845b2015-07-06 14:33:04 -0600747#ifdef _WIN32
Tony Barbour6a3faf02015-07-23 10:36:18 -0600748 m_surface_description.platform = VK_PLATFORM_WIN32_WSI;
749 m_surface_description.pPlatformHandle = m_connection;
750 m_surface_description.pPlatformWindow = m_window;
Ian Elliott1a3845b2015-07-06 14:33:04 -0600751#else // _WIN32
Tony Barbour6a3faf02015-07-23 10:36:18 -0600752 m_platform_handle_xcb.connection = m_connection;
753 m_platform_handle_xcb.root = m_screen->root;
754 m_surface_description.platform = VK_PLATFORM_XCB_WSI;
755 m_surface_description.pPlatformHandle = &m_platform_handle_xcb;
756 m_surface_description.pPlatformWindow = &m_window;
Ian Elliott1a3845b2015-07-06 14:33:04 -0600757#endif // _WIN32
Tony Barbour6a3faf02015-07-23 10:36:18 -0600758
759 // Iterate over each queue to learn whether it supports presenting to WSI:
760 VkBool32 supportsPresent;
761 m_present_queue_node_index = UINT32_MAX;
762 std::vector<vk_testing::Queue *> queues = m_device.graphics_queues();
763 for (int i=0; i < queues.size(); i++)
764 {
765 int family_index = queues[i]->get_family_index();
766 m_fpGetPhysicalDeviceSurfaceSupportWSI(m_device.phy().handle(),
767 family_index,
768 (VkSurfaceDescriptionWSI *) &m_surface_description,
769 &supportsPresent);
770 if (supportsPresent) {
771 m_present_queue_node_index = family_index;
772 }
773 }
774
775 assert(m_present_queue_node_index != UINT32_MAX);
776
777
778 // Get the list of VkFormat's that are supported:
779 size_t formatsSize;
780 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
781 (VkSurfaceDescriptionWSI *) &m_surface_description,
782 VK_SURFACE_INFO_TYPE_FORMATS_WSI,
783 &formatsSize, NULL);
784 assert(!err);
785 VkSurfaceFormatPropertiesWSI *surfFormats = (VkSurfaceFormatPropertiesWSI *)malloc(formatsSize);
786 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
787 (VkSurfaceDescriptionWSI *) &m_surface_description,
788 VK_SURFACE_INFO_TYPE_FORMATS_WSI,
789 &formatsSize, surfFormats);
790 assert(!err);
791 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
792 // the surface has no preferred format. Otherwise, at least one
793 // supported format will be returned.
794 size_t formatCount = formatsSize / sizeof(VkSurfaceFormatPropertiesWSI);
795 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
796 {
797 m_format = VK_FORMAT_B8G8R8A8_UNORM;
798 }
799 else
800 {
801 assert(formatCount >= 1);
802 m_format = surfFormats[0].format;
803 }
804
805 // Check the surface proprties and formats
806 size_t capsSize;
807 size_t presentModesSize;
808 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
809 (const VkSurfaceDescriptionWSI *)&m_surface_description,
810 VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, NULL);
811 assert(!err);
812 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
813 (const VkSurfaceDescriptionWSI *)&m_surface_description,
814 VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, NULL);
815 assert(!err);
816
817 VkSurfacePropertiesWSI *surfProperties =
818 (VkSurfacePropertiesWSI *)malloc(capsSize);
819 VkSurfacePresentModePropertiesWSI *presentModes =
820 (VkSurfacePresentModePropertiesWSI *)malloc(presentModesSize);
821
822 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
823 (const VkSurfaceDescriptionWSI *)&m_surface_description,
824 VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, surfProperties);
825 assert(!err);
826 err = m_fpGetSurfaceInfoWSI(m_device.handle(),
827 (const VkSurfaceDescriptionWSI *)&m_surface_description,
828 VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, presentModes);
829 assert(!err);
830
831 VkExtent2D swapChainExtent;
832 // width and height are either both -1, or both not -1.
833 if (surfProperties->currentExtent.width == -1)
834 {
835 // If the surface size is undefined, the size is set to
836 // the size of the images requested.
837 swapChainExtent.width = m_width;
838 swapChainExtent.height = m_height;
839 }
840 else
841 {
842 // If the surface size is defined, the swap chain size must match
843 swapChainExtent = surfProperties->currentExtent;
844 }
845
846 // If mailbox mode is available, use it, as is the lowest-latency non-
847 // tearing mode. If not, fall back to IMMEDIATE which should always be
848 // available.
849 VkPresentModeWSI swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_WSI;
850 size_t presentModeCount = presentModesSize / sizeof(VkSurfacePresentModePropertiesWSI);
851 for (size_t i = 0; i < presentModeCount; i++) {
852 if (presentModes[i].presentMode == VK_PRESENT_MODE_MAILBOX_WSI) {
853 swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_WSI;
854 break;
855 }
856 }
857
858 // Determine the number of VkImage's to use in the swap chain (we desire to
859 // own only 1 image at a time, besides the images being displayed and
860 // queued for display):
861 uint32_t desiredNumberOfSwapChainImages = surfProperties->minImageCount + 1;
862 if ((surfProperties->maxImageCount > 0) &&
863 (desiredNumberOfSwapChainImages > surfProperties->maxImageCount))
864 {
865 // Application must settle for fewer images than desired:
866 desiredNumberOfSwapChainImages = surfProperties->maxImageCount;
867 }
868
869 VkSurfaceTransformWSI preTransform;
870 if (surfProperties->supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_WSI) {
871 preTransform = VK_SURFACE_TRANSFORM_NONE_WSI;
872 } else {
873 preTransform = surfProperties->currentTransform;
874 }
Ian Elliott1a3845b2015-07-06 14:33:04 -0600875
Chia-I Wuf8693382015-04-16 22:02:10 +0800876 VkSwapChainCreateInfoWSI swap_chain = {};
877 swap_chain.sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI;
Ian Elliott1a3845b2015-07-06 14:33:04 -0600878 swap_chain.pNext = NULL;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600879 swap_chain.pSurfaceDescription = (const VkSurfaceDescriptionWSI *)&m_surface_description;
880 swap_chain.minImageCount = desiredNumberOfSwapChainImages;
881 swap_chain.imageFormat = m_format;
882 swap_chain.imageExtent.width = swapChainExtent.width;
883 swap_chain.imageExtent.height = swapChainExtent.height;
Cody Northropdf8f42a2015-08-05 15:38:39 -0600884 // Workaround: Some implementations need color attachment for blit targets
885 swap_chain.imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT |
886 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600887 swap_chain.preTransform = preTransform;
Chia-I Wuf8693382015-04-16 22:02:10 +0800888 swap_chain.imageArraySize = 1;
Tony Barbour6a3faf02015-07-23 10:36:18 -0600889 swap_chain.presentMode = swapChainPresentMode;
890 swap_chain.oldSwapChain.handle = 0;
891 swap_chain.clipped = true;
892
893 uint32_t i;
Chia-I Wuf8693382015-04-16 22:02:10 +0800894
Chia-I Wuf368b602015-07-03 10:41:20 +0800895 err = m_fpCreateSwapChainWSI(m_device.handle(), &swap_chain, &m_swap_chain);
Chia-I Wuf8693382015-04-16 22:02:10 +0800896 assert(!err);
897
Tony Barbour6a3faf02015-07-23 10:36:18 -0600898 size_t swapChainImagesSize;
Ian Elliott1a3845b2015-07-06 14:33:04 -0600899 err = m_fpGetSwapChainInfoWSI(m_device.handle(), m_swap_chain,
Tony Barbour6a3faf02015-07-23 10:36:18 -0600900 VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
901 &swapChainImagesSize, NULL);
902 assert(!err);
903
904 VkSwapChainImagePropertiesWSI* swapChainImages = (VkSwapChainImagePropertiesWSI*)malloc(swapChainImagesSize);
905 assert(swapChainImages);
906 err = m_fpGetSwapChainInfoWSI(m_device.handle(), m_swap_chain,
907 VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
908 &swapChainImagesSize, swapChainImages);
909 assert(!err);
910
911 // The number of images within the swap chain is determined based on the
912 // size of the info returned
913 m_swapChainImageCount = swapChainImagesSize / sizeof(VkSwapChainImagePropertiesWSI);
914
915 m_buffers = (SwapChainBuffers*)malloc(sizeof(SwapChainBuffers)*m_swapChainImageCount);
916 assert(m_buffers);
917
918 for (i = 0; i < m_swapChainImageCount; i++) {
919 VkAttachmentViewCreateInfo color_attachment_view = {};
920 color_attachment_view.sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO;
921 color_attachment_view.pNext = NULL;
922 color_attachment_view.format = m_format;
923 color_attachment_view.mipLevel = 0;
924 color_attachment_view.baseArraySlice = 0;
925 color_attachment_view.arraySize = 1;
926
927 m_buffers[i].image = swapChainImages[i].image;
928
929 color_attachment_view.image = m_buffers[i].image;
930 err = vkCreateAttachmentView(m_device.handle(),
931 &color_attachment_view, &m_buffers[i].view);
932 assert(!err);
933 }
Tony Barbour96db8822015-02-25 12:28:39 -0700934}
935
Jon Ashburn07daee72015-05-21 18:13:33 -0600936void TestFrameworkVkPresent::InitPresentFramework(std::list<VkTestImageRecord> &imagesIn, VkInstance inst)
Tony Barbour96db8822015-02-25 12:28:39 -0700937{
Tony Barbour6a3faf02015-07-23 10:36:18 -0600938 GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceSupportWSI);
939 GET_DEVICE_PROC_ADDR(m_device.handle(), GetSurfaceInfoWSI);
940 GET_DEVICE_PROC_ADDR(m_device.handle(), CreateSwapChainWSI);
941 GET_DEVICE_PROC_ADDR(m_device.handle(), CreateSwapChainWSI);
942 GET_DEVICE_PROC_ADDR(m_device.handle(), DestroySwapChainWSI);
943 GET_DEVICE_PROC_ADDR(m_device.handle(), GetSwapChainInfoWSI);
944 GET_DEVICE_PROC_ADDR(m_device.handle(), AcquireNextImageWSI);
945 GET_DEVICE_PROC_ADDR(m_device.handle(), QueuePresentWSI);
Jon Ashburn07daee72015-05-21 18:13:33 -0600946
Tony Barbour96db8822015-02-25 12:28:39 -0700947 m_images = imagesIn;
948}
949
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600950#ifdef _WIN32
951void TestFrameworkVkPresent::CreateMyWindow()
952{
953 WNDCLASSEX win_class;
954 // const ::testing::TestInfo* const test_info =
955 // ::testing::UnitTest::GetInstance()->current_test_info();
956 m_connection = GetModuleHandle(NULL);
957
958 for (std::list<VkTestImageRecord>::const_iterator it = m_images.begin();
959 it != m_images.end(); it++) {
960 if (m_width < it->m_width)
961 m_width = it->m_width;
962 if (m_height < it->m_height)
963 m_height = it->m_height;
964 }
965 // Initialize the window class structure:
966 win_class.cbSize = sizeof(WNDCLASSEX);
967 win_class.style = CS_HREDRAW | CS_VREDRAW;
968 win_class.lpfnWndProc = (WNDPROC) &TestFrameworkVkPresent::WndProc;
969 win_class.cbClsExtra = 0;
970 win_class.cbWndExtra = 0;
971 win_class.hInstance = m_connection; // hInstance
972 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
973 win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
974 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
975 win_class.lpszMenuName = NULL;
976 win_class.lpszClassName = "Test";
977 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
978 // Register window class:
979 if (!RegisterClassEx(&win_class)) {
980 // It didn't work, so try to give a useful error:
981 printf("Unexpected error trying to start the application!\n");
982 fflush(stdout);
983 exit(1);
984 }
985 // Create window with the registered class:
Cody Northrop39582252015-08-05 15:39:31 -0600986 RECT wr = { 0, 0, m_width, m_height };
987 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600988 m_window = CreateWindowEx(0,
989 "Test", // class name
990 "Test", // app name
991 WS_OVERLAPPEDWINDOW | // window style
992 WS_VISIBLE |
993 WS_SYSMENU,
994 100,100, // x/y coords
Cody Northrop39582252015-08-05 15:39:31 -0600995 wr.right - wr.left, // width
996 wr.bottom - wr.top, // height
Tony Barbour3d69c9e2015-05-20 16:53:31 -0600997 NULL, // handle to parent
998 NULL, // handle to menu
999 m_connection, // hInstance
1000 NULL); // no extra parameters
1001
1002 if (!m_window) {
1003 // It didn't work, so try to give a useful error:
1004 DWORD error = GetLastError();
1005 char message[120];
1006 sprintf(message, "Cannot create a window in which to draw!\n GetLastError = %d", error);
1007 MessageBox(NULL, message, "Error", MB_OK);
1008 exit(1);
1009 }
Tony-LunarG399dfca2015-05-19 14:08:26 -06001010 // Put our this pointer into the window's user data so our WndProc can use it when it starts.
1011 SetWindowLongPtr(m_window, GWLP_USERDATA, (LONG_PTR) this);
Tony Barbour3d69c9e2015-05-20 16:53:31 -06001012}
1013#else
Tony Barbour6918cd52015-04-09 12:58:51 -06001014void TestFrameworkVkPresent::CreateMyWindow()
Tony Barbour96db8822015-02-25 12:28:39 -07001015{
Chia-I Wuf8693382015-04-16 22:02:10 +08001016 const xcb_setup_t *setup;
1017 xcb_screen_iterator_t iter;
1018 int scr;
Tony Barbour96db8822015-02-25 12:28:39 -07001019 uint32_t value_mask, value_list[32];
1020
Chia-I Wuf8693382015-04-16 22:02:10 +08001021 m_connection = xcb_connect(NULL, &scr);
1022
1023 setup = xcb_get_setup(m_connection);
1024 iter = xcb_setup_roots_iterator(setup);
1025 while (scr-- > 0)
1026 xcb_screen_next(&iter);
1027
1028 m_screen = iter.data;
1029
1030 for (std::list<VkTestImageRecord>::const_iterator it = m_images.begin();
1031 it != m_images.end(); it++) {
1032 if (m_width < it->m_width)
1033 m_width = it->m_width;
1034 if (m_height < it->m_height)
1035 m_height = it->m_height;
1036 }
1037
1038 m_window = xcb_generate_id(m_connection);
Tony Barbour96db8822015-02-25 12:28:39 -07001039
1040 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
Chia-I Wuf8693382015-04-16 22:02:10 +08001041 value_list[0] = m_screen->black_pixel;
Tony Barbour96db8822015-02-25 12:28:39 -07001042 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
1043 XCB_EVENT_MASK_EXPOSURE |
1044 XCB_EVENT_MASK_STRUCTURE_NOTIFY;
1045
Chia-I Wuf8693382015-04-16 22:02:10 +08001046 xcb_create_window(m_connection,
Tony Barbour96db8822015-02-25 12:28:39 -07001047 XCB_COPY_FROM_PARENT,
Chia-I Wuf8693382015-04-16 22:02:10 +08001048 m_window, m_screen->root,
Tony Barbour96db8822015-02-25 12:28:39 -07001049 0, 0, m_width, m_height, 0,
1050 XCB_WINDOW_CLASS_INPUT_OUTPUT,
Chia-I Wuf8693382015-04-16 22:02:10 +08001051 m_screen->root_visual,
Tony Barbour96db8822015-02-25 12:28:39 -07001052 value_mask, value_list);
1053
1054 /* Magic code that will send notification when window is destroyed */
Chia-I Wuf8693382015-04-16 22:02:10 +08001055 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(m_connection, 1, 12,
Tony Barbour96db8822015-02-25 12:28:39 -07001056 "WM_PROTOCOLS");
Chia-I Wuf8693382015-04-16 22:02:10 +08001057 xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(m_connection, cookie, 0);
Tony Barbour96db8822015-02-25 12:28:39 -07001058
Chia-I Wuf8693382015-04-16 22:02:10 +08001059 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(m_connection, 0, 16, "WM_DELETE_WINDOW");
1060 m_atom_wm_delete_window = xcb_intern_atom_reply(m_connection, cookie2, 0);
Tony Barbour96db8822015-02-25 12:28:39 -07001061
Chia-I Wuf8693382015-04-16 22:02:10 +08001062 xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE,
Tony Barbour96db8822015-02-25 12:28:39 -07001063 m_window, (*reply).atom, 4, 32, 1,
1064 &(*m_atom_wm_delete_window).atom);
1065 free(reply);
1066
Chia-I Wuf8693382015-04-16 22:02:10 +08001067 xcb_map_window(m_connection, m_window);
Tony Barbour96db8822015-02-25 12:28:39 -07001068}
Tony Barbour3d69c9e2015-05-20 16:53:31 -06001069#endif
Tony Barbour96db8822015-02-25 12:28:39 -07001070
Tony Barbour6918cd52015-04-09 12:58:51 -06001071void TestFrameworkVkPresent::TearDown()
Tony Barbour96db8822015-02-25 12:28:39 -07001072{
Ian Elliott1a3845b2015-07-06 14:33:04 -06001073 m_fpDestroySwapChainWSI(m_device.handle(), m_swap_chain);
Tony Barbour3d69c9e2015-05-20 16:53:31 -06001074#ifndef _WIN32
Chia-I Wuf8693382015-04-16 22:02:10 +08001075 xcb_destroy_window(m_connection, m_window);
1076 xcb_disconnect(m_connection);
Tony Barbour3d69c9e2015-05-20 16:53:31 -06001077#endif
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001078}
1079
Tony Barbour6918cd52015-04-09 12:58:51 -06001080void VkTestFramework::Finish()
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001081{
1082 if (m_images.size() == 0) return;
1083
Chia-I Wuf8693382015-04-16 22:02:10 +08001084 vk_testing::Environment env;
1085 env.SetUp();
Tony Barbour96db8822015-02-25 12:28:39 -07001086 {
Chia-I Wuf8693382015-04-16 22:02:10 +08001087 TestFrameworkVkPresent vkPresent(env.default_device());
Tony Barbour96db8822015-02-25 12:28:39 -07001088
Jon Ashburn07daee72015-05-21 18:13:33 -06001089 vkPresent.InitPresentFramework(m_images, env.get_instance());
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001090 vkPresent.CreateMyWindow();
Chia-I Wuf8693382015-04-16 22:02:10 +08001091 vkPresent.CreateSwapChain();
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001092 vkPresent.Run();
1093 vkPresent.TearDown();
Tony Barbour96db8822015-02-25 12:28:39 -07001094 }
Chia-I Wuf8693382015-04-16 22:02:10 +08001095 env.TearDown();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001096}
1097
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001098//
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001099// These are the default resources for TBuiltInResources, used for both
1100// - parsing this string for the case where the user didn't supply one
1101// - dumping out a template for user construction of a config file
1102//
1103static const char* DefaultConfig =
1104 "MaxLights 32\n"
1105 "MaxClipPlanes 6\n"
1106 "MaxTextureUnits 32\n"
1107 "MaxTextureCoords 32\n"
1108 "MaxVertexAttribs 64\n"
1109 "MaxVertexUniformComponents 4096\n"
1110 "MaxVaryingFloats 64\n"
1111 "MaxVertexTextureImageUnits 32\n"
1112 "MaxCombinedTextureImageUnits 80\n"
1113 "MaxTextureImageUnits 32\n"
1114 "MaxFragmentUniformComponents 4096\n"
1115 "MaxDrawBuffers 32\n"
1116 "MaxVertexUniformVectors 128\n"
1117 "MaxVaryingVectors 8\n"
1118 "MaxFragmentUniformVectors 16\n"
1119 "MaxVertexOutputVectors 16\n"
1120 "MaxFragmentInputVectors 15\n"
1121 "MinProgramTexelOffset -8\n"
1122 "MaxProgramTexelOffset 7\n"
1123 "MaxClipDistances 8\n"
1124 "MaxComputeWorkGroupCountX 65535\n"
1125 "MaxComputeWorkGroupCountY 65535\n"
1126 "MaxComputeWorkGroupCountZ 65535\n"
1127 "MaxComputeWorkGroupSizeX 1024\n"
1128 "MaxComputeWorkGroupSizeY 1024\n"
1129 "MaxComputeWorkGroupSizeZ 64\n"
1130 "MaxComputeUniformComponents 1024\n"
1131 "MaxComputeTextureImageUnits 16\n"
1132 "MaxComputeImageUniforms 8\n"
1133 "MaxComputeAtomicCounters 8\n"
1134 "MaxComputeAtomicCounterBuffers 1\n"
1135 "MaxVaryingComponents 60\n"
1136 "MaxVertexOutputComponents 64\n"
1137 "MaxGeometryInputComponents 64\n"
1138 "MaxGeometryOutputComponents 128\n"
1139 "MaxFragmentInputComponents 128\n"
1140 "MaxImageUnits 8\n"
1141 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
1142 "MaxCombinedShaderOutputResources 8\n"
1143 "MaxImageSamples 0\n"
1144 "MaxVertexImageUniforms 0\n"
1145 "MaxTessControlImageUniforms 0\n"
1146 "MaxTessEvaluationImageUniforms 0\n"
1147 "MaxGeometryImageUniforms 0\n"
1148 "MaxFragmentImageUniforms 8\n"
1149 "MaxCombinedImageUniforms 8\n"
1150 "MaxGeometryTextureImageUnits 16\n"
1151 "MaxGeometryOutputVertices 256\n"
1152 "MaxGeometryTotalOutputComponents 1024\n"
1153 "MaxGeometryUniformComponents 1024\n"
1154 "MaxGeometryVaryingComponents 64\n"
1155 "MaxTessControlInputComponents 128\n"
1156 "MaxTessControlOutputComponents 128\n"
1157 "MaxTessControlTextureImageUnits 16\n"
1158 "MaxTessControlUniformComponents 1024\n"
1159 "MaxTessControlTotalOutputComponents 4096\n"
1160 "MaxTessEvaluationInputComponents 128\n"
1161 "MaxTessEvaluationOutputComponents 128\n"
1162 "MaxTessEvaluationTextureImageUnits 16\n"
1163 "MaxTessEvaluationUniformComponents 1024\n"
1164 "MaxTessPatchComponents 120\n"
1165 "MaxPatchVertices 32\n"
1166 "MaxTessGenLevel 64\n"
1167 "MaxViewports 16\n"
1168 "MaxVertexAtomicCounters 0\n"
1169 "MaxTessControlAtomicCounters 0\n"
1170 "MaxTessEvaluationAtomicCounters 0\n"
1171 "MaxGeometryAtomicCounters 0\n"
1172 "MaxFragmentAtomicCounters 8\n"
1173 "MaxCombinedAtomicCounters 8\n"
1174 "MaxAtomicCounterBindings 1\n"
1175 "MaxVertexAtomicCounterBuffers 0\n"
1176 "MaxTessControlAtomicCounterBuffers 0\n"
1177 "MaxTessEvaluationAtomicCounterBuffers 0\n"
1178 "MaxGeometryAtomicCounterBuffers 0\n"
1179 "MaxFragmentAtomicCounterBuffers 1\n"
1180 "MaxCombinedAtomicCounterBuffers 1\n"
1181 "MaxAtomicCounterBufferSize 16384\n"
1182 "MaxTransformFeedbackBuffers 4\n"
1183 "MaxTransformFeedbackInterleavedComponents 64\n"
1184 "MaxCullDistances 8\n"
1185 "MaxCombinedClipAndCullDistances 8\n"
1186 "MaxSamples 4\n"
1187
1188 "nonInductiveForLoops 1\n"
1189 "whileLoops 1\n"
1190 "doWhileLoops 1\n"
1191 "generalUniformIndexing 1\n"
1192 "generalAttributeMatrixVectorIndexing 1\n"
1193 "generalVaryingIndexing 1\n"
1194 "generalSamplerIndexing 1\n"
1195 "generalVariableIndexing 1\n"
1196 "generalConstantMatrixVectorIndexing 1\n"
1197 ;
1198
1199//
1200// *.conf => this is a config file that can set limits/resources
1201//
Tony Barbour6918cd52015-04-09 12:58:51 -06001202bool VkTestFramework::SetConfigFile(const std::string& name)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001203{
1204 if (name.size() < 5)
1205 return false;
1206
1207 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
1208 ConfigFile = name;
1209 return true;
1210 }
1211
1212 return false;
1213}
1214
1215//
1216// Parse either a .conf file provided by the user or the default string above.
1217//
Tony Barbour6918cd52015-04-09 12:58:51 -06001218void VkTestFramework::ProcessConfigFile()
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001219{
1220 char** configStrings = 0;
1221 char* config = 0;
1222 if (ConfigFile.size() > 0) {
1223 configStrings = ReadFileData(ConfigFile.c_str());
1224 if (configStrings)
1225 config = *configStrings;
1226 else {
1227 printf("Error opening configuration file; will instead use the default configuration\n");
1228 }
1229 }
1230
1231 if (config == 0) {
1232 config = new char[strlen(DefaultConfig) + 1];
1233 strcpy(config, DefaultConfig);
1234 }
1235
1236 const char* delims = " \t\n\r";
1237 const char* token = strtok(config, delims);
1238 while (token) {
1239 const char* valueStr = strtok(0, delims);
1240 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
1241 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
1242 return;
1243 }
1244 int value = atoi(valueStr);
1245
1246 if (strcmp(token, "MaxLights") == 0)
1247 Resources.maxLights = value;
1248 else if (strcmp(token, "MaxClipPlanes") == 0)
1249 Resources.maxClipPlanes = value;
1250 else if (strcmp(token, "MaxTextureUnits") == 0)
1251 Resources.maxTextureUnits = value;
1252 else if (strcmp(token, "MaxTextureCoords") == 0)
1253 Resources.maxTextureCoords = value;
1254 else if (strcmp(token, "MaxVertexAttribs") == 0)
1255 Resources.maxVertexAttribs = value;
1256 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
1257 Resources.maxVertexUniformComponents = value;
1258 else if (strcmp(token, "MaxVaryingFloats") == 0)
1259 Resources.maxVaryingFloats = value;
1260 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
1261 Resources.maxVertexTextureImageUnits = value;
1262 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
1263 Resources.maxCombinedTextureImageUnits = value;
1264 else if (strcmp(token, "MaxTextureImageUnits") == 0)
1265 Resources.maxTextureImageUnits = value;
1266 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
1267 Resources.maxFragmentUniformComponents = value;
1268 else if (strcmp(token, "MaxDrawBuffers") == 0)
1269 Resources.maxDrawBuffers = value;
1270 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
1271 Resources.maxVertexUniformVectors = value;
1272 else if (strcmp(token, "MaxVaryingVectors") == 0)
1273 Resources.maxVaryingVectors = value;
1274 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
1275 Resources.maxFragmentUniformVectors = value;
1276 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
1277 Resources.maxVertexOutputVectors = value;
1278 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
1279 Resources.maxFragmentInputVectors = value;
1280 else if (strcmp(token, "MinProgramTexelOffset") == 0)
1281 Resources.minProgramTexelOffset = value;
1282 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
1283 Resources.maxProgramTexelOffset = value;
1284 else if (strcmp(token, "MaxClipDistances") == 0)
1285 Resources.maxClipDistances = value;
1286 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
1287 Resources.maxComputeWorkGroupCountX = value;
1288 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
1289 Resources.maxComputeWorkGroupCountY = value;
1290 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
1291 Resources.maxComputeWorkGroupCountZ = value;
1292 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
1293 Resources.maxComputeWorkGroupSizeX = value;
1294 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
1295 Resources.maxComputeWorkGroupSizeY = value;
1296 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
1297 Resources.maxComputeWorkGroupSizeZ = value;
1298 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
1299 Resources.maxComputeUniformComponents = value;
1300 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
1301 Resources.maxComputeTextureImageUnits = value;
1302 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
1303 Resources.maxComputeImageUniforms = value;
1304 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
1305 Resources.maxComputeAtomicCounters = value;
1306 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
1307 Resources.maxComputeAtomicCounterBuffers = value;
1308 else if (strcmp(token, "MaxVaryingComponents") == 0)
1309 Resources.maxVaryingComponents = value;
1310 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
1311 Resources.maxVertexOutputComponents = value;
1312 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
1313 Resources.maxGeometryInputComponents = value;
1314 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
1315 Resources.maxGeometryOutputComponents = value;
1316 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
1317 Resources.maxFragmentInputComponents = value;
1318 else if (strcmp(token, "MaxImageUnits") == 0)
1319 Resources.maxImageUnits = value;
1320 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
1321 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
1322 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
1323 Resources.maxCombinedShaderOutputResources = value;
1324 else if (strcmp(token, "MaxImageSamples") == 0)
1325 Resources.maxImageSamples = value;
1326 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
1327 Resources.maxVertexImageUniforms = value;
1328 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
1329 Resources.maxTessControlImageUniforms = value;
1330 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
1331 Resources.maxTessEvaluationImageUniforms = value;
1332 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
1333 Resources.maxGeometryImageUniforms = value;
1334 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
1335 Resources.maxFragmentImageUniforms = value;
1336 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
1337 Resources.maxCombinedImageUniforms = value;
1338 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
1339 Resources.maxGeometryTextureImageUnits = value;
1340 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
1341 Resources.maxGeometryOutputVertices = value;
1342 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
1343 Resources.maxGeometryTotalOutputComponents = value;
1344 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
1345 Resources.maxGeometryUniformComponents = value;
1346 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
1347 Resources.maxGeometryVaryingComponents = value;
1348 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
1349 Resources.maxTessControlInputComponents = value;
1350 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
1351 Resources.maxTessControlOutputComponents = value;
1352 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
1353 Resources.maxTessControlTextureImageUnits = value;
1354 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
1355 Resources.maxTessControlUniformComponents = value;
1356 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
1357 Resources.maxTessControlTotalOutputComponents = value;
1358 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
1359 Resources.maxTessEvaluationInputComponents = value;
1360 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
1361 Resources.maxTessEvaluationOutputComponents = value;
1362 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
1363 Resources.maxTessEvaluationTextureImageUnits = value;
1364 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
1365 Resources.maxTessEvaluationUniformComponents = value;
1366 else if (strcmp(token, "MaxTessPatchComponents") == 0)
1367 Resources.maxTessPatchComponents = value;
1368 else if (strcmp(token, "MaxPatchVertices") == 0)
1369 Resources.maxPatchVertices = value;
1370 else if (strcmp(token, "MaxTessGenLevel") == 0)
1371 Resources.maxTessGenLevel = value;
1372 else if (strcmp(token, "MaxViewports") == 0)
1373 Resources.maxViewports = value;
1374 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
1375 Resources.maxVertexAtomicCounters = value;
1376 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
1377 Resources.maxTessControlAtomicCounters = value;
1378 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
1379 Resources.maxTessEvaluationAtomicCounters = value;
1380 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
1381 Resources.maxGeometryAtomicCounters = value;
1382 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
1383 Resources.maxFragmentAtomicCounters = value;
1384 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
1385 Resources.maxCombinedAtomicCounters = value;
1386 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
1387 Resources.maxAtomicCounterBindings = value;
1388 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
1389 Resources.maxVertexAtomicCounterBuffers = value;
1390 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
1391 Resources.maxTessControlAtomicCounterBuffers = value;
1392 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
1393 Resources.maxTessEvaluationAtomicCounterBuffers = value;
1394 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
1395 Resources.maxGeometryAtomicCounterBuffers = value;
1396 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
1397 Resources.maxFragmentAtomicCounterBuffers = value;
1398 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
1399 Resources.maxCombinedAtomicCounterBuffers = value;
1400 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
1401 Resources.maxAtomicCounterBufferSize = value;
1402 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
1403 Resources.maxTransformFeedbackBuffers = value;
1404 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
1405 Resources.maxTransformFeedbackInterleavedComponents = value;
1406 else if (strcmp(token, "MaxCullDistances") == 0)
1407 Resources.maxCullDistances = value;
1408 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
1409 Resources.maxCombinedClipAndCullDistances = value;
1410 else if (strcmp(token, "MaxSamples") == 0)
1411 Resources.maxSamples = value;
1412
1413 else if (strcmp(token, "nonInductiveForLoops") == 0)
1414 Resources.limits.nonInductiveForLoops = (value != 0);
1415 else if (strcmp(token, "whileLoops") == 0)
1416 Resources.limits.whileLoops = (value != 0);
1417 else if (strcmp(token, "doWhileLoops") == 0)
1418 Resources.limits.doWhileLoops = (value != 0);
1419 else if (strcmp(token, "generalUniformIndexing") == 0)
1420 Resources.limits.generalUniformIndexing = (value != 0);
1421 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
1422 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
1423 else if (strcmp(token, "generalVaryingIndexing") == 0)
1424 Resources.limits.generalVaryingIndexing = (value != 0);
1425 else if (strcmp(token, "generalSamplerIndexing") == 0)
1426 Resources.limits.generalSamplerIndexing = (value != 0);
1427 else if (strcmp(token, "generalVariableIndexing") == 0)
1428 Resources.limits.generalVariableIndexing = (value != 0);
1429 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
1430 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
1431 else
1432 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
1433
1434 token = strtok(0, delims);
1435 }
1436 if (configStrings)
1437 FreeFileData(configStrings);
1438}
1439
Tony Barbour6918cd52015-04-09 12:58:51 -06001440void VkTestFramework::SetMessageOptions(EShMessages& messages)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001441{
1442 if (m_compile_options & EOptionRelaxedErrors)
1443 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
1444 if (m_compile_options & EOptionIntermediate)
1445 messages = (EShMessages)(messages | EShMsgAST);
1446 if (m_compile_options & EOptionSuppressWarnings)
1447 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
1448}
1449
1450//
1451// Malloc a string of sufficient size and read a string into it.
1452//
Tony Barbour6918cd52015-04-09 12:58:51 -06001453char** VkTestFramework::ReadFileData(const char* fileName)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001454{
1455 FILE *in;
1456 #if defined(_WIN32) && defined(__GNUC__)
1457 in = fopen(fileName, "r");
1458 int errorCode = in ? 0 : 1;
1459 #else
1460 int errorCode = fopen_s(&in, fileName, "r");
1461 #endif
1462
1463 char *fdata;
1464 int count = 0;
1465 const int maxSourceStrings = 5;
1466 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1));
1467
1468 if (errorCode) {
1469 printf("Error: unable to open input file: %s\n", fileName);
1470 return 0;
1471 }
1472
1473 while (fgetc(in) != EOF)
1474 count++;
1475
1476 fseek(in, 0, SEEK_SET);
1477
1478 if (!(fdata = (char*)malloc(count+2))) {
1479 printf("Error allocating memory\n");
1480 return 0;
1481 }
1482 if (fread(fdata,1,count, in)!=count) {
1483 printf("Error reading input file: %s\n", fileName);
1484 return 0;
1485 }
1486 fdata[count] = '\0';
1487 fclose(in);
1488 if (count == 0) {
1489 return_data[0]=(char*)malloc(count+2);
1490 return_data[0][0]='\0';
1491 m_num_shader_strings = 0;
1492 return return_data;
1493 } else
1494 m_num_shader_strings = 1;
1495
1496 int len = (int)(ceil)((float)count/(float)m_num_shader_strings);
1497 int ptr_len=0,i=0;
1498 while(count>0){
1499 return_data[i]=(char*)malloc(len+2);
1500 memcpy(return_data[i],fdata+ptr_len,len);
1501 return_data[i][len]='\0';
1502 count-=(len);
1503 ptr_len+=(len);
1504 if(count<len){
1505 if(count==0){
1506 m_num_shader_strings=(i+1);
1507 break;
1508 }
1509 len = count;
1510 }
1511 ++i;
1512 }
1513 return return_data;
1514}
1515
Tony Barbour6918cd52015-04-09 12:58:51 -06001516void VkTestFramework::FreeFileData(char** data)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001517{
1518 for(int i=0;i<m_num_shader_strings;i++)
1519 free(data[i]);
1520}
1521
1522//
1523// Deduce the language from the filename. Files must end in one of the
1524// following extensions:
1525//
1526// .vert = vertex
1527// .tesc = tessellation control
1528// .tese = tessellation evaluation
1529// .geom = geometry
1530// .frag = fragment
1531// .comp = compute
1532//
Tony Barbour6918cd52015-04-09 12:58:51 -06001533EShLanguage VkTestFramework::FindLanguage(const std::string& name)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001534{
1535 size_t ext = name.rfind('.');
1536 if (ext == std::string::npos) {
1537 return EShLangVertex;
1538 }
1539
1540 std::string suffix = name.substr(ext + 1, std::string::npos);
1541 if (suffix == "vert")
1542 return EShLangVertex;
1543 else if (suffix == "tesc")
1544 return EShLangTessControl;
1545 else if (suffix == "tese")
1546 return EShLangTessEvaluation;
1547 else if (suffix == "geom")
1548 return EShLangGeometry;
1549 else if (suffix == "frag")
1550 return EShLangFragment;
1551 else if (suffix == "comp")
1552 return EShLangCompute;
1553
1554 return EShLangVertex;
1555}
1556
1557//
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001558// Convert VK shader type to compiler's
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001559//
Tony Barbourd1c35722015-04-16 15:59:00 -06001560EShLanguage VkTestFramework::FindLanguage(const VkShaderStage shader_type)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001561{
1562 switch (shader_type) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001563 case VK_SHADER_STAGE_VERTEX:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001564 return EShLangVertex;
1565
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001566 case VK_SHADER_STAGE_TESS_CONTROL:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001567 return EShLangTessControl;
1568
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001569 case VK_SHADER_STAGE_TESS_EVALUATION:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001570 return EShLangTessEvaluation;
1571
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001572 case VK_SHADER_STAGE_GEOMETRY:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001573 return EShLangGeometry;
1574
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001575 case VK_SHADER_STAGE_FRAGMENT:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001576 return EShLangFragment;
1577
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001578 case VK_SHADER_STAGE_COMPUTE:
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001579 return EShLangCompute;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001580
Chia-I Wub4c2aa42014-12-15 23:50:11 +08001581 default:
1582 return EShLangVertex;
1583 }
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001584}
1585
1586
1587//
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001588// Compile a given string containing GLSL into SPV for use by VK
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001589// Return value of false means an error was encountered.
1590//
Tony Barbourd1c35722015-04-16 15:59:00 -06001591bool VkTestFramework::GLSLtoSPV(const VkShaderStage shader_type,
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001592 const char *pshader,
Cody Northrop5a95b472015-06-03 13:01:54 -06001593 std::vector<unsigned int> &spirv)
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001594{
1595 glslang::TProgram& program = *new glslang::TProgram;
1596 const char *shaderStrings[1];
1597
1598 // TODO: Do we want to load a special config file depending on the
1599 // shader source? Optional name maybe?
1600 // SetConfigFile(fileName);
1601
1602 ProcessConfigFile();
1603
1604 EShMessages messages = EShMsgDefault;
1605 SetMessageOptions(messages);
1606
1607 EShLanguage stage = FindLanguage(shader_type);
1608 glslang::TShader* shader = new glslang::TShader(stage);
1609
1610 shaderStrings[0] = pshader;
1611 shader->setStrings(shaderStrings, 1);
1612
1613 if (! shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
1614
Cody Northrop195d6622014-11-03 12:54:37 -07001615 if (! (m_compile_options & EOptionSuppressInfolog)) {
1616 puts(shader->getInfoLog());
1617 puts(shader->getInfoDebugLog());
1618 }
1619
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001620 return false; // something didn't work
1621 }
1622
1623 program.addShader(shader);
1624
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001625
1626 //
1627 // Program-level processing...
1628 //
1629
Cody Northrop195d6622014-11-03 12:54:37 -07001630 if (! program.link(messages)) {
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001631
Cody Northrop195d6622014-11-03 12:54:37 -07001632 if (! (m_compile_options & EOptionSuppressInfolog)) {
1633 puts(shader->getInfoLog());
1634 puts(shader->getInfoDebugLog());
1635 }
1636
1637 return false;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001638 }
1639
1640 if (m_compile_options & EOptionDumpReflection) {
1641 program.buildReflection();
1642 program.dumpReflection();
1643 }
1644
Cody Northrop5a95b472015-06-03 13:01:54 -06001645 glslang::GlslangToSpv(*program.getIntermediate(stage), spirv);
1646
1647 //
1648 // Test the different modes of SPIR-V modification
1649 //
1650 if (this->m_canonicalize_spv) {
1651 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::ALL_BUT_STRIP);
1652 }
1653
1654 if (this->m_strip_spv) {
1655 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::STRIP);
1656 }
1657
1658 if (this->m_do_everything_spv) {
1659 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::DO_EVERYTHING);
1660 }
1661
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001662
1663 return true;
1664}
1665
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001666
1667
Tony Barbour6918cd52015-04-09 12:58:51 -06001668VkTestImageRecord::VkTestImageRecord() : // Constructor
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001669 m_width( 0 ),
1670 m_height( 0 ),
Chia-I Wu837f9952014-12-15 23:29:34 +08001671 m_data( NULL ),
1672 m_data_size( 0 )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001673{
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001674}
1675
Tony Barbour6918cd52015-04-09 12:58:51 -06001676VkTestImageRecord::~VkTestImageRecord()
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001677{
1678
1679}
1680
Tony Barbour6918cd52015-04-09 12:58:51 -06001681VkTestImageRecord::VkTestImageRecord(const VkTestImageRecord &copyin) // Copy constructor to handle pass by value.
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001682{
1683 m_title = copyin.m_title;
1684 m_width = copyin.m_width;
1685 m_height = copyin.m_height;
1686 m_data_size = copyin.m_data_size;
1687 m_data = copyin.m_data; // TODO: Do we need to copy the data or is pointer okay?
1688}
1689
Tony Barbour6918cd52015-04-09 12:58:51 -06001690ostream &operator<<(ostream &output, const VkTestImageRecord &VkTestImageRecord)
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001691{
Tony Barbour6918cd52015-04-09 12:58:51 -06001692 output << VkTestImageRecord.m_title << " (" << VkTestImageRecord.m_width <<
1693 "," << VkTestImageRecord.m_height << ")" << endl;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001694 return output;
1695}
1696
Tony Barbour6918cd52015-04-09 12:58:51 -06001697VkTestImageRecord& VkTestImageRecord::operator=(const VkTestImageRecord &rhs)
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001698{
1699 m_title = rhs.m_title;
1700 m_width = rhs.m_width;
1701 m_height = rhs.m_height;
1702 m_data_size = rhs.m_data_size;
1703 m_data = rhs.m_data;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001704 return *this;
1705}
1706
Tony Barbour6918cd52015-04-09 12:58:51 -06001707int VkTestImageRecord::operator==(const VkTestImageRecord &rhs) const
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001708{
1709 if( this->m_data != rhs.m_data) return 0;
1710 return 1;
1711}
1712
1713// This function is required for built-in STL list functions like sort
Tony Barbour6918cd52015-04-09 12:58:51 -06001714int VkTestImageRecord::operator<(const VkTestImageRecord &rhs) const
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001715{
1716 if( this->m_data_size < rhs.m_data_size ) return 1;
1717 return 0;
1718}
1719