blob: 89287c5838654cee976c6c4c0a41f4f4f8b6c43b [file] [log] [blame]
Po-Hsien Wang00777b22019-04-24 16:37:09 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Po-Hsien Wang53230a22020-11-12 18:03:18 -08005#include <png.h>
Po-Hsien Wang00777b22019-04-24 16:37:09 -07006#include <stdio.h>
7#include <stdlib.h>
8#include <time.h>
9#include <unistd.h>
10#include <chrono>
11#include <fstream>
12#include <sstream>
13#include <string>
14#include <vector>
15
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070016#include "utils.h"
17
Po-Hsien Wanga956e652020-11-11 16:29:04 -080018extern FilePath g_spirv_dir;
19
Po-Hsien Wang53230a22020-11-12 18:03:18 -080020void vkbench::Image::Save(FilePath file_path) {
21 if (data_ == nullptr) {
22 DEBUG("No data to save to %s", file_path.c_str());
23 return;
24 }
25 std::string ext = "";
26
27 std::string::size_type last_dot =
28 file_path.value().find_last_of(".", std::string::npos);
29 if (last_dot == std::string::npos) {
30 RUNTIME_ERROR("No image extension found for file: %s", file_path.c_str());
31 }
32 ext = file_path.value().substr(last_dot + 1);
33
34 if (ext == "png") {
35 savePNG(file_path);
36 } else if (ext == "ppm") {
37 savePPM(file_path);
38 } else {
39 RUNTIME_ERROR("Unknown extension: %s", ext.c_str());
40 }
41 DEBUG("Image saved to %s", file_path.c_str());
42 // Try to flush saved image to disk such that more data survives a hard crash.
43 system("/bin/sync");
44}
45
46// savePPM saves data into file_path in PPM format. It assumes data is in
47// R8G8B8A8 format.
48void vkbench::Image::savePPM(FilePath file_path) {
49 FilePath directory = file_path.DirName();
50 CreateDirectory(directory);
51
52 std::ofstream file(file_path.value(), std::ios::binary | std::ios::out);
53 DEFER(file.close());
54
55 const unsigned char* row_ptr = data_ + resource_layout_.offset;
56 file << "P6\n"
57 << size_.width << "\n"
58 << size_.height << "\n"
59 << 255 << std::endl;
60 for (uint32_t y = 0; y < size_.height; y++) {
61 unsigned int* row = (unsigned int*)row_ptr;
62 for (uint32_t x = 0; x < size_.width; x++) {
63 file.write((char*)row, 3);
64 row++;
65 }
66 row_ptr += resource_layout_.rowPitch;
67 }
68}
69
70// savePNG saves data into file_path in PNG format. It assumes data is in
71// R8G8B8A8 format.
72void vkbench::Image::savePNG(FilePath file_path) {
73 FilePath directory = file_path.DirName();
74 CreateDirectory(directory);
75
76 /* create file */
77 FILE* file = fopen(file_path.c_str(), "wb");
78 if (!file)
79 RUNTIME_ERROR("File %s couldn't be opened for writing", file_path.c_str());
80 DEFER(fclose(file));
81
82 png_bytep* row_pointers = new png_bytep[sizeof(png_bytep) * size_.height];
83 unsigned char* row_ptr = data_ + resource_layout_.offset;
84 for (int y = size_.height - 1; y >= 0; y--) {
85 row_pointers[y] = new png_byte[4 * size_.width];
86 memcpy(row_pointers[y], row_ptr, 4 * size_.width);
87 row_ptr += resource_layout_.rowPitch;
88 }
89
90 /* initialize stuff */
91 png_structp png_ptr =
92 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
93 if (!png_ptr)
94 RUNTIME_ERROR("png_create_write_struct failed");
95 png_infop info_ptr = png_create_info_struct(png_ptr);
96 if (!info_ptr)
97 RUNTIME_ERROR("png_create_info_struct failed");
98 if (setjmp(png_jmpbuf(png_ptr)))
99 RUNTIME_ERROR("error during png_init_io");
100 png_init_io(png_ptr, file);
101
102 /* write header */
103 if (setjmp(png_jmpbuf(png_ptr)))
104 RUNTIME_ERROR("error during writing png header");
105 png_byte bit_depth = 8; // 8 bits per channel RGBA
106 png_byte color_type = 6; // RGBA
107 png_set_IHDR(png_ptr, info_ptr, size_.width, size_.height, bit_depth,
108 color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
109 PNG_FILTER_TYPE_BASE);
110 png_write_info(png_ptr, info_ptr);
111
112 /* write bytes */
113 if (setjmp(png_jmpbuf(png_ptr)))
114 RUNTIME_ERROR("error during png_write_image");
115 png_write_image(png_ptr, row_pointers);
116
117 /* end write */
118 if (setjmp(png_jmpbuf(png_ptr)))
119 RUNTIME_ERROR("error during png_write_end");
120 png_write_end(png_ptr, NULL);
121
122 for (int y = 0; y < size_.height; y++)
123 delete row_pointers[y];
124 delete[] row_pointers;
125}
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700126
127void PrintDateTime() {
128 time_t timer;
129 char buffer[26];
130 time(&timer);
131 struct tm* tm_info = localtime(&timer);
132 strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
133 LOG("# DateTime: %s", buffer)
134}
135
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800136std::string readShaderFile(const std::string& filename) {
137 FilePath file_path = g_spirv_dir.Append(FilePath(filename));
138 std::ifstream file(file_path.value(), std::ios::ate | std::ios::binary);
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800139 if (!file.is_open()) {
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800140 RUNTIME_ERROR("Failed to open %s", file_path.c_str());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800141 }
142 DEFER(file.close());
143
144 size_t fileSize = (size_t)file.tellg();
145 std::vector<char> buffer(fileSize);
146 file.seekg(0);
147 file.read(buffer.data(), fileSize);
148 return std::string(buffer.begin(), buffer.end());
149}
150
151// CreateShaderModule creates a shader module from a loaded SPIR-V code.
152vk::ShaderModule CreateShaderModule(const vk::Device& device,
153 std::string code) {
154 vk::ShaderModuleCreateInfo create_info;
155 create_info.setCodeSize(code.length());
156 create_info.setPCode(reinterpret_cast<const uint32_t*>(code.c_str()));
157 return device.createShaderModule(create_info);
158}
159
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700160/* Execute a shell command and return its file descriptor for reading output. */
161/* @param command: command to be run. */
162/* @param result: the stdout of the command output. */
163/* @return true if the command is executed successfully. */
164bool ExecuteCommand(const std::string& kCommand,
165 std::string* result = nullptr) {
166 FILE* fd = popen(kCommand.c_str(), "r");
167 if (!fd) {
168 return false;
169 }
170
171 if (result) {
172 fseek(fd, 0, SEEK_END);
173 long size = ftell(fd);
174 fseek(fd, 0, SEEK_SET);
175 fread(&result[0], sizeof(char), size, fd);
176 }
177 return pclose(fd) == 0;
178}
179
180std::vector<std::string> SplitString(const std::string& kInput,
181 char delimiter) {
182 std::vector<std::string> result;
183 std::stringstream srcStream(kInput);
184
185 std::string token;
186 while (getline(srcStream, token, delimiter)) {
187 result.push_back(token);
188 }
189 return result;
190}
191
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700192bool IsItemInVector(const std::vector<std::string>& list,
193 const char* value,
194 bool empty_value = false) {
195 if (list.empty())
196 return empty_value;
197 return !(find(list.begin(), list.end(), std::string(value)) == list.end());
198}
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800199
200bool check_file_existence(const char* file_path, struct stat* buffer) {
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800201 struct stat local_buf;
202 bool exist = stat(file_path, &local_buf) == 0;
203 if (buffer && exist)
204 memcpy(buffer, &local_buf, sizeof(local_buf));
205 return exist;
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800206}
207
208bool check_dir_existence(const char* file_path) {
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800209 struct stat buffer;
210 bool exist = check_file_existence(file_path, &buffer);
211 if (!exist)
212 return false;
213 return S_ISDIR(buffer.st_mode);
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800214}