blob: af3d58560b31ccf7503caedfa5c44209e4c80790 [file] [log] [blame]
Jesse Hallb1352bc2015-09-04 16:12:33 -07001/*
2 * Copyright 2015 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
Jesse Halld7b994a2015-09-07 14:17:37 -070017// #define LOG_NDEBUG 0
18
19#include <algorithm>
20#include <memory>
21
22#include <gui/BufferQueue.h>
Jesse Hallb1352bc2015-09-04 16:12:33 -070023#include <log/log.h>
Jesse Halld7b994a2015-09-07 14:17:37 -070024#include <sync/sync.h>
25
26#include "loader.h"
27
28using namespace vulkan;
29
30namespace {
31
32// ----------------------------------------------------------------------------
33// These functions/classes form an adaptor that allows objects to be refcounted
34// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
35// allocation of the shared_ptr<> control structure to VkAllocCallbacks. The
36// platform holds a reference to the ANativeWindow using its embedded reference
37// count, and the ANativeWindow implementation holds references to the
38// ANativeWindowBuffers using their embedded reference counts, so the
39// shared_ptr *must* cooperate with these and hold at least one reference to
40// the object using the embedded reference count.
41
42template <typename T>
43struct NativeBaseDeleter {
44 void operator()(T* obj) { obj->common.decRef(&obj->common); }
45};
46
47template <typename T>
48class VulkanAllocator {
49 public:
50 typedef T value_type;
51
52 explicit VulkanAllocator(VkDevice device) : device_(device) {}
53
54 template <typename U>
55 explicit VulkanAllocator(const VulkanAllocator<U>& other)
56 : device_(other.device_) {}
57
58 T* allocate(size_t n) const {
59 return static_cast<T*>(AllocDeviceMem(
60 device_, n * sizeof(T), alignof(T), VK_SYSTEM_ALLOC_TYPE_INTERNAL));
61 }
62 void deallocate(T* p, size_t) const { return FreeDeviceMem(device_, p); }
63
64 private:
65 template <typename U>
66 friend class VulkanAllocator;
67 VkDevice device_;
68};
69
70template <typename T>
71std::shared_ptr<T> InitSharedPtr(VkDevice device, T* obj) {
72 obj->common.incRef(&obj->common);
73 return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
74 VulkanAllocator<T>(device));
75}
76
77// ----------------------------------------------------------------------------
78
79struct Swapchain {
80 Swapchain(std::shared_ptr<ANativeWindow> window_, uint32_t num_images_)
81 : window(window_), num_images(num_images_) {}
82
83 std::shared_ptr<ANativeWindow> window;
84 uint32_t num_images;
85
86 struct Image {
87 Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
88 VkImage image;
89 std::shared_ptr<ANativeWindowBuffer> buffer;
90 // The fence is only valid when the buffer is dequeued, and should be
91 // -1 any other time. When valid, we own the fd, and must ensure it is
92 // closed: either by closing it explicitly when queueing the buffer,
93 // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
94 int dequeue_fence;
95 bool dequeued;
96 } images[android::BufferQueue::NUM_BUFFER_SLOTS];
97};
98
99VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
100 return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
101}
102
103Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
104 return reinterpret_cast<Swapchain*>(handle.handle);
105}
106
107} // anonymous namespace
Jesse Hallb1352bc2015-09-04 16:12:33 -0700108
109namespace vulkan {
110
111VkResult GetPhysicalDeviceSurfaceSupportKHR(
112 VkPhysicalDevice /*pdev*/,
113 uint32_t /*queue_family*/,
114 const VkSurfaceDescriptionKHR* surface_desc,
115 VkBool32* supported) {
116// TODO(jessehall): Fix the header, preferrably upstream, so values added to
117// existing enums don't trigger warnings like this.
118#pragma clang diagnostic push
119#pragma clang diagnostic ignored "-Wold-style-cast"
120#pragma clang diagnostic ignored "-Wsign-conversion"
121 if (surface_desc->sType != VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR)
122 return VK_ERROR_INVALID_VALUE;
123#pragma clang diagnostic pop
124
125 const VkSurfaceDescriptionWindowKHR* window_desc =
126 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
127
128 // TODO(jessehall): Also check whether the physical device exports the
129 // VK_EXT_ANDROID_native_buffer extension. For now, assume it does.
130 *supported = (window_desc->platform == VK_PLATFORM_ANDROID_KHR &&
131 !window_desc->pPlatformHandle &&
132 static_cast<ANativeWindow*>(window_desc->pPlatformWindow)
133 ->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
134
135 return VK_SUCCESS;
136}
137
Jesse Halld7b994a2015-09-07 14:17:37 -0700138VkResult GetSurfacePropertiesKHR(VkDevice /*device*/,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700139 const VkSurfaceDescriptionKHR* surface_desc,
140 VkSurfacePropertiesKHR* properties) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700141 const VkSurfaceDescriptionWindowKHR* window_desc =
142 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
143 ANativeWindow* window =
144 static_cast<ANativeWindow*>(window_desc->pPlatformWindow);
145
146 int err;
147
148 // TODO(jessehall): Currently the window must be connected for several
149 // queries -- including default dimensions -- to work, since Surface caches
150 // the queried values at connect() and queueBuffer(), and query() returns
151 // those cached values.
152 //
153 // The proposed refactoring to create a VkSurface object (bug 14596) will
154 // give us a place to connect once per window. If that doesn't end up
155 // happening, we'll probably need to maintain an internal list of windows
156 // that have swapchains created for them, search that list here, and
157 // only temporarily connect if the window doesn't have a swapchain.
158
159 bool disconnect = true;
160 err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
161 if (err == -EINVAL) {
162 // This is returned if the window is already connected, among other
163 // things. We'll just assume we're already connected and charge ahead.
164 // See TODO above, this is not cool.
165 ALOGW(
166 "vkGetSurfacePropertiesKHR: native_window_api_connect returned "
167 "-EINVAL, assuming already connected");
168 err = 0;
169 disconnect = false;
170 } else if (err != 0) {
171 // TODO(jessehall): Improve error reporting. Can we enumerate possible
172 // errors and translate them to valid Vulkan result codes?
173 return VK_ERROR_UNKNOWN;
174 }
175
176 int width, height;
177 err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
178 if (err != 0) {
179 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
180 strerror(-err), err);
181 if (disconnect)
182 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
183 return VK_ERROR_UNKNOWN;
184 }
185 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
186 if (err != 0) {
187 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
188 strerror(-err), err);
189 if (disconnect)
190 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
191 return VK_ERROR_UNKNOWN;
192 }
193
194 if (disconnect)
195 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
196
197 properties->currentExtent = VkExtent2D{width, height};
198
199 // TODO(jessehall): Figure out what the min/max values should be.
200 properties->minImageCount = 2;
201 properties->maxImageCount = 3;
202
203 // TODO(jessehall): Figure out what the max extent should be. Maximum
204 // texture dimension maybe?
205 properties->minImageExtent = VkExtent2D{1, 1};
206 properties->maxImageExtent = VkExtent2D{4096, 4096};
207
208 // TODO(jessehall): We can support all transforms, fix this once
209 // implemented.
210 properties->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_KHR;
211
212 // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
213 properties->currentTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
214
215 properties->maxImageArraySize = 1;
216
217 // TODO(jessehall): I think these are right, but haven't thought hard about
218 // it. Do we need to query the driver for support of any of these?
219 // Currently not included:
220 // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
221 // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
222 // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
223 properties->supportedUsageFlags =
224 VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT |
225 VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
226 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
227 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
228
Jesse Hallb1352bc2015-09-04 16:12:33 -0700229 return VK_SUCCESS;
230}
231
Jesse Halld7b994a2015-09-07 14:17:37 -0700232VkResult GetSurfaceFormatsKHR(VkDevice /*device*/,
233 const VkSurfaceDescriptionKHR* /*surface_desc*/,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700234 uint32_t* count,
235 VkSurfaceFormatKHR* formats) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700236 // TODO(jessehall): Fill out the set of supported formats. Open question
237 // whether we should query the driver for support -- how does it know what
238 // the consumer can support? Should we support formats that don't
239 // correspond to gralloc formats?
240
241 const VkSurfaceFormatKHR kFormats[] = {
242 {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
243 {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
244 };
245 const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
246
247 VkResult result = VK_SUCCESS;
248 if (formats) {
249 if (*count < kNumFormats)
250 result = VK_INCOMPLETE;
251 std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
252 }
253 *count = kNumFormats;
254 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700255}
256
Jesse Halld7b994a2015-09-07 14:17:37 -0700257VkResult GetSurfacePresentModesKHR(
258 VkDevice /*device*/,
259 const VkSurfaceDescriptionKHR* /*surface_desc*/,
260 uint32_t* count,
261 VkPresentModeKHR* modes) {
262 const VkPresentModeKHR kModes[] = {
263 VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
264 };
265 const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
266
267 VkResult result = VK_SUCCESS;
268 if (modes) {
269 if (*count < kNumModes)
270 result = VK_INCOMPLETE;
271 std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
272 }
273 *count = kNumModes;
274 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700275}
276
277VkResult CreateSwapchainKHR(VkDevice device,
278 const VkSwapchainCreateInfoKHR* create_info,
Jesse Halld7b994a2015-09-07 14:17:37 -0700279 VkSwapchainKHR* swapchain_handle) {
280 int err;
281 VkResult result = VK_SUCCESS;
282
283 ALOGV_IF(create_info->imageArraySize != 1,
284 "Swapchain imageArraySize (%u) != 1 not supported",
285 create_info->imageArraySize);
286
287 ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
288 "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
289 ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
290 "color spaces other than SRGB_NONLINEAR not yet implemented");
291 ALOGE_IF(create_info->oldSwapchain,
292 "swapchain re-creation not yet implemented");
293 ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_NONE_KHR,
294 "swapchain preTransform not yet implemented");
295 ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
296 "present modes other than FIFO are not yet implemented");
297
298 // -- Configure the native window --
299 // Failure paths from here on need to disconnect the window.
300
301 std::shared_ptr<ANativeWindow> window = InitSharedPtr(
302 device, static_cast<ANativeWindow*>(
303 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(
304 create_info->pSurfaceDescription)
305 ->pPlatformWindow));
306
307 // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
308 err = native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL);
309 if (err != 0) {
310 // TODO(jessehall): Improve error reporting. Can we enumerate possible
311 // errors and translate them to valid Vulkan result codes?
312 ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
313 err);
314 return VK_ERROR_UNKNOWN;
315 }
316
317 err = native_window_set_buffers_dimensions(window.get(),
318 create_info->imageExtent.width,
319 create_info->imageExtent.height);
320 if (err != 0) {
321 // TODO(jessehall): Improve error reporting. Can we enumerate possible
322 // errors and translate them to valid Vulkan result codes?
323 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
324 create_info->imageExtent.width, create_info->imageExtent.height,
325 strerror(-err), err);
326 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
327 return VK_ERROR_UNKNOWN;
328 }
329
330 uint32_t min_undequeued_buffers;
331 err = window->query(window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
332 reinterpret_cast<int*>(&min_undequeued_buffers));
333 if (err != 0) {
334 // TODO(jessehall): Improve error reporting. Can we enumerate possible
335 // errors and translate them to valid Vulkan result codes?
336 ALOGE("window->query failed: %s (%d)", strerror(-err), err);
337 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
338 return VK_ERROR_UNKNOWN;
339 }
340 uint32_t num_images =
341 (create_info->minImageCount - 1) + min_undequeued_buffers;
342 err = native_window_set_buffer_count(window.get(), num_images);
343 if (err != 0) {
344 // TODO(jessehall): Improve error reporting. Can we enumerate possible
345 // errors and translate them to valid Vulkan result codes?
346 ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
347 err);
348 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
349 return VK_ERROR_UNKNOWN;
350 }
351
352 // TODO(jessehall): Do we need to call modify native_window_set_usage()
353 // based on create_info->imageUsageFlags?
354
355 // -- Allocate our Swapchain object --
356 // After this point, we must deallocate the swapchain on error.
357
358 void* mem = AllocDeviceMem(device, sizeof(Swapchain), alignof(Swapchain),
359 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
360 if (!mem) {
361 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
362 return VK_ERROR_OUT_OF_HOST_MEMORY;
363 }
364 Swapchain* swapchain = new (mem) Swapchain(window, num_images);
365
366 // -- Dequeue all buffers and create a VkImage for each --
367 // Any failures during or after this must cancel the dequeued buffers.
368
369 VkNativeBufferANDROID image_native_buffer = {
370// TODO(jessehall): Figure out how to make extension headers not horrible.
371#pragma clang diagnostic push
372#pragma clang diagnostic ignored "-Wold-style-cast"
373 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
374#pragma clang diagnostic pop
375 .pNext = nullptr,
376 };
377 VkImageCreateInfo image_create = {
378 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
379 .pNext = &image_native_buffer,
380 .imageType = VK_IMAGE_TYPE_2D,
381 .format = VK_FORMAT_R8G8B8A8_UNORM, // TODO(jessehall)
382 .extent = {0, 0, 1},
383 .mipLevels = 1,
384 .arraySize = 1,
385 .samples = 1,
386 .tiling = VK_IMAGE_TILING_OPTIMAL,
387 .usage = create_info->imageUsageFlags,
388 .flags = 0,
389 .sharingMode = create_info->sharingMode,
390 .queueFamilyCount = create_info->queueFamilyCount,
391 .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
392 };
393
394 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
395 for (uint32_t i = 0; i < num_images; i++) {
396 Swapchain::Image& img = swapchain->images[i];
397
398 ANativeWindowBuffer* buffer;
399 err = window->dequeueBuffer(window.get(), &buffer, &img.dequeue_fence);
400 if (err != 0) {
401 // TODO(jessehall): Improve error reporting. Can we enumerate
402 // possible errors and translate them to valid Vulkan result codes?
403 ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
404 result = VK_ERROR_UNKNOWN;
405 break;
406 }
407 img.buffer = InitSharedPtr(device, buffer);
408 img.dequeued = true;
409
410 image_create.extent =
411 VkExtent3D{img.buffer->width, img.buffer->height, 1};
412 image_native_buffer.handle = img.buffer->handle;
413 image_native_buffer.stride = img.buffer->stride;
414 image_native_buffer.format = img.buffer->format;
415 image_native_buffer.usage = img.buffer->usage;
416
417 result = driver_vtbl.CreateImage(device, &image_create, &img.image);
418 if (result != VK_SUCCESS) {
419 ALOGD("vkCreateImage w/ native buffer failed: %u", result);
420 break;
421 }
422 }
423
424 // -- Cancel all buffers, returning them to the queue --
425 // If an error occurred before, also destroy the VkImage and release the
426 // buffer reference. Otherwise, we retain a strong reference to the buffer.
427 //
428 // TODO(jessehall): The error path here is the same as DestroySwapchain,
429 // but not the non-error path. Should refactor/unify.
430 for (uint32_t i = 0; i < num_images; i++) {
431 Swapchain::Image& img = swapchain->images[i];
432 if (img.dequeued) {
433 window->cancelBuffer(window.get(), img.buffer.get(),
434 img.dequeue_fence);
435 img.dequeue_fence = -1;
436 img.dequeued = false;
437 }
438 if (result != VK_SUCCESS) {
439 if (img.image)
440 driver_vtbl.DestroyImage(device, img.image);
441 }
442 }
443
444 if (result != VK_SUCCESS) {
445 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
446 swapchain->~Swapchain();
447 FreeDeviceMem(device, swapchain);
448 return result;
449 }
450
451 *swapchain_handle = HandleFromSwapchain(swapchain);
Jesse Hallb1352bc2015-09-04 16:12:33 -0700452 return VK_SUCCESS;
453}
454
Jesse Halld7b994a2015-09-07 14:17:37 -0700455VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle) {
456 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
457 Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
458 const std::shared_ptr<ANativeWindow>& window = swapchain->window;
459
460 for (uint32_t i = 0; i < swapchain->num_images; i++) {
461 Swapchain::Image& img = swapchain->images[i];
462 if (img.dequeued) {
463 window->cancelBuffer(window.get(), img.buffer.get(),
464 img.dequeue_fence);
465 img.dequeue_fence = -1;
466 img.dequeued = false;
467 }
468 if (img.image) {
469 driver_vtbl.DestroyImage(device, img.image);
470 }
471 }
472
473 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
474 swapchain->~Swapchain();
475 FreeDeviceMem(device, swapchain);
476
Jesse Hallb1352bc2015-09-04 16:12:33 -0700477 return VK_SUCCESS;
478}
479
Jesse Halld7b994a2015-09-07 14:17:37 -0700480VkResult GetSwapchainImagesKHR(VkDevice,
481 VkSwapchainKHR swapchain_handle,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700482 uint32_t* count,
Jesse Halld7b994a2015-09-07 14:17:37 -0700483 VkImage* images) {
484 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
485 VkResult result = VK_SUCCESS;
486 if (images) {
487 uint32_t n = swapchain.num_images;
488 if (*count < swapchain.num_images) {
489 n = *count;
490 result = VK_INCOMPLETE;
491 }
492 for (uint32_t i = 0; i < n; i++)
493 images[i] = swapchain.images[i].image;
494 }
495 *count = swapchain.num_images;
496 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700497}
498
499VkResult AcquireNextImageKHR(VkDevice device,
Jesse Halld7b994a2015-09-07 14:17:37 -0700500 VkSwapchainKHR swapchain_handle,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700501 uint64_t timeout,
502 VkSemaphore semaphore,
503 uint32_t* image_index) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700504 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
505 VkResult result;
506 int err;
507
508 ALOGW_IF(
509 timeout != UINT64_MAX,
510 "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
511
512 ANativeWindowBuffer* buffer;
513 int fence;
514 err = swapchain.window->dequeueBuffer(swapchain.window.get(), &buffer,
515 &fence);
516 if (err != 0) {
517 // TODO(jessehall): Improve error reporting. Can we enumerate possible
518 // errors and translate them to valid Vulkan result codes?
519 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
520 return VK_ERROR_UNKNOWN;
521 }
522
523 uint32_t idx;
524 for (idx = 0; idx < swapchain.num_images; idx++) {
525 if (swapchain.images[idx].buffer.get() == buffer) {
526 swapchain.images[idx].dequeued = true;
527 swapchain.images[idx].dequeue_fence = fence;
528 break;
529 }
530 }
531 if (idx == swapchain.num_images) {
532 ALOGE("dequeueBuffer returned unrecognized buffer");
533 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
534#pragma clang diagnostic push
535#pragma clang diagnostic ignored "-Wold-style-cast"
536 return VK_ERROR_OUT_OF_DATE_KHR;
537#pragma clang diagnostic pop
538 }
539
540 int fence_clone = -1;
541 if (fence != -1) {
542 fence_clone = dup(fence);
543 if (fence_clone == -1) {
544 ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
545 strerror(errno), errno);
546 sync_wait(fence, -1 /* forever */);
547 }
548 }
549
550 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
551 result =
552 driver_vtbl.ImportNativeFenceANDROID(device, semaphore, fence_clone);
553 if (result != VK_SUCCESS) {
554 // NOTE: we're relying on ImportNativeFenceANDROID to close
555 // fence_clone, even if the call fails. We could close it ourselves on
556 // failure, but that would create a race condition if the driver closes
557 // it on a failure path. We must assume one of: the driver *always*
558 // closes it even on failure, or *never* closes it on failure.
559 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
560 swapchain.images[idx].dequeued = false;
561 swapchain.images[idx].dequeue_fence = -1;
562 return result;
563 }
564
565 *image_index = idx;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700566 return VK_SUCCESS;
567}
568
569VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700570#pragma clang diagnostic push
571#pragma clang diagnostic ignored "-Wold-style-cast"
572#pragma clang diagnostic ignored "-Wsign-conversion"
573 ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
574 "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
575 present_info->sType);
Jesse Hallb1352bc2015-09-04 16:12:33 -0700576#pragma clang diagnostic pop
Jesse Halld7b994a2015-09-07 14:17:37 -0700577 ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
578
579 const DeviceVtbl& driver_vtbl = GetDriverVtbl(queue);
580 VkResult final_result = VK_SUCCESS;
581 for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
582 Swapchain& swapchain =
583 *SwapchainFromHandle(present_info->swapchains[sc]);
584 uint32_t image_idx = present_info->imageIndices[sc];
585 VkResult result;
586 int err;
587
588 if (image_idx >= swapchain.num_images ||
589 !swapchain.images[image_idx].dequeued) {
590 ALOGE(
591 "invalid image index or image not acquired: swapchain=%u "
592 "index=%u",
593 sc, image_idx);
594 final_result = VK_ERROR_INVALID_VALUE;
595 continue;
596 }
597 Swapchain::Image& img = swapchain.images[image_idx];
598
599 int fence = -1;
600 result = driver_vtbl.QueueSignalNativeFenceANDROID(queue, &fence);
601 if (result != VK_SUCCESS) {
602 ALOGE("vkQueueSignalNativeFenceANDROID failed: %d", result);
603 if (final_result == VK_SUCCESS)
604 final_result = result;
605 // TODO(jessehall): What happens to the buffer here? Does the app
606 // still own it or not, i.e. should we cancel the buffer? Hard to
607 // do correctly without synchronizing, though I guess we could wait
608 // for the queue to idle.
609 continue;
610 }
611
612 err = swapchain.window->queueBuffer(swapchain.window.get(),
613 img.buffer.get(), fence);
614 if (err != 0) {
615 // TODO(jessehall): What now? We should probably cancel the buffer,
616 // I guess?
617 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
618 if (final_result == VK_SUCCESS)
619 final_result = VK_ERROR_UNKNOWN;
620 continue;
621 }
622
623 if (img.dequeue_fence != -1) {
624 close(img.dequeue_fence);
625 img.dequeue_fence = -1;
626 }
627 img.dequeued = false;
628 }
629
630 return final_result;
631}
Jesse Hallb1352bc2015-09-04 16:12:33 -0700632
633} // namespace vulkan