1 /* 2 * Copyright 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include "anv_private.h" 25 #include "wsi_common.h" 26 #include "vk_format_info.h" 27 28 static const struct wsi_callbacks wsi_cbs = { 29 .get_phys_device_format_properties = anv_GetPhysicalDeviceFormatProperties, 30 }; 31 32 VkResult 33 anv_init_wsi(struct anv_physical_device *physical_device) 34 { 35 VkResult result; 36 37 memset(physical_device->wsi_device.wsi, 0, sizeof(physical_device->wsi_device.wsi)); 38 39 #ifdef VK_USE_PLATFORM_XCB_KHR 40 result = wsi_x11_init_wsi(&physical_device->wsi_device, &physical_device->instance->alloc); 41 if (result != VK_SUCCESS) 42 return result; 43 #endif 44 45 #ifdef VK_USE_PLATFORM_WAYLAND_KHR 46 result = wsi_wl_init_wsi(&physical_device->wsi_device, &physical_device->instance->alloc, 47 anv_physical_device_to_handle(physical_device), 48 &wsi_cbs); 49 if (result != VK_SUCCESS) { 50 #ifdef VK_USE_PLATFORM_XCB_KHR 51 wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc); 52 #endif 53 return result; 54 } 55 #endif 56 57 return VK_SUCCESS; 58 } 59 60 void 61 anv_finish_wsi(struct anv_physical_device *physical_device) 62 { 63 #ifdef VK_USE_PLATFORM_WAYLAND_KHR 64 wsi_wl_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc); 65 #endif 66 #ifdef VK_USE_PLATFORM_XCB_KHR 67 wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc); 68 #endif 69 } 70 71 void anv_DestroySurfaceKHR( 72 VkInstance _instance, 73 VkSurfaceKHR _surface, 74 const VkAllocationCallbacks* pAllocator) 75 { 76 ANV_FROM_HANDLE(anv_instance, instance, _instance); 77 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); 78 79 if (!surface) 80 return; 81 82 vk_free2(&instance->alloc, pAllocator, surface); 83 } 84 85 VkResult anv_GetPhysicalDeviceSurfaceSupportKHR( 86 VkPhysicalDevice physicalDevice, 87 uint32_t queueFamilyIndex, 88 VkSurfaceKHR _surface, 89 VkBool32* pSupported) 90 { 91 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 92 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); 93 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform]; 94 95 return iface->get_support(surface, &device->wsi_device, 96 &device->instance->alloc, 97 queueFamilyIndex, pSupported); 98 } 99 100 VkResult anv_GetPhysicalDeviceSurfaceCapabilitiesKHR( 101 VkPhysicalDevice physicalDevice, 102 VkSurfaceKHR _surface, 103 VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) 104 { 105 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 106 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); 107 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform]; 108 109 return iface->get_capabilities(surface, pSurfaceCapabilities); 110 } 111 112 VkResult anv_GetPhysicalDeviceSurfaceFormatsKHR( 113 VkPhysicalDevice physicalDevice, 114 VkSurfaceKHR _surface, 115 uint32_t* pSurfaceFormatCount, 116 VkSurfaceFormatKHR* pSurfaceFormats) 117 { 118 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 119 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); 120 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform]; 121 122 return iface->get_formats(surface, &device->wsi_device, pSurfaceFormatCount, 123 pSurfaceFormats); 124 } 125 126 VkResult anv_GetPhysicalDeviceSurfacePresentModesKHR( 127 VkPhysicalDevice physicalDevice, 128 VkSurfaceKHR _surface, 129 uint32_t* pPresentModeCount, 130 VkPresentModeKHR* pPresentModes) 131 { 132 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 133 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); 134 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform]; 135 136 return iface->get_present_modes(surface, pPresentModeCount, 137 pPresentModes); 138 } 139 140 141 static VkResult 142 x11_anv_wsi_image_create(VkDevice device_h, 143 const VkSwapchainCreateInfoKHR *pCreateInfo, 144 const VkAllocationCallbacks* pAllocator, 145 VkImage *image_p, 146 VkDeviceMemory *memory_p, 147 uint32_t *size, 148 uint32_t *offset, 149 uint32_t *row_pitch, int *fd_p) 150 { 151 struct anv_device *device = anv_device_from_handle(device_h); 152 VkImage image_h; 153 struct anv_image *image; 154 155 VkResult result; 156 result = anv_image_create(anv_device_to_handle(device), 157 &(struct anv_image_create_info) { 158 .isl_tiling_flags = ISL_TILING_X_BIT, 159 .stride = 0, 160 .vk_info = 161 &(VkImageCreateInfo) { 162 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 163 .imageType = VK_IMAGE_TYPE_2D, 164 .format = pCreateInfo->imageFormat, 165 .extent = { 166 .width = pCreateInfo->imageExtent.width, 167 .height = pCreateInfo->imageExtent.height, 168 .depth = 1 169 }, 170 .mipLevels = 1, 171 .arrayLayers = 1, 172 .samples = 1, 173 /* FIXME: Need a way to use X tiling to allow scanout */ 174 .tiling = VK_IMAGE_TILING_OPTIMAL, 175 .usage = (pCreateInfo->imageUsage | 176 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), 177 .flags = 0, 178 }}, 179 NULL, 180 &image_h); 181 if (result != VK_SUCCESS) 182 return result; 183 184 image = anv_image_from_handle(image_h); 185 assert(vk_format_is_color(image->vk_format)); 186 187 VkDeviceMemory memory_h; 188 struct anv_device_memory *memory; 189 result = anv_AllocateMemory(anv_device_to_handle(device), 190 &(VkMemoryAllocateInfo) { 191 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 192 .allocationSize = image->size, 193 .memoryTypeIndex = 0, 194 }, 195 NULL /* XXX: pAllocator */, 196 &memory_h); 197 if (result != VK_SUCCESS) 198 goto fail_create_image; 199 200 memory = anv_device_memory_from_handle(memory_h); 201 memory->bo.is_winsys_bo = true; 202 203 anv_BindImageMemory(device_h, image_h, memory_h, 0); 204 205 struct anv_surface *surface = &image->color_surface; 206 assert(surface->isl.tiling == ISL_TILING_X); 207 208 *row_pitch = surface->isl.row_pitch; 209 int ret = anv_gem_set_tiling(device, memory->bo.gem_handle, 210 surface->isl.row_pitch, I915_TILING_X); 211 if (ret) { 212 /* FINISHME: Choose a better error. */ 213 result = vk_errorf(VK_ERROR_OUT_OF_DEVICE_MEMORY, 214 "set_tiling failed: %m"); 215 goto fail_alloc_memory; 216 } 217 218 int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle); 219 if (fd == -1) { 220 /* FINISHME: Choose a better error. */ 221 result = vk_errorf(VK_ERROR_OUT_OF_DEVICE_MEMORY, 222 "handle_to_fd failed: %m"); 223 goto fail_alloc_memory; 224 } 225 226 *image_p = image_h; 227 *memory_p = memory_h; 228 *fd_p = fd; 229 *size = image->size; 230 *offset = image->offset; 231 return VK_SUCCESS; 232 fail_alloc_memory: 233 anv_FreeMemory(device_h, memory_h, pAllocator); 234 235 fail_create_image: 236 anv_DestroyImage(device_h, image_h, pAllocator); 237 return result; 238 } 239 240 static void 241 x11_anv_wsi_image_free(VkDevice device, 242 const VkAllocationCallbacks* pAllocator, 243 VkImage image_h, 244 VkDeviceMemory memory_h) 245 { 246 anv_DestroyImage(device, image_h, pAllocator); 247 248 anv_FreeMemory(device, memory_h, pAllocator); 249 } 250 251 static const struct wsi_image_fns anv_wsi_image_fns = { 252 .create_wsi_image = x11_anv_wsi_image_create, 253 .free_wsi_image = x11_anv_wsi_image_free, 254 }; 255 256 VkResult anv_CreateSwapchainKHR( 257 VkDevice _device, 258 const VkSwapchainCreateInfoKHR* pCreateInfo, 259 const VkAllocationCallbacks* pAllocator, 260 VkSwapchainKHR* pSwapchain) 261 { 262 ANV_FROM_HANDLE(anv_device, device, _device); 263 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); 264 struct wsi_interface *iface = 265 device->instance->physicalDevice.wsi_device.wsi[surface->platform]; 266 struct wsi_swapchain *swapchain; 267 const VkAllocationCallbacks *alloc; 268 269 if (pAllocator) 270 alloc = pAllocator; 271 else 272 alloc = &device->alloc; 273 VkResult result = iface->create_swapchain(surface, _device, 274 &device->instance->physicalDevice.wsi_device, 275 pCreateInfo, 276 alloc, &anv_wsi_image_fns, 277 &swapchain); 278 if (result != VK_SUCCESS) 279 return result; 280 281 swapchain->alloc = *alloc; 282 283 for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++) 284 swapchain->fences[i] = VK_NULL_HANDLE; 285 286 *pSwapchain = wsi_swapchain_to_handle(swapchain); 287 288 return VK_SUCCESS; 289 } 290 291 void anv_DestroySwapchainKHR( 292 VkDevice _device, 293 VkSwapchainKHR _swapchain, 294 const VkAllocationCallbacks* pAllocator) 295 { 296 ANV_FROM_HANDLE(anv_device, device, _device); 297 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); 298 const VkAllocationCallbacks *alloc; 299 300 if (!swapchain) 301 return; 302 303 if (pAllocator) 304 alloc = pAllocator; 305 else 306 alloc = &device->alloc; 307 for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++) { 308 if (swapchain->fences[i] != VK_NULL_HANDLE) 309 anv_DestroyFence(_device, swapchain->fences[i], pAllocator); 310 } 311 312 swapchain->destroy(swapchain, alloc); 313 } 314 315 VkResult anv_GetSwapchainImagesKHR( 316 VkDevice device, 317 VkSwapchainKHR _swapchain, 318 uint32_t* pSwapchainImageCount, 319 VkImage* pSwapchainImages) 320 { 321 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); 322 323 return swapchain->get_images(swapchain, pSwapchainImageCount, 324 pSwapchainImages); 325 } 326 327 VkResult anv_AcquireNextImageKHR( 328 VkDevice device, 329 VkSwapchainKHR _swapchain, 330 uint64_t timeout, 331 VkSemaphore semaphore, 332 VkFence _fence, 333 uint32_t* pImageIndex) 334 { 335 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); 336 ANV_FROM_HANDLE(anv_fence, fence, _fence); 337 338 VkResult result = swapchain->acquire_next_image(swapchain, timeout, 339 semaphore, pImageIndex); 340 341 /* Thanks to implicit sync, the image is ready immediately. */ 342 if (fence) 343 fence->state = ANV_FENCE_STATE_SIGNALED; 344 345 return result; 346 } 347 348 VkResult anv_QueuePresentKHR( 349 VkQueue _queue, 350 const VkPresentInfoKHR* pPresentInfo) 351 { 352 ANV_FROM_HANDLE(anv_queue, queue, _queue); 353 VkResult result = VK_SUCCESS; 354 355 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { 356 ANV_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); 357 VkResult item_result; 358 359 assert(anv_device_from_handle(swapchain->device) == queue->device); 360 361 if (swapchain->fences[0] == VK_NULL_HANDLE) { 362 item_result = anv_CreateFence(anv_device_to_handle(queue->device), 363 &(VkFenceCreateInfo) { 364 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 365 .flags = 0, 366 }, &swapchain->alloc, &swapchain->fences[0]); 367 if (pPresentInfo->pResults != NULL) 368 pPresentInfo->pResults[i] = item_result; 369 result = result == VK_SUCCESS ? item_result : result; 370 if (item_result != VK_SUCCESS) 371 continue; 372 } else { 373 anv_ResetFences(anv_device_to_handle(queue->device), 374 1, &swapchain->fences[0]); 375 } 376 377 anv_QueueSubmit(_queue, 0, NULL, swapchain->fences[0]); 378 379 item_result = swapchain->queue_present(swapchain, 380 pPresentInfo->pImageIndices[i]); 381 /* TODO: What if one of them returns OUT_OF_DATE? */ 382 if (pPresentInfo->pResults != NULL) 383 pPresentInfo->pResults[i] = item_result; 384 result = result == VK_SUCCESS ? item_result : result; 385 if (item_result != VK_SUCCESS) 386 continue; 387 388 VkFence last = swapchain->fences[2]; 389 swapchain->fences[2] = swapchain->fences[1]; 390 swapchain->fences[1] = swapchain->fences[0]; 391 swapchain->fences[0] = last; 392 393 if (last != VK_NULL_HANDLE) { 394 anv_WaitForFences(anv_device_to_handle(queue->device), 395 1, &last, true, 1); 396 } 397 } 398 399 return VK_SUCCESS; 400 } 401