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