The open source OpenXR runtime
at mr/scanout-values 251 lines 6.4 kB view raw
1// Copyright 2019-2020, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Android window code. 6 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 7 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 8 * @author Jakob Bornecrantz <jakob@collabora.com> 9 * @ingroup comp_main 10 */ 11 12#include "xrt/xrt_compiler.h" 13 14#include "util/u_misc.h" 15 16#include "android/android_globals.h" 17#include "android/android_custom_surface.h" 18 19#include "main/comp_window.h" 20 21#include <android/native_window.h> 22 23#include <poll.h> 24#include <errno.h> 25#include <stdlib.h> 26#include <string.h> 27#include <linux/input.h> 28 29#define WINDOW_TITLE "Monado" 30 31/* 32 * 33 * Private structs. 34 * 35 */ 36 37/*! 38 * An Android window. 39 * 40 * @implements comp_target_swapchain 41 */ 42struct comp_window_android 43{ 44 struct comp_target_swapchain base; 45 46 struct android_custom_surface *custom_surface; 47}; 48 49 50/* 51 * 52 * Functions. 53 * 54 */ 55 56static inline struct vk_bundle * 57get_vk(struct comp_window_android *cwa) 58{ 59 return &cwa->base.base.c->base.vk; 60} 61 62static bool 63comp_window_android_init(struct comp_target *ct) 64{ 65 (void)ct; 66 67 return true; 68} 69 70static void 71comp_window_android_destroy(struct comp_target *ct) 72{ 73 struct comp_window_android *cwa = (struct comp_window_android *)ct; 74 75 comp_target_swapchain_cleanup(&cwa->base); 76 77 android_custom_surface_destroy(&cwa->custom_surface); 78 79 free(ct); 80} 81 82static void 83comp_window_android_update_window_title(struct comp_target *ct, const char *title) 84{ 85 (void)ct; 86} 87 88static struct ANativeWindow * 89_create_android_window(struct comp_window_android *cwa) 90{ 91 // 0 means default display 92 cwa->custom_surface = android_custom_surface_async_start( // 93 android_globals_get_vm(), // vm 94 android_globals_get_context(), // context 95 0, // display_id 96 WINDOW_TITLE, // title in dumpsys 97 0); // preferred_display_mode_id 98 99 if (cwa->custom_surface == NULL) { 100 COMP_ERROR(cwa->base.base.c, 101 "comp_window_android_create_surface: could not " 102 "start asynchronous attachment of our custom surface"); 103 return NULL; 104 } 105 106 return android_custom_surface_wait_get_surface(cwa->custom_surface, 2000); 107} 108 109static VkResult 110comp_window_android_create_surface(struct comp_window_android *cwa, 111 struct ANativeWindow *window, 112 VkSurfaceKHR *out_surface) 113{ 114 struct vk_bundle *vk = get_vk(cwa); 115 VkResult ret; 116 117 VkAndroidSurfaceCreateInfoKHR surface_info = { 118 .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, 119 .flags = 0, 120 .window = window, 121 }; 122 123 VkSurfaceKHR surface = VK_NULL_HANDLE; 124 ret = vk->vkCreateAndroidSurfaceKHR( // 125 vk->instance, // 126 &surface_info, // 127 NULL, // 128 &surface); // 129 if (ret != VK_SUCCESS) { 130 COMP_ERROR(cwa->base.base.c, "vkCreateAndroidSurfaceKHR: %s", vk_result_string(ret)); 131 return ret; 132 } 133 134 VK_NAME_SURFACE(vk, surface, "comp_window_android surface"); 135 *out_surface = surface; 136 137 return VK_SUCCESS; 138} 139 140static bool 141comp_window_android_init_swapchain(struct comp_target *ct, uint32_t width, uint32_t height) 142{ 143 struct comp_window_android *cwa = (struct comp_window_android *)ct; 144 VkResult ret; 145 146 struct ANativeWindow *window = NULL; 147 148 if (android_globals_get_activity() != NULL) { 149 /* In process: Creating surface from activity */ 150 window = _create_android_window(cwa); 151 } else if (android_custom_surface_can_draw_overlays(android_globals_get_vm(), android_globals_get_context())) { 152 /* Out of process: Create surface */ 153 window = _create_android_window(cwa); 154 } else { 155 /* Out of process: Getting cached surface. 156 * This loop polls for a surface created by Client.java in blockingConnect. 157 * TODO: change java code to callback native code to notify Session lifecycle progress, instead 158 * of polling here 159 */ 160 for (int i = 0; i < 100; i++) { 161 window = (struct ANativeWindow *)android_globals_get_window(); 162 if (window) 163 break; 164 os_nanosleep(20 * U_TIME_1MS_IN_NS); 165 } 166 } 167 168 169 if (window == NULL) { 170 COMP_ERROR(cwa->base.base.c, "could not get ANativeWindow"); 171 return false; 172 } 173 android_globals_store_window((struct _ANativeWindow *)window); 174 175 ret = comp_window_android_create_surface(cwa, window, &cwa->base.surface.handle); 176 if (ret != VK_SUCCESS) { 177 COMP_ERROR(ct->c, "Failed to create surface '%s'!", vk_result_string(ret)); 178 return false; 179 } 180 181 return true; 182} 183 184static void 185comp_window_android_flush(struct comp_target *ct) 186{ 187 (void)ct; 188} 189 190struct comp_target * 191comp_window_android_create(struct comp_compositor *c) 192{ 193 struct comp_window_android *w = U_TYPED_CALLOC(struct comp_window_android); 194 195 // The display timing code hasn't been tested on Android and may be broken. 196 comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); 197 198 w->base.base.name = "Android"; 199 w->base.base.destroy = comp_window_android_destroy; 200 w->base.base.flush = comp_window_android_flush; 201 w->base.base.init_pre_vulkan = comp_window_android_init; 202 w->base.base.init_post_vulkan = comp_window_android_init_swapchain; 203 w->base.base.set_title = comp_window_android_update_window_title; 204 w->base.base.c = c; 205 206 return &w->base.base; 207} 208 209 210/* 211 * 212 * Factory 213 * 214 */ 215 216static const char *instance_extensions[] = { 217 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, 218}; 219 220static bool 221detect(const struct comp_target_factory *ctf, struct comp_compositor *c) 222{ 223 return false; 224} 225 226static bool 227create_target(const struct comp_target_factory *ctf, struct comp_compositor *c, struct comp_target **out_ct) 228{ 229 struct comp_target *ct = comp_window_android_create(c); 230 if (ct == NULL) { 231 return false; 232 } 233 234 *out_ct = ct; 235 236 return true; 237} 238 239const struct comp_target_factory comp_target_factory_android = { 240 .name = "Android", 241 .identifier = "android", 242 .requires_vulkan_for_create = false, 243 .is_deferred = true, 244 .required_instance_version = 0, 245 .required_instance_extensions = instance_extensions, 246 .required_instance_extension_count = ARRAY_SIZE(instance_extensions), 247 .optional_device_extensions = NULL, 248 .optional_device_extension_count = 0, 249 .detect = detect, 250 .create_target = create_target, 251};