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