1 // Copyright 2021 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Buffer.hpp"
16 #include "DrawTester.hpp"
17 #include "benchmark/benchmark.h"
18
19 #include <cassert>
20 #include <vector>
21
22 template<typename T>
RunBenchmark(benchmark::State & state,T & tester)23 static void RunBenchmark(benchmark::State &state, T &tester)
24 {
25 tester.initialize();
26
27 if(false) tester.show(); // Enable for visual verification.
28
29 // Warmup
30 tester.renderFrame();
31
32 for(auto _ : state)
33 {
34 tester.renderFrame();
35 }
36 }
37
TriangleSolidColor(benchmark::State & state,Multisample multisample)38 static void TriangleSolidColor(benchmark::State &state, Multisample multisample)
39 {
40 DrawTester tester(multisample);
41
42 tester.onCreateVertexBuffers([](DrawTester &tester) {
43 struct Vertex
44 {
45 float position[3];
46 };
47
48 Vertex vertexBufferData[] = {
49 { { 1.0f, 1.0f, 0.5f } },
50 { { -1.0f, 1.0f, 0.5f } },
51 { { 0.0f, -1.0f, 0.5f } }
52 };
53
54 std::vector<vk::VertexInputAttributeDescription> inputAttributes;
55 inputAttributes.push_back(vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)));
56
57 tester.addVertexBuffer(vertexBufferData, sizeof(vertexBufferData), std::move(inputAttributes));
58 });
59
60 tester.onCreateVertexShader([](DrawTester &tester) {
61 const char *vertexShader = R"(#version 310 es
62 layout(location = 0) in vec3 inPos;
63
64 void main()
65 {
66 gl_Position = vec4(inPos.xyz, 1.0);
67 })";
68
69 return tester.createShaderModule(vertexShader, EShLanguage::EShLangVertex);
70 });
71
72 tester.onCreateFragmentShader([](DrawTester &tester) {
73 const char *fragmentShader = R"(#version 310 es
74 precision highp float;
75
76 layout(location = 0) out vec4 outColor;
77
78 void main()
79 {
80 outColor = vec4(1.0, 1.0, 1.0, 1.0);
81 })";
82
83 return tester.createShaderModule(fragmentShader, EShLanguage::EShLangFragment);
84 });
85
86 RunBenchmark(state, tester);
87 }
88
TriangleInterpolateColor(benchmark::State & state,Multisample multisample)89 static void TriangleInterpolateColor(benchmark::State &state, Multisample multisample)
90 {
91 DrawTester tester(multisample);
92
93 tester.onCreateVertexBuffers([](DrawTester &tester) {
94 struct Vertex
95 {
96 float position[3];
97 float color[3];
98 };
99
100 Vertex vertexBufferData[] = {
101 { { 1.0f, 1.0f, 0.05f }, { 1.0f, 0.0f, 0.0f } },
102 { { -1.0f, 1.0f, 0.5f }, { 0.0f, 1.0f, 0.0f } },
103 { { 0.0f, -1.0f, 0.5f }, { 0.0f, 0.0f, 1.0f } }
104 };
105
106 std::vector<vk::VertexInputAttributeDescription> inputAttributes;
107 inputAttributes.push_back(vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)));
108 inputAttributes.push_back(vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color)));
109
110 tester.addVertexBuffer(vertexBufferData, sizeof(vertexBufferData), std::move(inputAttributes));
111 });
112
113 tester.onCreateVertexShader([](DrawTester &tester) {
114 const char *vertexShader = R"(#version 310 es
115 layout(location = 0) in vec3 inPos;
116 layout(location = 1) in vec3 inColor;
117
118 layout(location = 0) out vec3 outColor;
119
120 void main()
121 {
122 outColor = inColor;
123 gl_Position = vec4(inPos.xyz, 1.0);
124 })";
125
126 return tester.createShaderModule(vertexShader, EShLanguage::EShLangVertex);
127 });
128
129 tester.onCreateFragmentShader([](DrawTester &tester) {
130 const char *fragmentShader = R"(#version 310 es
131 precision highp float;
132
133 layout(location = 0) in vec3 inColor;
134
135 layout(location = 0) out vec4 outColor;
136
137 void main()
138 {
139 outColor = vec4(inColor, 1.0);
140 })";
141
142 return tester.createShaderModule(fragmentShader, EShLanguage::EShLangFragment);
143 });
144
145 RunBenchmark(state, tester);
146 }
147
TriangleSampleTexture(benchmark::State & state,Multisample multisample)148 static void TriangleSampleTexture(benchmark::State &state, Multisample multisample)
149 {
150 DrawTester tester(multisample);
151
152 tester.onCreateVertexBuffers([](DrawTester &tester) {
153 struct Vertex
154 {
155 float position[3];
156 float texCoord[2];
157 };
158
159 Vertex vertexBufferData[] = {
160 { { 1.0f, 1.0f, 0.5f }, { 1.0f, 0.0f } },
161 { { -1.0f, 1.0f, 0.5f }, { 0.0f, 1.0f } },
162 { { 0.0f, -1.0f, 0.5f }, { 0.0f, 0.0f } }
163 };
164
165 std::vector<vk::VertexInputAttributeDescription> inputAttributes;
166 inputAttributes.push_back(vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)));
167 inputAttributes.push_back(vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, texCoord)));
168
169 tester.addVertexBuffer(vertexBufferData, sizeof(vertexBufferData), std::move(inputAttributes));
170 });
171
172 tester.onCreateVertexShader([](DrawTester &tester) {
173 const char *vertexShader = R"(#version 310 es
174 layout(location = 0) in vec3 inPos;
175 layout(location = 1) in vec2 inTexCoord;
176 layout(location = 0) out vec2 outTexCoord;
177
178 void main()
179 {
180 gl_Position = vec4(inPos.xyz, 1.0);
181 outTexCoord = inTexCoord;
182 })";
183
184 return tester.createShaderModule(vertexShader, EShLanguage::EShLangVertex);
185 });
186
187 tester.onCreateFragmentShader([](DrawTester &tester) {
188 const char *fragmentShader = R"(#version 310 es
189 precision highp float;
190
191 layout(location = 0) in vec2 inTexCoord;
192 layout(location = 0) out vec4 outColor;
193 layout(binding = 0) uniform sampler2D texSampler;
194
195 void main()
196 {
197 outColor = texture(texSampler, inTexCoord);
198 })";
199
200 return tester.createShaderModule(fragmentShader, EShLanguage::EShLangFragment);
201 });
202
203 tester.onCreateDescriptorSetLayouts([](DrawTester &tester) -> std::vector<vk::DescriptorSetLayoutBinding> {
204 vk::DescriptorSetLayoutBinding samplerLayoutBinding;
205 samplerLayoutBinding.binding = 1;
206 samplerLayoutBinding.descriptorCount = 1;
207 samplerLayoutBinding.descriptorType = vk::DescriptorType::eCombinedImageSampler;
208 samplerLayoutBinding.pImmutableSamplers = nullptr;
209 samplerLayoutBinding.stageFlags = vk::ShaderStageFlagBits::eFragment;
210
211 return { samplerLayoutBinding };
212 });
213
214 tester.onUpdateDescriptorSet([](DrawTester &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet) {
215 auto &device = tester.getDevice();
216 auto &physicalDevice = tester.getPhysicalDevice();
217 auto &queue = tester.getQueue();
218
219 auto &texture = tester.addImage(device, physicalDevice, 16, 16, vk::Format::eR8G8B8A8Unorm).obj;
220
221 // Fill texture with colorful checkerboard
222 std::array<uint32_t, 3> rgb = { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF };
223 int colorIndex = 0;
224 vk::DeviceSize bufferSize = 16 * 16 * 4;
225 Buffer buffer(device, bufferSize, vk::BufferUsageFlagBits::eTransferSrc);
226 uint32_t *data = static_cast<uint32_t *>(buffer.mapMemory());
227
228 for(int i = 0; i < 16; i++)
229 {
230 for(int j = 0; j < 16; j++)
231 {
232 if(((i ^ j) & 1) == 0)
233 {
234 data[i + 16 * j] = rgb[colorIndex++ % rgb.size()];
235 }
236 else
237 {
238 data[i + 16 * j] = 0;
239 }
240 }
241 }
242
243 buffer.unmapMemory();
244
245 Util::transitionImageLayout(device, commandPool, queue, texture.getImage(), vk::Format::eR8G8B8A8Unorm, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
246 Util::copyBufferToImage(device, commandPool, queue, buffer.getBuffer(), texture.getImage(), 16, 16);
247 Util::transitionImageLayout(device, commandPool, queue, texture.getImage(), vk::Format::eR8G8B8A8Unorm, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
248
249 vk::SamplerCreateInfo samplerInfo;
250 samplerInfo.magFilter = vk::Filter::eLinear;
251 samplerInfo.minFilter = vk::Filter::eLinear;
252 samplerInfo.addressModeU = vk::SamplerAddressMode::eRepeat;
253 samplerInfo.addressModeV = vk::SamplerAddressMode::eRepeat;
254 samplerInfo.addressModeW = vk::SamplerAddressMode::eRepeat;
255 samplerInfo.anisotropyEnable = VK_FALSE;
256 samplerInfo.unnormalizedCoordinates = VK_FALSE;
257 samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
258 samplerInfo.mipLodBias = 0.0f;
259 samplerInfo.minLod = 0.0f;
260 samplerInfo.maxLod = 0.0f;
261
262 auto sampler = tester.addSampler(samplerInfo);
263
264 vk::DescriptorImageInfo imageInfo;
265 imageInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
266 imageInfo.imageView = texture.getImageView();
267 imageInfo.sampler = sampler.obj;
268
269 std::array<vk::WriteDescriptorSet, 1> descriptorWrites = {};
270
271 descriptorWrites[0].dstSet = descriptorSet;
272 descriptorWrites[0].dstBinding = 1;
273 descriptorWrites[0].dstArrayElement = 0;
274 descriptorWrites[0].descriptorType = vk::DescriptorType::eCombinedImageSampler;
275 descriptorWrites[0].descriptorCount = 1;
276 descriptorWrites[0].pImageInfo = &imageInfo;
277
278 device.updateDescriptorSets(static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
279 });
280
281 RunBenchmark(state, tester);
282 }
283
284 BENCHMARK_CAPTURE(TriangleSolidColor, TriangleSolidColor, Multisample::False)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
285 BENCHMARK_CAPTURE(TriangleInterpolateColor, TriangleInterpolateColor, Multisample::False)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
286 BENCHMARK_CAPTURE(TriangleSampleTexture, TriangleSampleTexture, Multisample::False)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
287 BENCHMARK_CAPTURE(TriangleSolidColor, TriangleSolidColor_Multisample, Multisample::True)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
288 BENCHMARK_CAPTURE(TriangleInterpolateColor, TriangleInterpolateColor_Multisample, Multisample::True)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
289 BENCHMARK_CAPTURE(TriangleSampleTexture, TriangleSampleTexture_Multisample, Multisample::True)->Unit(benchmark::kMillisecond)->MeasureProcessCPUTime();
290