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