1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #define LOG_TAG "VulkanPreTransformTestHelpers"
19
20 #ifndef VK_USE_PLATFORM_ANDROID_KHR
21 #define VK_USE_PLATFORM_ANDROID_KHR
22 #endif
23
24 #include <android/log.h>
25 #include <cstring>
26
27 #include "VulkanPreTransformTestHelpers.h"
28
29 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
30 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
31 #define ASSERT(a) \
32 if (!(a)) { \
33 ALOGE("Failure: " #a " at " __FILE__ ":%d", __LINE__); \
34 return VK_TEST_ERROR; \
35 }
36 #define VK_CALL(a) ASSERT(VK_SUCCESS == (a))
37
38 #define TIMEOUT_30_SEC 30000000000
39
40 static const float vertexData[] = {
41 // L:left, T:top, R:right, B:bottom, C:center
42 -1.0f, -1.0f, 0.0f, // LT
43 -1.0f, 0.0f, 0.0f, // LC
44 0.0f, -1.0f, 0.0f, // CT
45 0.0f, 0.0f, 0.0f, // CC
46 1.0f, -1.0f, 0.0f, // RT
47 1.0f, 0.0f, 0.0f, // RC
48 -1.0f, 0.0f, 0.0f, // LC
49 -1.0f, 1.0f, 0.0f, // LB
50 0.0f, 0.0f, 0.0f, // CC
51 0.0f, 1.0f, 0.0f, // CB
52 1.0f, 0.0f, 0.0f, // RC
53 1.0f, 1.0f, 0.0f, // RB
54 };
55
56 static const float fragData[] = {
57 1.0f, 0.0f, 0.0f, // Red
58 0.0f, 1.0f, 0.0f, // Green
59 0.0f, 0.0f, 1.0f, // Blue
60 1.0f, 1.0f, 0.0f, // Yellow
61 };
62
63 static const char* requiredInstanceExtensions[] = {
64 "VK_KHR_surface",
65 "VK_KHR_android_surface",
66 };
67
68 static const char* requiredDeviceExtensions[] = {
69 "VK_KHR_swapchain",
70 };
71
enumerateInstanceExtensions(std::vector<VkExtensionProperties> * extensions)72 static bool enumerateInstanceExtensions(std::vector<VkExtensionProperties>* extensions) {
73 VkResult result;
74
75 uint32_t count = 0;
76 result = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
77 if (result != VK_SUCCESS) return false;
78
79 extensions->resize(count);
80 result = vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions->data());
81 if (result != VK_SUCCESS) return false;
82
83 return true;
84 }
85
enumerateDeviceExtensions(VkPhysicalDevice device,std::vector<VkExtensionProperties> * extensions)86 static bool enumerateDeviceExtensions(VkPhysicalDevice device,
87 std::vector<VkExtensionProperties>* extensions) {
88 VkResult result;
89
90 uint32_t count = 0;
91 result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, nullptr);
92 if (result != VK_SUCCESS) return false;
93
94 extensions->resize(count);
95 result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, extensions->data());
96 if (result != VK_SUCCESS) return false;
97
98 return true;
99 }
100
hasExtension(const char * extension_name,const std::vector<VkExtensionProperties> & extensions)101 static bool hasExtension(const char* extension_name,
102 const std::vector<VkExtensionProperties>& extensions) {
103 return std::find_if(extensions.cbegin(), extensions.cend(),
104 [extension_name](const VkExtensionProperties& extension) {
105 return strcmp(extension.extensionName, extension_name) == 0;
106 }) != extensions.cend();
107 }
108
DeviceInfo()109 DeviceInfo::DeviceInfo()
110 : mInstance(VK_NULL_HANDLE),
111 mGpu(VK_NULL_HANDLE),
112 mWindow(nullptr),
113 mSurface(VK_NULL_HANDLE),
114 mQueueFamilyIndex(0),
115 mDevice(VK_NULL_HANDLE),
116 mQueue(VK_NULL_HANDLE) {}
117
~DeviceInfo()118 DeviceInfo::~DeviceInfo() {
119 if (mDevice) {
120 vkDeviceWaitIdle(mDevice);
121 vkDestroyDevice(mDevice, nullptr);
122 mDevice = VK_NULL_HANDLE;
123 }
124 if (mInstance) {
125 vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
126 vkDestroyInstance(mInstance, nullptr);
127 mInstance = VK_NULL_HANDLE;
128 }
129 if (mWindow) {
130 ANativeWindow_release(mWindow);
131 mWindow = nullptr;
132 }
133 }
134
init(JNIEnv * env,jobject jSurface)135 VkTestResult DeviceInfo::init(JNIEnv* env, jobject jSurface) {
136 ASSERT(jSurface);
137
138 mWindow = ANativeWindow_fromSurface(env, jSurface);
139 ASSERT(mWindow);
140
141 std::vector<VkExtensionProperties> supportedInstanceExtensions;
142 ASSERT(enumerateInstanceExtensions(&supportedInstanceExtensions));
143
144 std::vector<const char*> enabledInstanceExtensions;
145 for (const auto extension : requiredInstanceExtensions) {
146 ASSERT(hasExtension(extension, supportedInstanceExtensions));
147 enabledInstanceExtensions.push_back(extension);
148 }
149
150 const VkApplicationInfo appInfo = {
151 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
152 .pNext = nullptr,
153 .pApplicationName = "VulkanPreTransformTest",
154 .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
155 .pEngineName = "",
156 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
157 .apiVersion = VK_MAKE_VERSION(1, 0, 0),
158 };
159 const VkInstanceCreateInfo instanceInfo = {
160 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
161 .pNext = nullptr,
162 .flags = 0,
163 .pApplicationInfo = &appInfo,
164 .enabledLayerCount = 0,
165 .ppEnabledLayerNames = nullptr,
166 .enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size()),
167 .ppEnabledExtensionNames = enabledInstanceExtensions.data(),
168 };
169 VK_CALL(vkCreateInstance(&instanceInfo, nullptr, &mInstance));
170
171 uint32_t gpuCount = 0;
172 VK_CALL(vkEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr));
173 if (gpuCount == 0) {
174 ALOGD("No physical device available");
175 return VK_TEST_PHYSICAL_DEVICE_NOT_EXISTED;
176 }
177
178 std::vector<VkPhysicalDevice> gpus(gpuCount, VK_NULL_HANDLE);
179 VK_CALL(vkEnumeratePhysicalDevices(mInstance, &gpuCount, gpus.data()));
180
181 mGpu = gpus[0];
182
183 const VkAndroidSurfaceCreateInfoKHR surfaceInfo = {
184 .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
185 .pNext = nullptr,
186 .flags = 0,
187 .window = mWindow,
188 };
189 VK_CALL(vkCreateAndroidSurfaceKHR(mInstance, &surfaceInfo, nullptr, &mSurface));
190
191 std::vector<VkExtensionProperties> supportedDeviceExtensions;
192 ASSERT(enumerateDeviceExtensions(mGpu, &supportedDeviceExtensions));
193
194 std::vector<const char*> enabledDeviceExtensions;
195 for (const auto extension : requiredDeviceExtensions) {
196 ASSERT(hasExtension(extension, supportedDeviceExtensions));
197 enabledDeviceExtensions.push_back(extension);
198 }
199
200 uint32_t queueFamilyCount = 0;
201 vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount, nullptr);
202 ASSERT(queueFamilyCount);
203
204 std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
205 vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount, queueFamilyProperties.data());
206
207 uint32_t queueFamilyIndex;
208 for (queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; ++queueFamilyIndex) {
209 if (queueFamilyProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
210 break;
211 }
212 }
213 ASSERT(queueFamilyIndex < queueFamilyCount);
214 mQueueFamilyIndex = queueFamilyIndex;
215
216 const float priority = 1.0f;
217 const VkDeviceQueueCreateInfo queueCreateInfo = {
218 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
219 .pNext = nullptr,
220 .flags = 0,
221 .queueFamilyIndex = mQueueFamilyIndex,
222 .queueCount = 1,
223 .pQueuePriorities = &priority,
224 };
225 const VkDeviceCreateInfo deviceCreateInfo = {
226 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
227 .pNext = nullptr,
228 .queueCreateInfoCount = 1,
229 .pQueueCreateInfos = &queueCreateInfo,
230 .enabledLayerCount = 0,
231 .ppEnabledLayerNames = nullptr,
232 .enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size()),
233 .ppEnabledExtensionNames = enabledDeviceExtensions.data(),
234 .pEnabledFeatures = nullptr,
235 };
236 VK_CALL(vkCreateDevice(mGpu, &deviceCreateInfo, nullptr, &mDevice));
237
238 vkGetDeviceQueue(mDevice, mQueueFamilyIndex, 0, &mQueue);
239
240 return VK_TEST_SUCCESS;
241 }
242
SwapchainInfo(const DeviceInfo * const deviceInfo)243 SwapchainInfo::SwapchainInfo(const DeviceInfo* const deviceInfo)
244 : mDeviceInfo(deviceInfo),
245 mFormat(VK_FORMAT_UNDEFINED),
246 mSurfaceSize({0, 0}),
247 mImageSize({0, 0}),
248 mSwapchain(VK_NULL_HANDLE),
249 mSwapchainLength(0) {}
250
~SwapchainInfo()251 SwapchainInfo::~SwapchainInfo() {
252 if (mDeviceInfo->device()) {
253 vkDeviceWaitIdle(mDeviceInfo->device());
254 vkDestroySwapchainKHR(mDeviceInfo->device(), mSwapchain, nullptr);
255 }
256 }
257
init(bool setPreTransform,int * outPreTransformHint)258 VkTestResult SwapchainInfo::init(bool setPreTransform, int* outPreTransformHint) {
259 VkSurfaceCapabilitiesKHR surfaceCapabilities;
260 VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
261 &surfaceCapabilities));
262 ALOGD("Vulkan Surface Capabilities:\n");
263 ALOGD("\timage count: %u - %u\n", surfaceCapabilities.minImageCount,
264 surfaceCapabilities.maxImageCount);
265 ALOGD("\tarray layers: %u\n", surfaceCapabilities.maxImageArrayLayers);
266 ALOGD("\timage size (now): %dx%d\n", surfaceCapabilities.currentExtent.width,
267 surfaceCapabilities.currentExtent.height);
268 ALOGD("\timage size (extent): %dx%d - %dx%d\n", surfaceCapabilities.minImageExtent.width,
269 surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.width,
270 surfaceCapabilities.maxImageExtent.height);
271 ALOGD("\tusage: %x\n", surfaceCapabilities.supportedUsageFlags);
272 ALOGD("\tcurrent transform: %u\n", surfaceCapabilities.currentTransform);
273 ALOGD("\tallowed transforms: %x\n", surfaceCapabilities.supportedTransforms);
274 ALOGD("\tcomposite alpha flags: %u\n", surfaceCapabilities.supportedCompositeAlpha);
275
276 uint32_t formatCount = 0;
277 VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
278 &formatCount, nullptr));
279
280 std::vector<VkSurfaceFormatKHR> formats(formatCount);
281 VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
282 &formatCount, formats.data()));
283
284 uint32_t formatIndex;
285 for (formatIndex = 0; formatIndex < formatCount; ++formatIndex) {
286 if (formats[formatIndex].format == VK_FORMAT_R8G8B8A8_UNORM) {
287 break;
288 }
289 }
290 ASSERT(formatIndex < formatCount);
291
292 mFormat = formats[formatIndex].format;
293 mImageSize = mSurfaceSize = surfaceCapabilities.currentExtent;
294
295 VkSurfaceTransformFlagBitsKHR preTransform =
296 (setPreTransform ? surfaceCapabilities.currentTransform
297 : VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
298 ALOGD("currentTransform = %u, preTransform = %u",
299 static_cast<uint32_t>(surfaceCapabilities.currentTransform),
300 static_cast<uint32_t>(preTransform));
301
302 if ((preTransform &
303 (VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
304 VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
305 VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR)) != 0) {
306 std::swap(mImageSize.width, mImageSize.height);
307 }
308
309 if (outPreTransformHint) {
310 *outPreTransformHint = surfaceCapabilities.currentTransform;
311 }
312
313 const uint32_t queueFamilyIndex = mDeviceInfo->queueFamilyIndex();
314 const VkSwapchainCreateInfoKHR swapchainCreateInfo = {
315 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
316 .pNext = nullptr,
317 .flags = 0,
318 .surface = mDeviceInfo->surface(),
319 .minImageCount = surfaceCapabilities.minImageCount,
320 .imageFormat = mFormat,
321 .imageColorSpace = formats[formatIndex].colorSpace,
322 .imageExtent = mImageSize,
323 .imageArrayLayers = 1,
324 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
325 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
326 .queueFamilyIndexCount = 1,
327 .pQueueFamilyIndices = &queueFamilyIndex,
328 .preTransform = preTransform,
329 .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
330 .presentMode = VK_PRESENT_MODE_FIFO_KHR,
331 .clipped = VK_FALSE,
332 };
333 VK_CALL(vkCreateSwapchainKHR(mDeviceInfo->device(), &swapchainCreateInfo, nullptr,
334 &mSwapchain));
335
336 VK_CALL(vkGetSwapchainImagesKHR(mDeviceInfo->device(), mSwapchain, &mSwapchainLength, nullptr));
337 ALOGD("Swapchain length = %u", mSwapchainLength);
338
339 return VK_TEST_SUCCESS;
340 }
341
Renderer(const DeviceInfo * const deviceInfo,const SwapchainInfo * const swapchainInfo)342 Renderer::Renderer(const DeviceInfo* const deviceInfo, const SwapchainInfo* const swapchainInfo)
343 : mDeviceInfo(deviceInfo),
344 mSwapchainInfo(swapchainInfo),
345 mDeviceMemory(VK_NULL_HANDLE),
346 mVertexBuffer(VK_NULL_HANDLE),
347 mRenderPass(VK_NULL_HANDLE),
348 mVertexShader(VK_NULL_HANDLE),
349 mFragmentShader(VK_NULL_HANDLE),
350 mPipelineLayout(VK_NULL_HANDLE),
351 mPipeline(VK_NULL_HANDLE),
352 mCommandPool(VK_NULL_HANDLE),
353 mSemaphore(VK_NULL_HANDLE),
354 mFence(VK_NULL_HANDLE) {}
355
~Renderer()356 Renderer::~Renderer() {
357 if (mDeviceInfo->device()) {
358 vkDeviceWaitIdle(mDeviceInfo->device());
359 vkDestroyShaderModule(mDeviceInfo->device(), mVertexShader, nullptr);
360 vkDestroyShaderModule(mDeviceInfo->device(), mFragmentShader, nullptr);
361 vkDestroyFence(mDeviceInfo->device(), mFence, nullptr);
362 vkDestroySemaphore(mDeviceInfo->device(), mSemaphore, nullptr);
363 if (!mCommandBuffers.empty()) {
364 vkFreeCommandBuffers(mDeviceInfo->device(), mCommandPool, mCommandBuffers.size(),
365 mCommandBuffers.data());
366 }
367 vkDestroyCommandPool(mDeviceInfo->device(), mCommandPool, nullptr);
368 vkDestroyPipeline(mDeviceInfo->device(), mPipeline, nullptr);
369 vkDestroyPipelineLayout(mDeviceInfo->device(), mPipelineLayout, nullptr);
370 vkDestroyBuffer(mDeviceInfo->device(), mVertexBuffer, nullptr);
371 vkFreeMemory(mDeviceInfo->device(), mDeviceMemory, nullptr);
372 vkDestroyRenderPass(mDeviceInfo->device(), mRenderPass, nullptr);
373 for (auto& framebuffer : mFramebuffers) {
374 vkDestroyFramebuffer(mDeviceInfo->device(), framebuffer, nullptr);
375 }
376 for (auto& imageView : mImageViews) {
377 vkDestroyImageView(mDeviceInfo->device(), imageView, nullptr);
378 }
379 }
380 }
381
createRenderPass()382 VkTestResult Renderer::createRenderPass() {
383 const VkAttachmentDescription attachmentDescription = {
384 .flags = 0,
385 .format = mSwapchainInfo->format(),
386 .samples = VK_SAMPLE_COUNT_1_BIT,
387 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
388 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
389 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
390 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
391 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
392 .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
393 };
394 const VkAttachmentReference attachmentReference = {
395 .attachment = 0,
396 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
397 };
398 const VkSubpassDescription subpassDescription = {
399 .flags = 0,
400 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
401 .inputAttachmentCount = 0,
402 .pInputAttachments = nullptr,
403 .colorAttachmentCount = 1,
404 .pColorAttachments = &attachmentReference,
405 .pResolveAttachments = nullptr,
406 .pDepthStencilAttachment = nullptr,
407 .preserveAttachmentCount = 0,
408 .pPreserveAttachments = nullptr,
409 };
410 const VkRenderPassCreateInfo renderPassCreateInfo = {
411 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
412 .pNext = nullptr,
413 .flags = 0,
414 .attachmentCount = 1,
415 .pAttachments = &attachmentDescription,
416 .subpassCount = 1,
417 .pSubpasses = &subpassDescription,
418 .dependencyCount = 0,
419 .pDependencies = nullptr,
420 };
421 VK_CALL(vkCreateRenderPass(mDeviceInfo->device(), &renderPassCreateInfo, nullptr,
422 &mRenderPass));
423
424 return VK_TEST_SUCCESS;
425 }
426
createFrameBuffers()427 VkTestResult Renderer::createFrameBuffers() {
428 uint32_t swapchainLength = mSwapchainInfo->swapchainLength();
429 std::vector<VkImage> images(swapchainLength, VK_NULL_HANDLE);
430 VK_CALL(vkGetSwapchainImagesKHR(mDeviceInfo->device(), mSwapchainInfo->swapchain(),
431 &swapchainLength, images.data()));
432
433 mImageViews.resize(swapchainLength, VK_NULL_HANDLE);
434 for (uint32_t i = 0; i < swapchainLength; ++i) {
435 const VkImageViewCreateInfo imageViewCreateInfo = {
436 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
437 .pNext = nullptr,
438 .flags = 0,
439 .image = images[i],
440 .viewType = VK_IMAGE_VIEW_TYPE_2D,
441 .format = mSwapchainInfo->format(),
442 .components =
443 {
444 .r = VK_COMPONENT_SWIZZLE_R,
445 .g = VK_COMPONENT_SWIZZLE_G,
446 .b = VK_COMPONENT_SWIZZLE_B,
447 .a = VK_COMPONENT_SWIZZLE_A,
448 },
449 .subresourceRange =
450 {
451 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
452 .baseMipLevel = 0,
453 .levelCount = 1,
454 .baseArrayLayer = 0,
455 .layerCount = 1,
456 },
457 };
458 VK_CALL(vkCreateImageView(mDeviceInfo->device(), &imageViewCreateInfo, nullptr,
459 &mImageViews[i]));
460 }
461
462 mFramebuffers.resize(swapchainLength, VK_NULL_HANDLE);
463 for (uint32_t i = 0; i < swapchainLength; ++i) {
464 const VkFramebufferCreateInfo framebufferCreateInfo = {
465 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
466 .pNext = nullptr,
467 .flags = 0,
468 .renderPass = mRenderPass,
469 .attachmentCount = 1,
470 .pAttachments = &mImageViews[i],
471 .width = mSwapchainInfo->imageSize().width,
472 .height = mSwapchainInfo->imageSize().height,
473 .layers = 1,
474 };
475 VK_CALL(vkCreateFramebuffer(mDeviceInfo->device(), &framebufferCreateInfo, nullptr,
476 &mFramebuffers[i]));
477 }
478
479 return VK_TEST_SUCCESS;
480 }
481
createVertexBuffers()482 VkTestResult Renderer::createVertexBuffers() {
483 const uint32_t queueFamilyIndex = mDeviceInfo->queueFamilyIndex();
484 const VkBufferCreateInfo bufferCreateInfo = {
485 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
486 .pNext = nullptr,
487 .flags = 0,
488 .size = sizeof(vertexData),
489 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
490 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
491 .queueFamilyIndexCount = 1,
492 .pQueueFamilyIndices = &queueFamilyIndex,
493 };
494 VK_CALL(vkCreateBuffer(mDeviceInfo->device(), &bufferCreateInfo, nullptr, &mVertexBuffer));
495
496 VkMemoryRequirements memoryRequirements;
497 vkGetBufferMemoryRequirements(mDeviceInfo->device(), mVertexBuffer, &memoryRequirements);
498
499 VkPhysicalDeviceMemoryProperties memoryProperties;
500 vkGetPhysicalDeviceMemoryProperties(mDeviceInfo->gpu(), &memoryProperties);
501
502 int32_t typeIndex = -1;
503 for (int32_t i = 0, typeBits = memoryRequirements.memoryTypeBits; i < 32; ++i) {
504 if ((typeBits & 1) == 1) {
505 if ((memoryProperties.memoryTypes[i].propertyFlags &
506 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
507 typeIndex = i;
508 break;
509 }
510 }
511 typeBits >>= 1;
512 }
513 ASSERT(typeIndex != -1);
514
515 VkMemoryAllocateInfo memoryAllocateInfo = {
516 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
517 .pNext = nullptr,
518 .allocationSize = memoryRequirements.size,
519 .memoryTypeIndex = static_cast<uint32_t>(typeIndex),
520 };
521 VK_CALL(vkAllocateMemory(mDeviceInfo->device(), &memoryAllocateInfo, nullptr, &mDeviceMemory));
522
523 void* data;
524 VK_CALL(vkMapMemory(mDeviceInfo->device(), mDeviceMemory, 0, sizeof(vertexData), 0, &data));
525
526 memcpy(data, vertexData, sizeof(vertexData));
527 vkUnmapMemory(mDeviceInfo->device(), mDeviceMemory);
528
529 VK_CALL(vkBindBufferMemory(mDeviceInfo->device(), mVertexBuffer, mDeviceMemory, 0));
530
531 return VK_TEST_SUCCESS;
532 }
533
loadShaderFromFile(const char * filePath,VkShaderModule * const outShader)534 VkTestResult Renderer::loadShaderFromFile(const char* filePath, VkShaderModule* const outShader) {
535 ASSERT(filePath);
536
537 AAsset* file = AAssetManager_open(mAssetManager, filePath, AASSET_MODE_BUFFER);
538 ASSERT(file);
539
540 size_t fileLength = AAsset_getLength(file);
541 std::vector<char> fileContent(fileLength);
542 AAsset_read(file, fileContent.data(), fileLength);
543 AAsset_close(file);
544
545 const VkShaderModuleCreateInfo shaderModuleCreateInfo = {
546 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
547 .pNext = nullptr,
548 .flags = 0,
549 .codeSize = fileLength,
550 .pCode = (const uint32_t*)(fileContent.data()),
551 };
552 VK_CALL(vkCreateShaderModule(mDeviceInfo->device(), &shaderModuleCreateInfo, nullptr,
553 outShader));
554
555 return VK_TEST_SUCCESS;
556 }
557
createGraphicsPipeline()558 VkTestResult Renderer::createGraphicsPipeline() {
559 const VkPushConstantRange pushConstantRange = {
560 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
561 .offset = 0,
562 .size = 3 * sizeof(float),
563 };
564 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
565 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
566 .pNext = nullptr,
567 .flags = 0,
568 .setLayoutCount = 0,
569 .pSetLayouts = nullptr,
570 .pushConstantRangeCount = 1,
571 .pPushConstantRanges = &pushConstantRange,
572 };
573 VK_CALL(vkCreatePipelineLayout(mDeviceInfo->device(), &pipelineLayoutCreateInfo, nullptr,
574 &mPipelineLayout));
575
576 ASSERT(!loadShaderFromFile("shaders/tri.vert.spv", &mVertexShader));
577 ASSERT(!loadShaderFromFile("shaders/tri.frag.spv", &mFragmentShader));
578
579 const VkPipelineShaderStageCreateInfo shaderStages[2] =
580 {{
581 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
582 .pNext = nullptr,
583 .flags = 0,
584 .stage = VK_SHADER_STAGE_VERTEX_BIT,
585 .module = mVertexShader,
586 .pName = "main",
587 .pSpecializationInfo = nullptr,
588 },
589 {
590 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
591 .pNext = nullptr,
592 .flags = 0,
593 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
594 .module = mFragmentShader,
595 .pName = "main",
596 .pSpecializationInfo = nullptr,
597 }};
598 const VkViewport viewports = {
599 .x = 0.0f,
600 .y = 0.0f,
601 .width = (float)mSwapchainInfo->imageSize().width,
602 .height = (float)mSwapchainInfo->imageSize().height,
603 .minDepth = 0.0f,
604 .maxDepth = 1.0f,
605 };
606 const VkRect2D scissor = {
607 .offset =
608 {
609 .x = 0,
610 .y = 0,
611 },
612 .extent = mSwapchainInfo->imageSize(),
613 };
614 const VkPipelineViewportStateCreateInfo viewportInfo = {
615 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
616 .pNext = nullptr,
617 .flags = 0,
618 .viewportCount = 1,
619 .pViewports = &viewports,
620 .scissorCount = 1,
621 .pScissors = &scissor,
622 };
623 VkSampleMask sampleMask = ~0u;
624 const VkPipelineMultisampleStateCreateInfo multisampleInfo = {
625 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
626 .pNext = nullptr,
627 .flags = 0,
628 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
629 .sampleShadingEnable = VK_FALSE,
630 .minSampleShading = 0,
631 .pSampleMask = &sampleMask,
632 .alphaToCoverageEnable = VK_FALSE,
633 .alphaToOneEnable = VK_FALSE,
634 };
635 const VkPipelineColorBlendAttachmentState attachmentStates = {
636 .blendEnable = VK_FALSE,
637 .srcColorBlendFactor = (VkBlendFactor)0,
638 .dstColorBlendFactor = (VkBlendFactor)0,
639 .colorBlendOp = (VkBlendOp)0,
640 .srcAlphaBlendFactor = (VkBlendFactor)0,
641 .dstAlphaBlendFactor = (VkBlendFactor)0,
642 .alphaBlendOp = (VkBlendOp)0,
643 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
644 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
645 };
646 const VkPipelineColorBlendStateCreateInfo colorBlendInfo = {
647 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
648 .pNext = nullptr,
649 .flags = 0,
650 .logicOpEnable = VK_FALSE,
651 .logicOp = VK_LOGIC_OP_COPY,
652 .attachmentCount = 1,
653 .pAttachments = &attachmentStates,
654 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
655 };
656 const VkPipelineRasterizationStateCreateInfo rasterInfo = {
657 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
658 .pNext = nullptr,
659 .flags = 0,
660 .depthClampEnable = VK_FALSE,
661 .rasterizerDiscardEnable = VK_FALSE,
662 .polygonMode = VK_POLYGON_MODE_FILL,
663 .cullMode = VK_CULL_MODE_NONE,
664 .frontFace = VK_FRONT_FACE_CLOCKWISE,
665 .depthBiasEnable = VK_FALSE,
666 .depthBiasConstantFactor = 0,
667 .depthBiasClamp = 0,
668 .depthBiasSlopeFactor = 0,
669 .lineWidth = 1,
670 };
671 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {
672 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
673 .pNext = nullptr,
674 .flags = 0,
675 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
676 .primitiveRestartEnable = VK_FALSE,
677 };
678 const VkVertexInputBindingDescription vertexInputBindingDescription = {
679 .binding = 0,
680 .stride = 3 * sizeof(float),
681 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
682 };
683 const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
684 .location = 0,
685 .binding = 0,
686 .format = VK_FORMAT_R32G32B32_SFLOAT,
687 .offset = 0,
688 };
689 const VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
690 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
691 .pNext = nullptr,
692 .flags = 0,
693 .vertexBindingDescriptionCount = 1,
694 .pVertexBindingDescriptions = &vertexInputBindingDescription,
695 .vertexAttributeDescriptionCount = 1,
696 .pVertexAttributeDescriptions = &vertexInputAttributeDescription,
697 };
698 const VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
699 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
700 .pNext = nullptr,
701 .flags = 0,
702 .stageCount = 2,
703 .pStages = shaderStages,
704 .pVertexInputState = &vertexInputInfo,
705 .pInputAssemblyState = &inputAssemblyInfo,
706 .pTessellationState = nullptr,
707 .pViewportState = &viewportInfo,
708 .pRasterizationState = &rasterInfo,
709 .pMultisampleState = &multisampleInfo,
710 .pDepthStencilState = nullptr,
711 .pColorBlendState = &colorBlendInfo,
712 .pDynamicState = nullptr,
713 .layout = mPipelineLayout,
714 .renderPass = mRenderPass,
715 .subpass = 0,
716 .basePipelineHandle = VK_NULL_HANDLE,
717 .basePipelineIndex = 0,
718 };
719 VK_CALL(vkCreateGraphicsPipelines(mDeviceInfo->device(), VK_NULL_HANDLE, 1, &pipelineCreateInfo,
720 nullptr, &mPipeline));
721
722 vkDestroyShaderModule(mDeviceInfo->device(), mVertexShader, nullptr);
723 vkDestroyShaderModule(mDeviceInfo->device(), mFragmentShader, nullptr);
724 mVertexShader = VK_NULL_HANDLE;
725 mFragmentShader = VK_NULL_HANDLE;
726
727 return VK_TEST_SUCCESS;
728 }
729
init(JNIEnv * env,jobject jAssetManager)730 VkTestResult Renderer::init(JNIEnv* env, jobject jAssetManager) {
731 mAssetManager = AAssetManager_fromJava(env, jAssetManager);
732 ASSERT(mAssetManager);
733
734 ASSERT(!createRenderPass());
735
736 ASSERT(!createFrameBuffers());
737
738 ASSERT(!createVertexBuffers());
739
740 ASSERT(!createGraphicsPipeline());
741
742 const VkCommandPoolCreateInfo commandPoolCreateInfo = {
743 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
744 .pNext = nullptr,
745 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
746 .queueFamilyIndex = mDeviceInfo->queueFamilyIndex(),
747 };
748 VK_CALL(vkCreateCommandPool(mDeviceInfo->device(), &commandPoolCreateInfo, nullptr,
749 &mCommandPool));
750
751 uint32_t swapchainLength = mSwapchainInfo->swapchainLength();
752 mCommandBuffers.resize(swapchainLength, VK_NULL_HANDLE);
753 const VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
754 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
755 .pNext = nullptr,
756 .commandPool = mCommandPool,
757 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
758 .commandBufferCount = swapchainLength,
759 };
760 VK_CALL(vkAllocateCommandBuffers(mDeviceInfo->device(), &commandBufferAllocateInfo,
761 mCommandBuffers.data()));
762
763 for (uint32_t i = 0; i < swapchainLength; ++i) {
764 const VkCommandBufferBeginInfo commandBufferBeginInfo = {
765 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
766 .pNext = nullptr,
767 .flags = 0,
768 .pInheritanceInfo = nullptr,
769 };
770 VK_CALL(vkBeginCommandBuffer(mCommandBuffers[i], &commandBufferBeginInfo));
771
772 const VkClearValue clearVals = {
773 .color.float32[0] = 0.0f,
774 .color.float32[1] = 0.0f,
775 .color.float32[2] = 0.0f,
776 .color.float32[3] = 1.0f,
777 };
778 const VkRenderPassBeginInfo renderPassBeginInfo = {
779 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
780 .pNext = nullptr,
781 .renderPass = mRenderPass,
782 .framebuffer = mFramebuffers[i],
783 .renderArea =
784 {
785 .offset =
786 {
787 .x = 0,
788 .y = 0,
789 },
790 .extent = mSwapchainInfo->imageSize(),
791 },
792 .clearValueCount = 1,
793 .pClearValues = &clearVals,
794 };
795 vkCmdBeginRenderPass(mCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
796
797 vkCmdBindPipeline(mCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline);
798
799 VkDeviceSize offset = 0;
800 vkCmdBindVertexBuffers(mCommandBuffers[i], 0, 1, &mVertexBuffer, &offset);
801
802 vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
803 3 * sizeof(float), &fragData[0]);
804 vkCmdDraw(mCommandBuffers[i], 4, 1, 0, 0);
805
806 vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
807 3 * sizeof(float), &fragData[3]);
808 vkCmdDraw(mCommandBuffers[i], 4, 1, 2, 0);
809
810 vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
811 3 * sizeof(float), &fragData[6]);
812 vkCmdDraw(mCommandBuffers[i], 4, 1, 6, 0);
813
814 vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
815 3 * sizeof(float), &fragData[9]);
816 vkCmdDraw(mCommandBuffers[i], 4, 1, 8, 0);
817
818 vkCmdEndRenderPass(mCommandBuffers[i]);
819
820 VK_CALL(vkEndCommandBuffer(mCommandBuffers[i]));
821 }
822
823 const VkFenceCreateInfo fenceCreateInfo = {
824 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
825 .pNext = nullptr,
826 .flags = 0,
827 };
828 VK_CALL(vkCreateFence(mDeviceInfo->device(), &fenceCreateInfo, nullptr, &mFence));
829
830 const VkSemaphoreCreateInfo semaphoreCreateInfo = {
831 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
832 .pNext = nullptr,
833 .flags = 0,
834 };
835 VK_CALL(vkCreateSemaphore(mDeviceInfo->device(), &semaphoreCreateInfo, nullptr, &mSemaphore));
836
837 return VK_TEST_SUCCESS;
838 }
839
drawFrame()840 VkTestResult Renderer::drawFrame() {
841 uint32_t nextIndex;
842 VK_CALL(vkAcquireNextImageKHR(mDeviceInfo->device(), mSwapchainInfo->swapchain(), UINT64_MAX,
843 mSemaphore, VK_NULL_HANDLE, &nextIndex));
844
845 VK_CALL(vkResetFences(mDeviceInfo->device(), 1, &mFence));
846
847 VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
848 const VkSubmitInfo submitInfo = {
849 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
850 .pNext = nullptr,
851 .waitSemaphoreCount = 1,
852 .pWaitSemaphores = &mSemaphore,
853 .pWaitDstStageMask = &waitStageMask,
854 .commandBufferCount = 1,
855 .pCommandBuffers = &mCommandBuffers[nextIndex],
856 .signalSemaphoreCount = 0,
857 .pSignalSemaphores = nullptr,
858 };
859 VK_CALL(vkQueueSubmit(mDeviceInfo->queue(), 1, &submitInfo, mFence))
860
861 VK_CALL(vkWaitForFences(mDeviceInfo->device(), 1, &mFence, VK_TRUE, TIMEOUT_30_SEC));
862
863 const VkSwapchainKHR swapchain = mSwapchainInfo->swapchain();
864 const VkPresentInfoKHR presentInfo = {
865 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
866 .pNext = nullptr,
867 .waitSemaphoreCount = 0,
868 .pWaitSemaphores = nullptr,
869 .swapchainCount = 1,
870 .pSwapchains = &swapchain,
871 .pImageIndices = &nextIndex,
872 .pResults = nullptr,
873 };
874 VkResult ret = vkQueuePresentKHR(mDeviceInfo->queue(), &presentInfo);
875 if (ret == VK_SUBOPTIMAL_KHR) {
876 return VK_TEST_SUCCESS_SUBOPTIMAL;
877 }
878
879 return ret == VK_SUCCESS ? VK_TEST_SUCCESS : VK_TEST_ERROR;
880 }
881