ntdll: Connect syscall frames across user callbacks on x86-64.
[wine.git] / dlls / wineandroid.drv / device.c
blobb8f6f97eec79b2e8e726ae0373df1ebf2a5bebfd
1 /*
2 * Android pseudo-device handling
4 * Copyright 2014-2017 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <sys/ioctl.h>
32 #include <unistd.h>
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winternl.h"
39 #include "winioctl.h"
40 #include "ddk/wdm.h"
41 #include "android.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(android);
47 #ifndef SYNC_IOC_WAIT
48 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
49 #endif
51 static HANDLE thread;
52 static JNIEnv *jni_env;
53 static HWND capture_window;
55 #define ANDROIDCONTROLTYPE ((ULONG)'A')
56 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
58 enum android_ioctl
60 IOCTL_CREATE_WINDOW,
61 IOCTL_DESTROY_WINDOW,
62 IOCTL_WINDOW_POS_CHANGED,
63 IOCTL_SET_WINDOW_PARENT,
64 IOCTL_DEQUEUE_BUFFER,
65 IOCTL_QUEUE_BUFFER,
66 IOCTL_CANCEL_BUFFER,
67 IOCTL_QUERY,
68 IOCTL_PERFORM,
69 IOCTL_SET_SWAP_INT,
70 IOCTL_SET_CAPTURE,
71 IOCTL_SET_CURSOR,
72 NB_IOCTLS
75 #define NB_CACHED_BUFFERS 4
77 struct native_buffer_wrapper;
79 /* buffer for storing a variable-size native handle inside an ioctl structure */
80 union native_handle_buffer
82 native_handle_t handle;
83 int space[256];
86 /* data about the native window in the context of the Java process */
87 struct native_win_data
89 struct ANativeWindow *parent;
90 struct ANativeWindowBuffer *buffers[NB_CACHED_BUFFERS];
91 void *mappings[NB_CACHED_BUFFERS];
92 HWND hwnd;
93 BOOL opengl;
94 int generation;
95 int api;
96 int buffer_format;
97 int swap_interval;
98 int buffer_lru[NB_CACHED_BUFFERS];
101 /* wrapper for a native window in the context of the client (non-Java) process */
102 struct native_win_wrapper
104 struct ANativeWindow win;
105 struct native_buffer_wrapper *buffers[NB_CACHED_BUFFERS];
106 struct ANativeWindowBuffer *locked_buffer;
107 HWND hwnd;
108 BOOL opengl;
109 LONG ref;
112 /* wrapper for a native buffer in the context of the client (non-Java) process */
113 struct native_buffer_wrapper
115 struct ANativeWindowBuffer buffer;
116 LONG ref;
117 HWND hwnd;
118 void *bits;
119 int buffer_id;
120 int generation;
121 union native_handle_buffer native_handle;
124 struct ioctl_header
126 int hwnd;
127 BOOL opengl;
130 struct ioctl_android_create_window
132 struct ioctl_header hdr;
133 int parent;
134 float scale;
137 struct ioctl_android_destroy_window
139 struct ioctl_header hdr;
142 struct ioctl_android_window_pos_changed
144 struct ioctl_header hdr;
145 RECT window_rect;
146 RECT client_rect;
147 RECT visible_rect;
148 int style;
149 int flags;
150 int after;
151 int owner;
154 struct ioctl_android_dequeueBuffer
156 struct ioctl_header hdr;
157 int win32;
158 int width;
159 int height;
160 int stride;
161 int format;
162 int usage;
163 int buffer_id;
164 int generation;
165 union native_handle_buffer native_handle;
168 struct ioctl_android_queueBuffer
170 struct ioctl_header hdr;
171 int buffer_id;
172 int generation;
175 struct ioctl_android_cancelBuffer
177 struct ioctl_header hdr;
178 int buffer_id;
179 int generation;
182 struct ioctl_android_query
184 struct ioctl_header hdr;
185 int what;
186 int value;
189 struct ioctl_android_perform
191 struct ioctl_header hdr;
192 int operation;
193 int args[4];
196 struct ioctl_android_set_swap_interval
198 struct ioctl_header hdr;
199 int interval;
202 struct ioctl_android_set_window_parent
204 struct ioctl_header hdr;
205 int parent;
206 float scale;
209 struct ioctl_android_set_capture
211 struct ioctl_header hdr;
214 struct ioctl_android_set_cursor
216 struct ioctl_header hdr;
217 int id;
218 int width;
219 int height;
220 int hotspotx;
221 int hotspoty;
222 int bits[1];
225 static struct gralloc_module_t *gralloc_module;
226 static struct gralloc1_device *gralloc1_device;
227 static BOOL gralloc1_caps[GRALLOC1_LAST_CAPABILITY + 1];
229 static gralloc1_error_t (*gralloc1_retain)( gralloc1_device_t *device, buffer_handle_t buffer );
230 static gralloc1_error_t (*gralloc1_release)( gralloc1_device_t *device, buffer_handle_t buffer );
231 static gralloc1_error_t (*gralloc1_lock)( gralloc1_device_t *device, buffer_handle_t buffer,
232 uint64_t producerUsage, uint64_t consumerUsage,
233 const gralloc1_rect_t *accessRegion, void **outData,
234 int32_t acquireFence );
235 static gralloc1_error_t (*gralloc1_unlock)( gralloc1_device_t *device, buffer_handle_t buffer,
236 int32_t *outReleaseFence );
238 static inline BOOL is_in_desktop_process(void)
240 return thread != NULL;
243 static inline DWORD current_client_id(void)
245 DWORD client_id = NtUserGetThreadInfo()->driver_data;
246 return client_id ? client_id : GetCurrentProcessId();
249 static inline BOOL is_client_in_process(void)
251 return current_client_id() == GetCurrentProcessId();
254 #ifdef __i386__ /* the Java VM uses %fs/%gs for its own purposes, so we need to wrap the calls */
256 static WORD orig_fs, java_fs;
257 static inline void wrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (java_fs) ); }
258 static inline void unwrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); }
259 static inline void init_java_thread( JavaVM *java_vm )
261 java_fs = *p_java_gdt_sel;
262 __asm__( "mov %%fs,%0" : "=r" (orig_fs) );
263 __asm__( "mov %0,%%fs" :: "r" (java_fs) );
264 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
265 if (!*p_java_gdt_sel) __asm__( "mov %%fs,%0" : "=r" (java_fs) );
266 __asm__( "mov %0,%%fs" :: "r" (orig_fs) );
269 #elif defined(__x86_64__)
271 #include <asm/prctl.h>
272 #include <asm/unistd.h>
273 static void *orig_teb, *java_teb;
274 static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
275 static inline void wrap_java_call(void) { arch_prctl( ARCH_SET_GS, java_teb ); }
276 static inline void unwrap_java_call(void) { arch_prctl( ARCH_SET_GS, orig_teb ); }
277 static inline void init_java_thread( JavaVM *java_vm )
279 arch_prctl( ARCH_GET_GS, &orig_teb );
280 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
281 arch_prctl( ARCH_GET_GS, &java_teb );
282 arch_prctl( ARCH_SET_GS, orig_teb );
285 #else
286 static inline void wrap_java_call(void) { }
287 static inline void unwrap_java_call(void) { }
288 static inline void init_java_thread( JavaVM *java_vm ) { (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); }
289 #endif /* __i386__ */
291 static struct native_win_data *data_map[65536];
293 static unsigned int data_map_idx( HWND hwnd, BOOL opengl )
295 /* window handles are always even, so use low-order bit for opengl flag */
296 return LOWORD(hwnd) + !!opengl;
299 static struct native_win_data *get_native_win_data( HWND hwnd, BOOL opengl )
301 struct native_win_data *data = data_map[data_map_idx( hwnd, opengl )];
303 if (data && data->hwnd == hwnd && !data->opengl == !opengl) return data;
304 WARN( "unknown win %p opengl %u\n", hwnd, opengl );
305 return NULL;
308 static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr )
310 return get_native_win_data( LongToHandle(hdr->hwnd), hdr->opengl );
313 static int get_ioctl_win_parent( HWND parent )
315 if (parent != NtUserGetDesktopWindow() && !NtUserGetAncestor( parent, GA_PARENT ))
316 return HandleToLong( HWND_MESSAGE );
317 return HandleToLong( parent );
320 static void wait_fence_and_close( int fence )
322 __s32 timeout = 1000; /* FIXME: should be -1 for infinite timeout */
324 if (fence == -1) return;
325 ioctl( fence, SYNC_IOC_WAIT, &timeout );
326 close( fence );
329 static int duplicate_fd( HANDLE client, int fd )
331 HANDLE handle, ret = 0;
333 if (!wine_server_fd_to_handle( dup(fd), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
334 NtDuplicateObject( GetCurrentProcess(), handle, client, &ret,
335 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
337 if (!ret) return -1;
338 return HandleToLong( ret );
341 static int map_native_handle( union native_handle_buffer *dest, const native_handle_t *src,
342 HANDLE mapping, HANDLE client )
344 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
345 int i;
347 if (mapping) /* only duplicate the mapping handle */
349 HANDLE ret = 0;
350 if (!NtDuplicateObject( GetCurrentProcess(), mapping, client, &ret,
351 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ))
352 return -ENOSPC;
353 dest->handle.numFds = 0;
354 dest->handle.numInts = 1;
355 dest->handle.data[0] = HandleToLong( ret );
356 return 0;
358 if (is_client_in_process()) /* transfer the actual handle pointer */
360 dest->handle.numFds = 0;
361 dest->handle.numInts = sizeof(src) / sizeof(int);
362 memcpy( dest->handle.data, &src, sizeof(src) );
363 return 0;
365 if (size > sizeof(*dest)) return -ENOSPC;
366 memcpy( dest, src, size );
367 /* transfer file descriptors to the client process */
368 for (i = 0; i < dest->handle.numFds; i++)
369 dest->handle.data[i] = duplicate_fd( client, src->data[i] );
370 return 0;
373 static native_handle_t *unmap_native_handle( const native_handle_t *src )
375 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
376 native_handle_t *dest;
377 int i;
379 if (!is_in_desktop_process())
381 dest = malloc( size );
382 memcpy( dest, src, size );
383 /* fetch file descriptors passed from the server process */
384 for (i = 0; i < dest->numFds; i++)
385 wine_server_handle_to_fd( LongToHandle(src->data[i]), GENERIC_READ | SYNCHRONIZE,
386 &dest->data[i], NULL );
388 else memcpy( &dest, src->data, sizeof(dest) );
389 return dest;
392 static void close_native_handle( native_handle_t *handle )
394 int i;
396 for (i = 0; i < handle->numFds; i++) close( handle->data[i] );
397 free( handle );
400 /* insert a buffer index at the head of the LRU list */
401 static void insert_buffer_lru( struct native_win_data *win, int index )
403 unsigned int i;
405 for (i = 0; i < NB_CACHED_BUFFERS; i++)
407 if (win->buffer_lru[i] == index) break;
408 if (win->buffer_lru[i] == -1) break;
411 assert( i < NB_CACHED_BUFFERS );
412 memmove( win->buffer_lru + 1, win->buffer_lru, i * sizeof(win->buffer_lru[0]) );
413 win->buffer_lru[0] = index;
416 static int register_buffer( struct native_win_data *win, struct ANativeWindowBuffer *buffer,
417 HANDLE *mapping, int *is_new )
419 unsigned int i;
421 *is_new = 0;
422 for (i = 0; i < NB_CACHED_BUFFERS; i++)
424 if (win->buffers[i] == buffer) goto done;
425 if (!win->buffers[i]) break;
428 if (i == NB_CACHED_BUFFERS)
430 /* reuse the least recently used buffer */
431 i = win->buffer_lru[NB_CACHED_BUFFERS - 1];
432 assert( i < NB_CACHED_BUFFERS );
434 TRACE( "%p %p evicting buffer %p id %d from cache\n",
435 win->hwnd, win->parent, win->buffers[i], i );
436 win->buffers[i]->common.decRef( &win->buffers[i]->common );
437 if (win->mappings[i]) NtUnmapViewOfSection( GetCurrentProcess(), win->mappings[i] );
440 win->buffers[i] = buffer;
441 win->mappings[i] = NULL;
443 if (mapping)
445 OBJECT_ATTRIBUTES attr;
446 LARGE_INTEGER size;
447 SIZE_T count = 0;
448 size.QuadPart = buffer->stride * buffer->height * 4;
449 InitializeObjectAttributes( &attr, NULL, OBJ_OPENIF, NULL, NULL );
450 NtCreateSection( mapping,
451 STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
452 &attr, &size, PAGE_READWRITE, 0, INVALID_HANDLE_VALUE );
453 NtMapViewOfSection( *mapping, GetCurrentProcess(), &win->mappings[i], 0, 0,
454 NULL, &count, ViewShare, 0, PAGE_READONLY );
456 buffer->common.incRef( &buffer->common );
457 *is_new = 1;
458 TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i );
460 done:
461 insert_buffer_lru( win, i );
462 return i;
465 static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data *win, int id )
467 if (id < 0 || id >= NB_CACHED_BUFFERS || !win->buffers[id])
469 ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent );
470 return NULL;
472 return win->buffers[id];
475 static void release_native_window( struct native_win_data *data )
477 unsigned int i;
479 if (data->parent) pANativeWindow_release( data->parent );
480 for (i = 0; i < NB_CACHED_BUFFERS; i++)
482 if (data->buffers[i]) data->buffers[i]->common.decRef( &data->buffers[i]->common );
483 if (data->mappings[i]) NtUnmapViewOfSection( GetCurrentProcess(), data->mappings[i] );
484 data->buffer_lru[i] = -1;
486 memset( data->buffers, 0, sizeof(data->buffers) );
487 memset( data->mappings, 0, sizeof(data->mappings) );
490 static void free_native_win_data( struct native_win_data *data )
492 unsigned int idx = data_map_idx( data->hwnd, data->opengl );
494 InterlockedCompareExchangePointer( (void **)&capture_window, 0, data->hwnd );
495 release_native_window( data );
496 free( data );
497 data_map[idx] = NULL;
500 static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl )
502 unsigned int i, idx = data_map_idx( hwnd, opengl );
503 struct native_win_data *data = data_map[idx];
505 if (data)
507 WARN( "data for %p not freed correctly\n", data->hwnd );
508 free_native_win_data( data );
510 if (!(data = calloc( 1, sizeof(*data) ))) return NULL;
511 data->hwnd = hwnd;
512 data->opengl = opengl;
513 if (!opengl) data->api = NATIVE_WINDOW_API_CPU;
514 data->buffer_format = PF_BGRA_8888;
515 data_map[idx] = data;
516 for (i = 0; i < NB_CACHED_BUFFERS; i++) data->buffer_lru[i] = -1;
517 return data;
520 NTSTATUS android_register_window( void *arg )
522 struct register_window_params *params = arg;
523 HWND hwnd = (HWND)params->arg1;
524 struct ANativeWindow *win = (struct ANativeWindow *)params->arg2;
525 BOOL opengl = params->arg3;
526 struct native_win_data *data = get_native_win_data( hwnd, opengl );
528 if (!win) return 0; /* do nothing and hold on to the window until we get a new surface */
530 if (!data || data->parent == win)
532 pANativeWindow_release( win );
533 if (data) NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
534 TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win );
535 return 0;
538 release_native_window( data );
539 data->parent = win;
540 data->generation++;
541 wrap_java_call();
542 if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api );
543 win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format );
544 win->setSwapInterval( win, data->swap_interval );
545 unwrap_java_call();
546 NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
547 TRACE( "%p -> %p win %p\n", hwnd, data, win );
548 return 0;
551 /* register a native window received from the Java side for use in ioctls */
552 void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl )
554 NtQueueApcThread( thread, register_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl );
557 void init_gralloc( const struct hw_module_t *module )
559 struct hw_device_t *device;
560 int ret;
562 TRACE( "got module %p ver %u.%u id %s name %s author %s\n",
563 module, module->module_api_version >> 8, module->module_api_version & 0xff,
564 debugstr_a(module->id), debugstr_a(module->name), debugstr_a(module->author) );
566 switch (module->module_api_version >> 8)
568 case 0:
569 gralloc_module = (struct gralloc_module_t *)module;
570 break;
571 case 1:
572 if (!(ret = module->methods->open( module, GRALLOC_HARDWARE_MODULE_ID, &device )))
574 int32_t caps[64];
575 uint32_t i, count = ARRAY_SIZE(caps);
577 gralloc1_device = (struct gralloc1_device *)device;
578 gralloc1_retain = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RETAIN );
579 gralloc1_release = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RELEASE );
580 gralloc1_lock = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_LOCK );
581 gralloc1_unlock = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_UNLOCK );
582 TRACE( "got device version %u funcs %p %p %p %p\n", device->version,
583 gralloc1_retain, gralloc1_release, gralloc1_lock, gralloc1_unlock );
585 gralloc1_device->getCapabilities( gralloc1_device, &count, caps );
586 if (count == ARRAY_SIZE(caps)) ERR( "too many gralloc capabilities\n" );
587 for (i = 0; i < count; i++)
588 if (caps[i] < ARRAY_SIZE(gralloc1_caps)) gralloc1_caps[caps[i]] = TRUE;
590 else ERR( "failed to open gralloc err %d\n", ret );
591 break;
592 default:
593 ERR( "unknown gralloc module version %u\n", module->module_api_version >> 8 );
594 break;
598 static int gralloc_grab_buffer( struct ANativeWindowBuffer *buffer )
600 if (gralloc1_device)
601 return gralloc1_retain( gralloc1_device, buffer->handle );
602 if (gralloc_module)
603 return gralloc_module->registerBuffer( gralloc_module, buffer->handle );
604 return -ENODEV;
607 static void gralloc_release_buffer( struct ANativeWindowBuffer *buffer )
609 if (gralloc1_device) gralloc1_release( gralloc1_device, buffer->handle );
610 else if (gralloc_module) gralloc_module->unregisterBuffer( gralloc_module, buffer->handle );
612 if (!gralloc1_caps[GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE])
613 close_native_handle( (native_handle_t *)buffer->handle );
616 static int gralloc_lock( struct ANativeWindowBuffer *buffer, void **bits )
618 if (gralloc1_device)
620 gralloc1_rect_t rect = { 0, 0, buffer->width, buffer->height };
621 return gralloc1_lock( gralloc1_device, buffer->handle,
622 GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN |
623 GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
624 GRALLOC1_CONSUMER_USAGE_NONE, &rect, bits, -1 );
626 if (gralloc_module)
627 return gralloc_module->lock( gralloc_module, buffer->handle,
628 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
629 0, 0, buffer->width, buffer->height, bits );
631 *bits = ((struct native_buffer_wrapper *)buffer)->bits;
632 return 0;
635 static void gralloc_unlock( struct ANativeWindowBuffer *buffer )
637 if (gralloc1_device)
639 int fence;
640 gralloc1_unlock( gralloc1_device, buffer->handle, &fence );
641 wait_fence_and_close( fence );
643 else if (gralloc_module) gralloc_module->unlock( gralloc_module, buffer->handle );
646 /* get the capture window stored in the desktop process */
647 HWND get_capture_window(void)
649 return capture_window;
652 static NTSTATUS android_error_to_status( int err )
654 switch (err)
656 case 0: return STATUS_SUCCESS;
657 case -ENOMEM: return STATUS_NO_MEMORY;
658 case -ENOSYS: return STATUS_NOT_SUPPORTED;
659 case -EINVAL: return STATUS_INVALID_PARAMETER;
660 case -ENOENT: return STATUS_INVALID_HANDLE;
661 case -EPERM: return STATUS_ACCESS_DENIED;
662 case -ENODEV: return STATUS_NO_SUCH_DEVICE;
663 case -EEXIST: return STATUS_DUPLICATE_NAME;
664 case -EPIPE: return STATUS_PIPE_DISCONNECTED;
665 case -ENODATA: return STATUS_NO_MORE_FILES;
666 case -ETIMEDOUT: return STATUS_IO_TIMEOUT;
667 case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST;
668 case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
669 default:
670 FIXME( "unmapped error %d\n", err );
671 return STATUS_UNSUCCESSFUL;
675 static int status_to_android_error( unsigned int status )
677 switch (status)
679 case STATUS_SUCCESS: return 0;
680 case STATUS_NO_MEMORY: return -ENOMEM;
681 case STATUS_NOT_SUPPORTED: return -ENOSYS;
682 case STATUS_INVALID_PARAMETER: return -EINVAL;
683 case STATUS_BUFFER_OVERFLOW: return -EINVAL;
684 case STATUS_INVALID_HANDLE: return -ENOENT;
685 case STATUS_ACCESS_DENIED: return -EPERM;
686 case STATUS_NO_SUCH_DEVICE: return -ENODEV;
687 case STATUS_DUPLICATE_NAME: return -EEXIST;
688 case STATUS_PIPE_DISCONNECTED: return -EPIPE;
689 case STATUS_NO_MORE_FILES: return -ENODATA;
690 case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
691 case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
692 case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
693 default:
694 FIXME( "unmapped status %08x\n", status );
695 return -EINVAL;
699 static jobject load_java_method( jmethodID *method, const char *name, const char *args )
701 jobject object = *p_java_object;
703 if (!*method)
705 jclass class;
707 wrap_java_call();
708 class = (*jni_env)->GetObjectClass( jni_env, object );
709 *method = (*jni_env)->GetMethodID( jni_env, class, name, args );
710 unwrap_java_call();
711 if (!*method)
713 FIXME( "method %s not found\n", name );
714 return NULL;
717 return object;
720 static void create_desktop_window( HWND hwnd )
722 static jmethodID method;
723 jobject object;
725 if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
727 wrap_java_call();
728 (*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
729 unwrap_java_call();
732 static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
734 static jmethodID method;
735 jobject object;
736 struct ioctl_android_create_window *res = data;
737 struct native_win_data *win_data;
738 DWORD pid = current_client_id();
740 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
742 if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd), res->hdr.opengl )))
743 return STATUS_NO_MEMORY;
745 TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent );
747 if (!(object = load_java_method( &method, "createWindow", "(IZIFI)V" ))) return STATUS_NOT_SUPPORTED;
749 wrap_java_call();
750 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->hdr.opengl, res->parent, res->scale, pid );
751 unwrap_java_call();
752 return STATUS_SUCCESS;
755 static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
757 static jmethodID method;
758 jobject object;
759 struct ioctl_android_destroy_window *res = data;
760 struct native_win_data *win_data;
762 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
764 win_data = get_ioctl_native_win_data( &res->hdr );
766 TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl );
768 if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
770 wrap_java_call();
771 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
772 unwrap_java_call();
773 if (win_data) free_native_win_data( win_data );
774 return STATUS_SUCCESS;
777 static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
779 static jmethodID method;
780 jobject object;
781 struct ioctl_android_window_pos_changed *res = data;
783 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
785 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
786 res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect),
787 wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner );
789 if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
790 return STATUS_NOT_SUPPORTED;
792 wrap_java_call();
793 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style,
794 res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom,
795 res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom,
796 res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom );
797 unwrap_java_call();
798 return STATUS_SUCCESS;
801 static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
803 struct ANativeWindow *parent;
804 struct ioctl_android_dequeueBuffer *res = data;
805 struct native_win_data *win_data;
806 struct ANativeWindowBuffer *buffer;
807 int fence, ret, is_new;
809 if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW;
811 if (in_size < offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
812 return STATUS_INVALID_PARAMETER;
814 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
815 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
817 *ret_size = offsetof( struct ioctl_android_dequeueBuffer, native_handle );
818 wrap_java_call();
819 ret = parent->dequeueBuffer( parent, &buffer, &fence );
820 unwrap_java_call();
821 if (!ret)
823 HANDLE mapping = 0;
825 TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
826 res->width = buffer->width;
827 res->height = buffer->height;
828 res->stride = buffer->stride;
829 res->format = buffer->format;
830 res->usage = buffer->usage;
831 res->buffer_id = register_buffer( win_data, buffer, res->win32 ? &mapping : NULL, &is_new );
832 res->generation = win_data->generation;
833 if (is_new)
835 OBJECT_ATTRIBUTES attr = { .Length = sizeof(attr) };
836 CLIENT_ID cid = { .UniqueProcess = UlongToHandle( current_client_id() ) };
837 HANDLE process;
838 NtOpenProcess( &process, PROCESS_DUP_HANDLE, &attr, &cid );
839 map_native_handle( &res->native_handle, buffer->handle, mapping, process );
840 NtClose( process );
841 *ret_size = sizeof( *res );
843 wait_fence_and_close( fence );
844 return STATUS_SUCCESS;
846 ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
847 return android_error_to_status( ret );
850 static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
852 struct ioctl_android_cancelBuffer *res = data;
853 struct ANativeWindow *parent;
854 struct ANativeWindowBuffer *buffer;
855 struct native_win_data *win_data;
856 int ret;
858 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
860 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
861 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
862 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
864 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
866 TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer );
867 wrap_java_call();
868 ret = parent->cancelBuffer( parent, buffer, -1 );
869 unwrap_java_call();
870 return android_error_to_status( ret );
873 static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
875 struct ioctl_android_queueBuffer *res = data;
876 struct ANativeWindow *parent;
877 struct ANativeWindowBuffer *buffer;
878 struct native_win_data *win_data;
879 int ret;
881 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
883 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
884 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
885 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
887 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
889 TRACE( "%08x buffer %p mapping %p\n", res->hdr.hwnd, buffer, win_data->mappings[res->buffer_id] );
890 if (win_data->mappings[res->buffer_id])
892 void *bits;
893 ret = gralloc_lock( buffer, &bits );
894 if (ret) return android_error_to_status( ret );
895 memcpy( bits, win_data->mappings[res->buffer_id], buffer->stride * buffer->height * 4 );
896 gralloc_unlock( buffer );
898 wrap_java_call();
899 ret = parent->queueBuffer( parent, buffer, -1 );
900 unwrap_java_call();
901 return android_error_to_status( ret );
904 static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
906 struct ioctl_android_query *res = data;
907 struct ANativeWindow *parent;
908 struct native_win_data *win_data;
909 int ret;
911 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
912 if (out_size < sizeof(*res)) return STATUS_BUFFER_OVERFLOW;
914 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
915 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
917 *ret_size = sizeof( *res );
918 wrap_java_call();
919 ret = parent->query( parent, res->what, &res->value );
920 unwrap_java_call();
921 return android_error_to_status( ret );
924 static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
926 struct ioctl_android_perform *res = data;
927 struct ANativeWindow *parent;
928 struct native_win_data *win_data;
929 int ret = -ENOENT;
931 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
933 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
934 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
936 switch (res->operation)
938 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
939 wrap_java_call();
940 ret = parent->perform( parent, res->operation, res->args[0] );
941 unwrap_java_call();
942 if (!ret) win_data->buffer_format = res->args[0];
943 break;
944 case NATIVE_WINDOW_API_CONNECT:
945 wrap_java_call();
946 ret = parent->perform( parent, res->operation, res->args[0] );
947 unwrap_java_call();
948 if (!ret) win_data->api = res->args[0];
949 break;
950 case NATIVE_WINDOW_API_DISCONNECT:
951 wrap_java_call();
952 ret = parent->perform( parent, res->operation, res->args[0] );
953 unwrap_java_call();
954 if (!ret) win_data->api = 0;
955 break;
956 case NATIVE_WINDOW_SET_USAGE:
957 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
958 case NATIVE_WINDOW_SET_SCALING_MODE:
959 wrap_java_call();
960 ret = parent->perform( parent, res->operation, res->args[0] );
961 unwrap_java_call();
962 break;
963 case NATIVE_WINDOW_SET_BUFFER_COUNT:
964 wrap_java_call();
965 ret = parent->perform( parent, res->operation, (size_t)res->args[0] );
966 unwrap_java_call();
967 break;
968 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
969 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
970 wrap_java_call();
971 ret = parent->perform( parent, res->operation, res->args[0], res->args[1] );
972 unwrap_java_call();
973 break;
974 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
975 wrap_java_call();
976 ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] );
977 unwrap_java_call();
978 break;
979 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
980 wrap_java_call();
981 ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) );
982 unwrap_java_call();
983 break;
984 case NATIVE_WINDOW_CONNECT:
985 case NATIVE_WINDOW_DISCONNECT:
986 case NATIVE_WINDOW_UNLOCK_AND_POST:
987 wrap_java_call();
988 ret = parent->perform( parent, res->operation );
989 unwrap_java_call();
990 break;
991 case NATIVE_WINDOW_SET_CROP:
993 android_native_rect_t rect;
994 rect.left = res->args[0];
995 rect.top = res->args[1];
996 rect.right = res->args[2];
997 rect.bottom = res->args[3];
998 wrap_java_call();
999 ret = parent->perform( parent, res->operation, &rect );
1000 unwrap_java_call();
1001 break;
1003 case NATIVE_WINDOW_LOCK:
1004 default:
1005 FIXME( "unsupported perform op %d\n", res->operation );
1006 break;
1008 return android_error_to_status( ret );
1011 static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1013 struct ioctl_android_set_swap_interval *res = data;
1014 struct ANativeWindow *parent;
1015 struct native_win_data *win_data;
1016 int ret;
1018 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1020 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
1021 win_data->swap_interval = res->interval;
1023 if (!(parent = win_data->parent)) return STATUS_SUCCESS;
1024 wrap_java_call();
1025 ret = parent->setSwapInterval( parent, res->interval );
1026 unwrap_java_call();
1027 return android_error_to_status( ret );
1030 static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1032 static jmethodID method;
1033 jobject object;
1034 struct ioctl_android_set_window_parent *res = data;
1035 struct native_win_data *win_data;
1036 DWORD pid = current_client_id();
1038 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1040 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
1042 TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
1044 if (!(object = load_java_method( &method, "setParent", "(IIFI)V" ))) return STATUS_NOT_SUPPORTED;
1046 wrap_java_call();
1047 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, res->scale, pid );
1048 unwrap_java_call();
1049 return STATUS_SUCCESS;
1052 static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1054 struct ioctl_android_set_capture *res = data;
1056 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1058 if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE;
1060 TRACE( "hwnd %08x\n", res->hdr.hwnd );
1062 InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd ));
1063 return STATUS_SUCCESS;
1066 static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1068 static jmethodID method;
1069 jobject object;
1070 int size;
1071 struct ioctl_android_set_cursor *res = data;
1073 if (in_size < offsetof( struct ioctl_android_set_cursor, bits )) return STATUS_INVALID_PARAMETER;
1075 if (res->width < 0 || res->height < 0 || res->width > 256 || res->height > 256)
1076 return STATUS_INVALID_PARAMETER;
1078 size = res->width * res->height;
1079 if (in_size != offsetof( struct ioctl_android_set_cursor, bits[size] ))
1080 return STATUS_INVALID_PARAMETER;
1082 TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size );
1084 if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" )))
1085 return STATUS_NOT_SUPPORTED;
1087 wrap_java_call();
1089 if (size)
1091 jintArray array = (*jni_env)->NewIntArray( jni_env, size );
1092 (*jni_env)->SetIntArrayRegion( jni_env, array, 0, size, (jint *)res->bits );
1093 (*jni_env)->CallVoidMethod( jni_env, object, method, 0, res->width, res->height,
1094 res->hotspotx, res->hotspoty, array );
1095 (*jni_env)->DeleteLocalRef( jni_env, array );
1097 else (*jni_env)->CallVoidMethod( jni_env, object, method, res->id, 0, 0, 0, 0, 0 );
1099 unwrap_java_call();
1101 return STATUS_SUCCESS;
1104 typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
1105 static const ioctl_func ioctl_funcs[] =
1107 createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
1108 destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
1109 windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */
1110 setWindowParent_ioctl, /* IOCTL_SET_WINDOW_PARENT */
1111 dequeueBuffer_ioctl, /* IOCTL_DEQUEUE_BUFFER */
1112 queueBuffer_ioctl, /* IOCTL_QUEUE_BUFFER */
1113 cancelBuffer_ioctl, /* IOCTL_CANCEL_BUFFER */
1114 query_ioctl, /* IOCTL_QUERY */
1115 perform_ioctl, /* IOCTL_PERFORM */
1116 setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
1117 setCapture_ioctl, /* IOCTL_SET_CAPTURE */
1118 setCursor_ioctl, /* IOCTL_SET_CURSOR */
1121 NTSTATUS android_dispatch_ioctl( void *arg )
1123 struct ioctl_params *params = arg;
1124 IRP *irp = params->irp;
1125 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
1126 DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
1128 if (code < NB_IOCTLS)
1130 struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
1131 DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
1132 ioctl_func func = ioctl_funcs[code];
1134 if (in_size >= sizeof(*header))
1136 irp->IoStatus.Information = 0;
1137 NtUserGetThreadInfo()->driver_data = params->client_id;
1138 irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
1139 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
1140 &irp->IoStatus.Information );
1141 NtUserGetThreadInfo()->driver_data = 0;
1143 else irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1145 else
1147 FIXME( "ioctl %x not supported\n", (int)irpsp->Parameters.DeviceIoControl.IoControlCode );
1148 irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1150 return STATUS_SUCCESS;
1153 NTSTATUS android_java_init( void *arg )
1155 JavaVM *java_vm;
1157 if (!(java_vm = *p_java_vm)) return STATUS_UNSUCCESSFUL; /* not running under Java */
1159 init_java_thread( java_vm );
1160 create_desktop_window( NtUserGetDesktopWindow() );
1161 return STATUS_SUCCESS;
1164 NTSTATUS android_java_uninit( void *arg )
1166 JavaVM *java_vm;
1168 if (!(java_vm = *p_java_vm)) return STATUS_UNSUCCESSFUL; /* not running under Java */
1170 wrap_java_call();
1171 (*java_vm)->DetachCurrentThread( java_vm );
1172 unwrap_java_call();
1173 return STATUS_SUCCESS;
1176 void start_android_device(void)
1178 void *ret_ptr;
1179 ULONG ret_len;
1180 thread = ULongToHandle( KeUserModeCallback( client_start_device, NULL, 0, &ret_ptr, &ret_len ));
1184 /* Client-side ioctl support */
1187 static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
1189 static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1190 static HANDLE device;
1191 IO_STATUS_BLOCK iosb;
1192 NTSTATUS status;
1194 if (!device)
1196 OBJECT_ATTRIBUTES attr;
1197 UNICODE_STRING name;
1198 IO_STATUS_BLOCK io;
1199 NTSTATUS status;
1200 HANDLE file;
1202 RtlInitUnicodeString( &name, deviceW );
1203 InitializeObjectAttributes( &attr, &name, OBJ_CASE_INSENSITIVE, NULL, NULL );
1204 status = NtCreateFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, NULL, 0,
1205 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,
1206 FILE_NON_DIRECTORY_FILE, NULL, 0 );
1207 if (status) return -ENOENT;
1208 if (InterlockedCompareExchangePointer( &device, file, NULL )) NtClose( file );
1211 status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
1212 in, in_size, out, out_size ? *out_size : 0 );
1213 if (status == STATUS_FILE_DELETED)
1215 WARN( "parent process is gone\n" );
1216 NtTerminateProcess( 0, 1 );
1218 if (out_size) *out_size = iosb.Information;
1219 return status_to_android_error( status );
1222 static void win_incRef( struct android_native_base_t *base )
1224 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1225 InterlockedIncrement( &win->ref );
1228 static void win_decRef( struct android_native_base_t *base )
1230 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1231 InterlockedDecrement( &win->ref );
1234 static void buffer_incRef( struct android_native_base_t *base )
1236 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1237 InterlockedIncrement( &buffer->ref );
1240 static void buffer_decRef( struct android_native_base_t *base )
1242 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1244 if (!InterlockedDecrement( &buffer->ref ))
1246 if (!is_in_desktop_process()) gralloc_release_buffer( &buffer->buffer );
1247 if (buffer->bits) NtUnmapViewOfSection( GetCurrentProcess(), buffer->bits );
1248 free( buffer );
1252 static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence )
1254 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1255 struct ioctl_android_dequeueBuffer res;
1256 DWORD size = sizeof(res);
1257 int ret, use_win32 = !gralloc_module && !gralloc1_device;
1259 res.hdr.hwnd = HandleToLong( win->hwnd );
1260 res.hdr.opengl = win->opengl;
1261 res.win32 = use_win32;
1262 ret = android_ioctl( IOCTL_DEQUEUE_BUFFER,
1263 &res, offsetof( struct ioctl_android_dequeueBuffer, native_handle ),
1264 &res, &size );
1265 if (ret) return ret;
1267 /* if we received the native handle, this is a new buffer */
1268 if (size > offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
1270 struct native_buffer_wrapper *buf = calloc( 1, sizeof(*buf) );
1272 buf->buffer.common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
1273 buf->buffer.common.version = sizeof( buf->buffer );
1274 buf->buffer.common.incRef = buffer_incRef;
1275 buf->buffer.common.decRef = buffer_decRef;
1276 buf->buffer.width = res.width;
1277 buf->buffer.height = res.height;
1278 buf->buffer.stride = res.stride;
1279 buf->buffer.format = res.format;
1280 buf->buffer.usage = res.usage;
1281 buf->buffer.handle = unmap_native_handle( &res.native_handle.handle );
1282 buf->ref = 1;
1283 buf->hwnd = win->hwnd;
1284 buf->buffer_id = res.buffer_id;
1285 buf->generation = res.generation;
1286 if (win->buffers[res.buffer_id])
1287 win->buffers[res.buffer_id]->buffer.common.decRef(&win->buffers[res.buffer_id]->buffer.common);
1288 win->buffers[res.buffer_id] = buf;
1290 if (use_win32)
1292 LARGE_INTEGER zero = { .QuadPart = 0 };
1293 SIZE_T count = 0;
1294 HANDLE mapping = LongToHandle( res.native_handle.handle.data[0] );
1295 NtMapViewOfSection( mapping, GetCurrentProcess(), &buf->bits, 0, 0, &zero, &count,
1296 ViewShare, 0, PAGE_READWRITE );
1297 NtClose( mapping );
1299 else if (!is_in_desktop_process())
1301 if ((ret = gralloc_grab_buffer( &buf->buffer )) < 0)
1302 WARN( "hwnd %p, buffer %p failed to register %d %s\n",
1303 win->hwnd, &buf->buffer, ret, strerror(-ret) );
1307 *buffer = &win->buffers[res.buffer_id]->buffer;
1308 *fence = -1;
1310 TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1311 win->hwnd, *buffer, res.width, res.height, res.stride, res.format, res.usage, *fence );
1312 return 0;
1315 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1317 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1318 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1319 struct ioctl_android_cancelBuffer cancel;
1321 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1322 win->hwnd, buffer, buffer->width, buffer->height,
1323 buffer->stride, buffer->format, buffer->usage, fence );
1324 cancel.buffer_id = buf->buffer_id;
1325 cancel.generation = buf->generation;
1326 cancel.hdr.hwnd = HandleToLong( win->hwnd );
1327 cancel.hdr.opengl = win->opengl;
1328 wait_fence_and_close( fence );
1329 return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL );
1332 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1334 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1335 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1336 struct ioctl_android_queueBuffer queue;
1338 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1339 win->hwnd, buffer, buffer->width, buffer->height,
1340 buffer->stride, buffer->format, buffer->usage, fence );
1341 queue.buffer_id = buf->buffer_id;
1342 queue.generation = buf->generation;
1343 queue.hdr.hwnd = HandleToLong( win->hwnd );
1344 queue.hdr.opengl = win->opengl;
1345 wait_fence_and_close( fence );
1346 return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL );
1349 static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer )
1351 int fence, ret = dequeueBuffer( window, buffer, &fence );
1353 if (!ret) wait_fence_and_close( fence );
1354 return ret;
1357 static int cancelBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1359 return cancelBuffer( window, buffer, -1 );
1362 static int lockBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1364 return 0; /* nothing to do */
1367 static int queueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1369 return queueBuffer( window, buffer, -1 );
1372 static int setSwapInterval( struct ANativeWindow *window, int interval )
1374 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1375 struct ioctl_android_set_swap_interval swap;
1377 TRACE( "hwnd %p interval %d\n", win->hwnd, interval );
1378 swap.hdr.hwnd = HandleToLong( win->hwnd );
1379 swap.hdr.opengl = win->opengl;
1380 swap.interval = interval;
1381 return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL );
1384 static int query( const ANativeWindow *window, int what, int *value )
1386 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1387 struct ioctl_android_query query;
1388 DWORD size = sizeof( query );
1389 int ret;
1391 query.hdr.hwnd = HandleToLong( win->hwnd );
1392 query.hdr.opengl = win->opengl;
1393 query.what = what;
1394 ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size );
1395 TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value );
1396 if (!ret) *value = query.value;
1397 return ret;
1400 static int perform( ANativeWindow *window, int operation, ... )
1402 static const char * const names[] =
1404 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
1405 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
1406 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
1407 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
1410 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1411 struct ioctl_android_perform perf;
1412 va_list args;
1414 perf.hdr.hwnd = HandleToLong( win->hwnd );
1415 perf.hdr.opengl = win->opengl;
1416 perf.operation = operation;
1417 memset( perf.args, 0, sizeof(perf.args) );
1419 va_start( args, operation );
1420 switch (operation)
1422 case NATIVE_WINDOW_SET_USAGE:
1423 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
1424 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
1425 case NATIVE_WINDOW_SET_SCALING_MODE:
1426 case NATIVE_WINDOW_API_CONNECT:
1427 case NATIVE_WINDOW_API_DISCONNECT:
1428 perf.args[0] = va_arg( args, int );
1429 TRACE( "hwnd %p %s arg %d\n", win->hwnd, names[operation], perf.args[0] );
1430 break;
1431 case NATIVE_WINDOW_SET_BUFFER_COUNT:
1432 perf.args[0] = va_arg( args, size_t );
1433 TRACE( "hwnd %p %s count %d\n", win->hwnd, names[operation], perf.args[0] );
1434 break;
1435 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
1436 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
1437 perf.args[0] = va_arg( args, int );
1438 perf.args[1] = va_arg( args, int );
1439 TRACE( "hwnd %p %s arg %dx%d\n", win->hwnd, names[operation], perf.args[0], perf.args[1] );
1440 break;
1441 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
1442 perf.args[0] = va_arg( args, int );
1443 perf.args[1] = va_arg( args, int );
1444 perf.args[2] = va_arg( args, int );
1445 TRACE( "hwnd %p %s arg %dx%d %d\n", win->hwnd, names[operation],
1446 perf.args[0], perf.args[1], perf.args[2] );
1447 break;
1448 case NATIVE_WINDOW_SET_CROP:
1450 android_native_rect_t *rect = va_arg( args, android_native_rect_t * );
1451 perf.args[0] = rect->left;
1452 perf.args[1] = rect->top;
1453 perf.args[2] = rect->right;
1454 perf.args[3] = rect->bottom;
1455 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win->hwnd, names[operation],
1456 perf.args[0], perf.args[1], perf.args[2], perf.args[3] );
1457 break;
1459 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
1461 int64_t timestamp = va_arg( args, int64_t );
1462 perf.args[0] = timestamp;
1463 perf.args[1] = timestamp >> 32;
1464 TRACE( "hwnd %p %s arg %08x%08x\n", win->hwnd, names[operation], perf.args[1], perf.args[0] );
1465 break;
1467 case NATIVE_WINDOW_LOCK:
1469 struct ANativeWindowBuffer *buffer;
1470 struct ANativeWindow_Buffer *buffer_ret = va_arg( args, ANativeWindow_Buffer * );
1471 ARect *bounds = va_arg( args, ARect * );
1472 int ret = window->dequeueBuffer_DEPRECATED( window, &buffer );
1473 if (!ret)
1475 if ((ret = gralloc_lock( buffer, &buffer_ret->bits )))
1477 WARN( "gralloc->lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
1478 window->cancelBuffer( window, buffer, -1 );
1481 if (!ret)
1483 buffer_ret->width = buffer->width;
1484 buffer_ret->height = buffer->height;
1485 buffer_ret->stride = buffer->stride;
1486 buffer_ret->format = buffer->format;
1487 win->locked_buffer = buffer;
1488 if (bounds)
1490 bounds->left = 0;
1491 bounds->top = 0;
1492 bounds->right = buffer->width;
1493 bounds->bottom = buffer->height;
1496 va_end( args );
1497 TRACE( "hwnd %p %s bits %p ret %d %s\n", win->hwnd, names[operation], buffer_ret->bits, ret, strerror(-ret) );
1498 return ret;
1500 case NATIVE_WINDOW_UNLOCK_AND_POST:
1502 int ret = -EINVAL;
1503 if (win->locked_buffer)
1505 gralloc_unlock( win->locked_buffer );
1506 ret = window->queueBuffer( window, win->locked_buffer, -1 );
1507 win->locked_buffer = NULL;
1509 va_end( args );
1510 TRACE( "hwnd %p %s ret %d\n", win->hwnd, names[operation], ret );
1511 return ret;
1513 case NATIVE_WINDOW_CONNECT:
1514 case NATIVE_WINDOW_DISCONNECT:
1515 TRACE( "hwnd %p %s\n", win->hwnd, names[operation] );
1516 break;
1517 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP:
1518 default:
1519 FIXME( "unsupported perform hwnd %p op %d %s\n", win->hwnd, operation,
1520 operation < ARRAY_SIZE( names ) ? names[operation] : "???" );
1521 break;
1523 va_end( args );
1524 return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL );
1527 struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl, float scale )
1529 struct ioctl_android_create_window req;
1530 struct native_win_wrapper *win = calloc( 1, sizeof(*win) );
1532 if (!win) return NULL;
1534 win->win.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
1535 win->win.common.version = sizeof(ANativeWindow);
1536 win->win.common.incRef = win_incRef;
1537 win->win.common.decRef = win_decRef;
1538 win->win.setSwapInterval = setSwapInterval;
1539 win->win.dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
1540 win->win.lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
1541 win->win.queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
1542 win->win.query = query;
1543 win->win.perform = perform;
1544 win->win.cancelBuffer_DEPRECATED = cancelBuffer_DEPRECATED;
1545 win->win.dequeueBuffer = dequeueBuffer;
1546 win->win.queueBuffer = queueBuffer;
1547 win->win.cancelBuffer = cancelBuffer;
1548 win->ref = 1;
1549 win->hwnd = hwnd;
1550 win->opengl = opengl;
1551 TRACE( "-> %p %p opengl=%u\n", win, win->hwnd, opengl );
1553 req.hdr.hwnd = HandleToLong( win->hwnd );
1554 req.hdr.opengl = win->opengl;
1555 req.parent = get_ioctl_win_parent( NtUserGetAncestor( hwnd, GA_PARENT ));
1556 req.scale = scale;
1557 android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
1559 return &win->win;
1562 struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window )
1564 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1565 InterlockedIncrement( &win->ref );
1566 return window;
1569 void release_ioctl_window( struct ANativeWindow *window )
1571 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1572 unsigned int i;
1574 if (InterlockedDecrement( &win->ref ) > 0) return;
1576 TRACE( "%p %p\n", win, win->hwnd );
1577 for (i = 0; i < ARRAY_SIZE( win->buffers ); i++)
1578 if (win->buffers[i]) win->buffers[i]->buffer.common.decRef( &win->buffers[i]->buffer.common );
1580 destroy_ioctl_window( win->hwnd, win->opengl );
1581 free( win );
1584 void destroy_ioctl_window( HWND hwnd, BOOL opengl )
1586 struct ioctl_android_destroy_window req;
1588 req.hdr.hwnd = HandleToLong( hwnd );
1589 req.hdr.opengl = opengl;
1590 android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
1593 int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect,
1594 const RECT *visible_rect, UINT style, UINT flags, HWND after, HWND owner )
1596 struct ioctl_android_window_pos_changed req;
1598 req.hdr.hwnd = HandleToLong( hwnd );
1599 req.hdr.opengl = FALSE;
1600 req.window_rect = *window_rect;
1601 req.client_rect = *client_rect;
1602 req.visible_rect = *visible_rect;
1603 req.style = style;
1604 req.flags = flags;
1605 req.after = HandleToLong( after );
1606 req.owner = HandleToLong( owner );
1607 return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );
1610 int ioctl_set_window_parent( HWND hwnd, HWND parent, float scale )
1612 struct ioctl_android_set_window_parent req;
1614 req.hdr.hwnd = HandleToLong( hwnd );
1615 req.hdr.opengl = FALSE;
1616 req.parent = get_ioctl_win_parent( parent );
1617 req.scale = scale;
1618 return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL );
1621 int ioctl_set_capture( HWND hwnd )
1623 struct ioctl_android_set_capture req;
1625 req.hdr.hwnd = HandleToLong( hwnd );
1626 req.hdr.opengl = FALSE;
1627 return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );
1630 int ioctl_set_cursor( int id, int width, int height,
1631 int hotspotx, int hotspoty, const unsigned int *bits )
1633 struct ioctl_android_set_cursor *req;
1634 unsigned int size = offsetof( struct ioctl_android_set_cursor, bits[width * height] );
1635 int ret;
1637 if (!(req = malloc( size ))) return -ENOMEM;
1638 req->hdr.hwnd = 0; /* unused */
1639 req->hdr.opengl = FALSE;
1640 req->id = id;
1641 req->width = width;
1642 req->height = height;
1643 req->hotspotx = hotspotx;
1644 req->hotspoty = hotspoty;
1645 memcpy( req->bits, bits, width * height * sizeof(req->bits[0]) );
1646 ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL );
1647 free( req );
1648 return ret;