makefiles: Explicitly create destination dirs when installing symlinks.
[wine/zf.git] / dlls / wineandroid.drv / device.c
blobc2eb63382ad99dfc8501494e1c3115ce3e6772f3
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 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <sys/ioctl.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winternl.h"
38 #include "winioctl.h"
39 #include "ddk/wdm.h"
40 #include "android.h"
41 #include "wine/server.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(android);
46 #ifndef SYNC_IOC_WAIT
47 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
48 #endif
50 extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
51 static HANDLE stop_event;
52 static HANDLE thread;
53 static JNIEnv *jni_env;
54 static HWND capture_window;
56 #define ANDROIDCONTROLTYPE ((ULONG)'A')
57 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
59 enum android_ioctl
61 IOCTL_CREATE_WINDOW,
62 IOCTL_DESTROY_WINDOW,
63 IOCTL_WINDOW_POS_CHANGED,
64 IOCTL_SET_WINDOW_PARENT,
65 IOCTL_DEQUEUE_BUFFER,
66 IOCTL_QUEUE_BUFFER,
67 IOCTL_CANCEL_BUFFER,
68 IOCTL_QUERY,
69 IOCTL_PERFORM,
70 IOCTL_SET_SWAP_INT,
71 IOCTL_SET_CAPTURE,
72 IOCTL_SET_CURSOR,
73 NB_IOCTLS
76 #define NB_CACHED_BUFFERS 4
78 struct native_buffer_wrapper;
80 /* buffer for storing a variable-size native handle inside an ioctl structure */
81 union native_handle_buffer
83 native_handle_t handle;
84 int space[256];
87 /* data about the native window in the context of the Java process */
88 struct native_win_data
90 struct ANativeWindow *parent;
91 struct ANativeWindowBuffer *buffers[NB_CACHED_BUFFERS];
92 void *mappings[NB_CACHED_BUFFERS];
93 HWND hwnd;
94 BOOL opengl;
95 int generation;
96 int api;
97 int buffer_format;
98 int swap_interval;
99 int buffer_lru[NB_CACHED_BUFFERS];
102 /* wrapper for a native window in the context of the client (non-Java) process */
103 struct native_win_wrapper
105 struct ANativeWindow win;
106 struct native_buffer_wrapper *buffers[NB_CACHED_BUFFERS];
107 struct ANativeWindowBuffer *locked_buffer;
108 HWND hwnd;
109 BOOL opengl;
110 LONG ref;
113 /* wrapper for a native buffer in the context of the client (non-Java) process */
114 struct native_buffer_wrapper
116 struct ANativeWindowBuffer buffer;
117 LONG ref;
118 HWND hwnd;
119 void *bits;
120 int buffer_id;
121 int generation;
122 union native_handle_buffer native_handle;
125 struct ioctl_header
127 int hwnd;
128 BOOL opengl;
131 struct ioctl_android_create_window
133 struct ioctl_header hdr;
134 int parent;
135 float scale;
138 struct ioctl_android_destroy_window
140 struct ioctl_header hdr;
143 struct ioctl_android_window_pos_changed
145 struct ioctl_header hdr;
146 RECT window_rect;
147 RECT client_rect;
148 RECT visible_rect;
149 int style;
150 int flags;
151 int after;
152 int owner;
155 struct ioctl_android_dequeueBuffer
157 struct ioctl_header hdr;
158 int win32;
159 int width;
160 int height;
161 int stride;
162 int format;
163 int usage;
164 int buffer_id;
165 int generation;
166 union native_handle_buffer native_handle;
169 struct ioctl_android_queueBuffer
171 struct ioctl_header hdr;
172 int buffer_id;
173 int generation;
176 struct ioctl_android_cancelBuffer
178 struct ioctl_header hdr;
179 int buffer_id;
180 int generation;
183 struct ioctl_android_query
185 struct ioctl_header hdr;
186 int what;
187 int value;
190 struct ioctl_android_perform
192 struct ioctl_header hdr;
193 int operation;
194 int args[4];
197 struct ioctl_android_set_swap_interval
199 struct ioctl_header hdr;
200 int interval;
203 struct ioctl_android_set_window_parent
205 struct ioctl_header hdr;
206 int parent;
207 float scale;
210 struct ioctl_android_set_capture
212 struct ioctl_header hdr;
215 struct ioctl_android_set_cursor
217 struct ioctl_header hdr;
218 int id;
219 int width;
220 int height;
221 int hotspotx;
222 int hotspoty;
223 int bits[1];
226 static struct gralloc_module_t *gralloc_module;
227 static struct gralloc1_device *gralloc1_device;
228 static BOOL gralloc1_caps[GRALLOC1_LAST_CAPABILITY + 1];
230 static gralloc1_error_t (*gralloc1_retain)( gralloc1_device_t *device, buffer_handle_t buffer );
231 static gralloc1_error_t (*gralloc1_release)( gralloc1_device_t *device, buffer_handle_t buffer );
232 static gralloc1_error_t (*gralloc1_lock)( gralloc1_device_t *device, buffer_handle_t buffer,
233 uint64_t producerUsage, uint64_t consumerUsage,
234 const gralloc1_rect_t *accessRegion, void **outData,
235 int32_t acquireFence );
236 static gralloc1_error_t (*gralloc1_unlock)( gralloc1_device_t *device, buffer_handle_t buffer,
237 int32_t *outReleaseFence );
239 static inline BOOL is_in_desktop_process(void)
241 return thread != NULL;
244 static inline DWORD current_client_id(void)
246 return HandleToUlong( PsGetCurrentProcessId() );
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 __asm__( "mov %%fs,%0" : "=r" (orig_fs) );
262 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
263 __asm__( "mov %%fs,%0" : "=r" (java_fs) );
264 __asm__( "mov %0,%%fs" :: "r" (orig_fs) );
267 #elif defined(__x86_64__)
269 #include <asm/prctl.h>
270 #include <asm/unistd.h>
271 static void *orig_teb, *java_teb;
272 static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
273 static inline void wrap_java_call(void) { arch_prctl( ARCH_SET_GS, java_teb ); }
274 static inline void unwrap_java_call(void) { arch_prctl( ARCH_SET_GS, orig_teb ); }
275 static inline void init_java_thread( JavaVM *java_vm )
277 arch_prctl( ARCH_GET_GS, &orig_teb );
278 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
279 arch_prctl( ARCH_GET_GS, &java_teb );
280 arch_prctl( ARCH_SET_GS, orig_teb );
283 #else
284 static inline void wrap_java_call(void) { }
285 static inline void unwrap_java_call(void) { }
286 static inline void init_java_thread( JavaVM *java_vm ) { (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); }
287 #endif /* __i386__ */
289 static struct native_win_data *data_map[65536];
291 static unsigned int data_map_idx( HWND hwnd, BOOL opengl )
293 /* window handles are always even, so use low-order bit for opengl flag */
294 return LOWORD(hwnd) + !!opengl;
297 static struct native_win_data *get_native_win_data( HWND hwnd, BOOL opengl )
299 struct native_win_data *data = data_map[data_map_idx( hwnd, opengl )];
301 if (data && data->hwnd == hwnd && !data->opengl == !opengl) return data;
302 WARN( "unknown win %p opengl %u\n", hwnd, opengl );
303 return NULL;
306 static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr )
308 return get_native_win_data( LongToHandle(hdr->hwnd), hdr->opengl );
311 static int get_ioctl_win_parent( HWND parent )
313 if (parent != GetDesktopWindow() && !GetAncestor( parent, GA_PARENT ))
314 return HandleToLong( HWND_MESSAGE );
315 return HandleToLong( parent );
318 static void wait_fence_and_close( int fence )
320 __s32 timeout = 1000; /* FIXME: should be -1 for infinite timeout */
322 if (fence == -1) return;
323 ioctl( fence, SYNC_IOC_WAIT, &timeout );
324 close( fence );
327 static int duplicate_fd( HANDLE client, int fd )
329 HANDLE handle, ret = 0;
331 if (!wine_server_fd_to_handle( dup(fd), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
332 DuplicateHandle( GetCurrentProcess(), handle, client, &ret,
333 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE );
335 if (!ret) return -1;
336 return HandleToLong( ret );
339 static int map_native_handle( union native_handle_buffer *dest, const native_handle_t *src,
340 HANDLE mapping, HANDLE client )
342 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
343 int i;
345 if (mapping) /* only duplicate the mapping handle */
347 HANDLE ret = 0;
348 if (!DuplicateHandle( GetCurrentProcess(), mapping, client, &ret,
349 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE ))
350 return -ENOSPC;
351 dest->handle.numFds = 0;
352 dest->handle.numInts = 1;
353 dest->handle.data[0] = HandleToLong( ret );
354 return 0;
356 if (is_client_in_process()) /* transfer the actual handle pointer */
358 dest->handle.numFds = 0;
359 dest->handle.numInts = sizeof(src) / sizeof(int);
360 memcpy( dest->handle.data, &src, sizeof(src) );
361 return 0;
363 if (size > sizeof(*dest)) return -ENOSPC;
364 memcpy( dest, src, size );
365 /* transfer file descriptors to the client process */
366 for (i = 0; i < dest->handle.numFds; i++)
367 dest->handle.data[i] = duplicate_fd( client, src->data[i] );
368 return 0;
371 static native_handle_t *unmap_native_handle( const native_handle_t *src )
373 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
374 native_handle_t *dest;
375 int i;
377 if (!is_in_desktop_process())
379 dest = malloc( size );
380 memcpy( dest, src, size );
381 /* fetch file descriptors passed from the server process */
382 for (i = 0; i < dest->numFds; i++)
383 wine_server_handle_to_fd( LongToHandle(src->data[i]), GENERIC_READ | SYNCHRONIZE,
384 &dest->data[i], NULL );
386 else memcpy( &dest, src->data, sizeof(dest) );
387 return dest;
390 static void close_native_handle( native_handle_t *handle )
392 int i;
394 for (i = 0; i < handle->numFds; i++) close( handle->data[i] );
395 free( handle );
398 /* insert a buffer index at the head of the LRU list */
399 static void insert_buffer_lru( struct native_win_data *win, int index )
401 unsigned int i;
403 for (i = 0; i < NB_CACHED_BUFFERS; i++)
405 if (win->buffer_lru[i] == index) break;
406 if (win->buffer_lru[i] == -1) break;
409 assert( i < NB_CACHED_BUFFERS );
410 memmove( win->buffer_lru + 1, win->buffer_lru, i * sizeof(win->buffer_lru[0]) );
411 win->buffer_lru[0] = index;
414 static int register_buffer( struct native_win_data *win, struct ANativeWindowBuffer *buffer,
415 HANDLE *mapping, int *is_new )
417 unsigned int i;
419 *is_new = 0;
420 for (i = 0; i < NB_CACHED_BUFFERS; i++)
422 if (win->buffers[i] == buffer) goto done;
423 if (!win->buffers[i]) break;
426 if (i == NB_CACHED_BUFFERS)
428 /* reuse the least recently used buffer */
429 i = win->buffer_lru[NB_CACHED_BUFFERS - 1];
430 assert( i < NB_CACHED_BUFFERS );
432 TRACE( "%p %p evicting buffer %p id %d from cache\n",
433 win->hwnd, win->parent, win->buffers[i], i );
434 win->buffers[i]->common.decRef( &win->buffers[i]->common );
435 if (win->mappings[i]) UnmapViewOfFile( win->mappings[i] );
438 win->buffers[i] = buffer;
439 win->mappings[i] = NULL;
441 if (mapping)
443 *mapping = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
444 buffer->stride * buffer->height * 4, NULL );
445 win->mappings[i] = MapViewOfFile( *mapping, FILE_MAP_READ, 0, 0, 0 );
447 buffer->common.incRef( &buffer->common );
448 *is_new = 1;
449 TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i );
451 done:
452 insert_buffer_lru( win, i );
453 return i;
456 static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data *win, int id )
458 if (id < 0 || id >= NB_CACHED_BUFFERS || !win->buffers[id])
460 ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent );
461 return NULL;
463 return win->buffers[id];
466 static void release_native_window( struct native_win_data *data )
468 unsigned int i;
470 if (data->parent) pANativeWindow_release( data->parent );
471 for (i = 0; i < NB_CACHED_BUFFERS; i++)
473 if (data->buffers[i]) data->buffers[i]->common.decRef( &data->buffers[i]->common );
474 if (data->mappings[i]) UnmapViewOfFile( data->mappings[i] );
475 data->buffer_lru[i] = -1;
477 memset( data->buffers, 0, sizeof(data->buffers) );
478 memset( data->mappings, 0, sizeof(data->mappings) );
481 static void free_native_win_data( struct native_win_data *data )
483 unsigned int idx = data_map_idx( data->hwnd, data->opengl );
485 InterlockedCompareExchangePointer( (void **)&capture_window, 0, data->hwnd );
486 release_native_window( data );
487 HeapFree( GetProcessHeap(), 0, data );
488 data_map[idx] = NULL;
491 static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl )
493 unsigned int i, idx = data_map_idx( hwnd, opengl );
494 struct native_win_data *data = data_map[idx];
496 if (data)
498 WARN( "data for %p not freed correctly\n", data->hwnd );
499 free_native_win_data( data );
501 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return NULL;
502 data->hwnd = hwnd;
503 data->opengl = opengl;
504 if (!opengl) data->api = NATIVE_WINDOW_API_CPU;
505 data->buffer_format = PF_BGRA_8888;
506 data_map[idx] = data;
507 for (i = 0; i < NB_CACHED_BUFFERS; i++) data->buffer_lru[i] = -1;
508 return data;
511 static void CALLBACK register_native_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
513 HWND hwnd = (HWND)arg1;
514 struct ANativeWindow *win = (struct ANativeWindow *)arg2;
515 BOOL opengl = arg3;
516 struct native_win_data *data = get_native_win_data( hwnd, opengl );
518 if (!win) return; /* do nothing and hold on to the window until we get a new surface */
520 if (!data || data->parent == win)
522 pANativeWindow_release( win );
523 if (data) PostMessageW( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
524 TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win );
525 return;
528 release_native_window( data );
529 data->parent = win;
530 data->generation++;
531 wrap_java_call();
532 if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api );
533 win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format );
534 win->setSwapInterval( win, data->swap_interval );
535 unwrap_java_call();
536 PostMessageW( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
537 TRACE( "%p -> %p win %p\n", hwnd, data, win );
540 /* register a native window received from the Java side for use in ioctls */
541 void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl )
543 NtQueueApcThread( thread, register_native_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl );
546 void init_gralloc( const struct hw_module_t *module )
548 struct hw_device_t *device;
549 int ret;
551 TRACE( "got module %p ver %u.%u id %s name %s author %s\n",
552 module, module->module_api_version >> 8, module->module_api_version & 0xff,
553 debugstr_a(module->id), debugstr_a(module->name), debugstr_a(module->author) );
555 switch (module->module_api_version >> 8)
557 case 0:
558 gralloc_module = (struct gralloc_module_t *)module;
559 break;
560 case 1:
561 if (!(ret = module->methods->open( module, GRALLOC_HARDWARE_MODULE_ID, &device )))
563 int32_t caps[64];
564 uint32_t i, count = ARRAY_SIZE(caps);
566 gralloc1_device = (struct gralloc1_device *)device;
567 gralloc1_retain = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RETAIN );
568 gralloc1_release = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RELEASE );
569 gralloc1_lock = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_LOCK );
570 gralloc1_unlock = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_UNLOCK );
571 TRACE( "got device version %u funcs %p %p %p %p\n", device->version,
572 gralloc1_retain, gralloc1_release, gralloc1_lock, gralloc1_unlock );
574 gralloc1_device->getCapabilities( gralloc1_device, &count, caps );
575 if (count == ARRAY_SIZE(caps)) ERR( "too many gralloc capabilities\n" );
576 for (i = 0; i < count; i++)
577 if (caps[i] < ARRAY_SIZE(gralloc1_caps)) gralloc1_caps[caps[i]] = TRUE;
579 else ERR( "failed to open gralloc err %d\n", ret );
580 break;
581 default:
582 ERR( "unknown gralloc module version %u\n", module->module_api_version >> 8 );
583 break;
587 static int gralloc_grab_buffer( struct ANativeWindowBuffer *buffer )
589 if (gralloc1_device)
590 return gralloc1_retain( gralloc1_device, buffer->handle );
591 if (gralloc_module)
592 return gralloc_module->registerBuffer( gralloc_module, buffer->handle );
593 return -ENODEV;
596 static void gralloc_release_buffer( struct ANativeWindowBuffer *buffer )
598 if (gralloc1_device) gralloc1_release( gralloc1_device, buffer->handle );
599 else if (gralloc_module) gralloc_module->unregisterBuffer( gralloc_module, buffer->handle );
601 if (!gralloc1_caps[GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE])
602 close_native_handle( (native_handle_t *)buffer->handle );
605 static int gralloc_lock( struct ANativeWindowBuffer *buffer, void **bits )
607 if (gralloc1_device)
609 gralloc1_rect_t rect = { 0, 0, buffer->width, buffer->height };
610 return gralloc1_lock( gralloc1_device, buffer->handle,
611 GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN |
612 GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
613 GRALLOC1_CONSUMER_USAGE_NONE, &rect, bits, -1 );
615 if (gralloc_module)
616 return gralloc_module->lock( gralloc_module, buffer->handle,
617 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
618 0, 0, buffer->width, buffer->height, bits );
620 *bits = ((struct native_buffer_wrapper *)buffer)->bits;
621 return 0;
624 static void gralloc_unlock( struct ANativeWindowBuffer *buffer )
626 if (gralloc1_device)
628 int fence;
629 gralloc1_unlock( gralloc1_device, buffer->handle, &fence );
630 wait_fence_and_close( fence );
632 else if (gralloc_module) gralloc_module->unlock( gralloc_module, buffer->handle );
635 /* get the capture window stored in the desktop process */
636 HWND get_capture_window(void)
638 return capture_window;
641 static NTSTATUS android_error_to_status( int err )
643 switch (err)
645 case 0: return STATUS_SUCCESS;
646 case -ENOMEM: return STATUS_NO_MEMORY;
647 case -ENOSYS: return STATUS_NOT_SUPPORTED;
648 case -EINVAL: return STATUS_INVALID_PARAMETER;
649 case -ENOENT: return STATUS_INVALID_HANDLE;
650 case -EPERM: return STATUS_ACCESS_DENIED;
651 case -ENODEV: return STATUS_NO_SUCH_DEVICE;
652 case -EEXIST: return STATUS_DUPLICATE_NAME;
653 case -EPIPE: return STATUS_PIPE_DISCONNECTED;
654 case -ENODATA: return STATUS_NO_MORE_FILES;
655 case -ETIMEDOUT: return STATUS_IO_TIMEOUT;
656 case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST;
657 case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
658 default:
659 FIXME( "unmapped error %d\n", err );
660 return STATUS_UNSUCCESSFUL;
664 static int status_to_android_error( NTSTATUS status )
666 switch (status)
668 case STATUS_SUCCESS: return 0;
669 case STATUS_NO_MEMORY: return -ENOMEM;
670 case STATUS_NOT_SUPPORTED: return -ENOSYS;
671 case STATUS_INVALID_PARAMETER: return -EINVAL;
672 case STATUS_BUFFER_OVERFLOW: return -EINVAL;
673 case STATUS_INVALID_HANDLE: return -ENOENT;
674 case STATUS_ACCESS_DENIED: return -EPERM;
675 case STATUS_NO_SUCH_DEVICE: return -ENODEV;
676 case STATUS_DUPLICATE_NAME: return -EEXIST;
677 case STATUS_PIPE_DISCONNECTED: return -EPIPE;
678 case STATUS_NO_MORE_FILES: return -ENODATA;
679 case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
680 case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
681 case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
682 default:
683 FIXME( "unmapped status %08x\n", status );
684 return -EINVAL;
688 static jobject load_java_method( jmethodID *method, const char *name, const char *args )
690 jobject object = p_wine_get_java_object();
692 if (!*method)
694 jclass class;
696 wrap_java_call();
697 class = (*jni_env)->GetObjectClass( jni_env, object );
698 *method = (*jni_env)->GetMethodID( jni_env, class, name, args );
699 unwrap_java_call();
700 if (!*method)
702 FIXME( "method %s not found\n", name );
703 return NULL;
706 return object;
709 static void create_desktop_window( HWND hwnd )
711 static jmethodID method;
712 jobject object;
714 if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
716 wrap_java_call();
717 (*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
718 unwrap_java_call();
721 static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
723 static jmethodID method;
724 jobject object;
725 struct ioctl_android_create_window *res = data;
726 struct native_win_data *win_data;
727 DWORD pid = current_client_id();
729 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
731 if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd), res->hdr.opengl )))
732 return STATUS_NO_MEMORY;
734 TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent );
736 if (!(object = load_java_method( &method, "createWindow", "(IZIFI)V" ))) return STATUS_NOT_SUPPORTED;
738 wrap_java_call();
739 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->hdr.opengl, res->parent, res->scale, pid );
740 unwrap_java_call();
741 return STATUS_SUCCESS;
744 static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
746 static jmethodID method;
747 jobject object;
748 struct ioctl_android_destroy_window *res = data;
749 struct native_win_data *win_data;
751 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
753 win_data = get_ioctl_native_win_data( &res->hdr );
755 TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl );
757 if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
759 wrap_java_call();
760 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
761 unwrap_java_call();
762 if (win_data) free_native_win_data( win_data );
763 return STATUS_SUCCESS;
766 static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
768 static jmethodID method;
769 jobject object;
770 struct ioctl_android_window_pos_changed *res = data;
772 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
774 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
775 res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect),
776 wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner );
778 if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
779 return STATUS_NOT_SUPPORTED;
781 wrap_java_call();
782 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style,
783 res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom,
784 res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom,
785 res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom );
786 unwrap_java_call();
787 return STATUS_SUCCESS;
790 static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
792 struct ANativeWindow *parent;
793 struct ioctl_android_dequeueBuffer *res = data;
794 struct native_win_data *win_data;
795 struct ANativeWindowBuffer *buffer;
796 int fence, ret, is_new;
798 if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW;
800 if (in_size < offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
801 return STATUS_INVALID_PARAMETER;
803 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
804 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
806 *ret_size = offsetof( struct ioctl_android_dequeueBuffer, native_handle );
807 wrap_java_call();
808 ret = parent->dequeueBuffer( parent, &buffer, &fence );
809 unwrap_java_call();
810 if (!ret)
812 HANDLE mapping = 0;
814 TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
815 res->width = buffer->width;
816 res->height = buffer->height;
817 res->stride = buffer->stride;
818 res->format = buffer->format;
819 res->usage = buffer->usage;
820 res->buffer_id = register_buffer( win_data, buffer, res->win32 ? &mapping : NULL, &is_new );
821 res->generation = win_data->generation;
822 if (is_new)
824 HANDLE process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, current_client_id() );
825 map_native_handle( &res->native_handle, buffer->handle, mapping, process );
826 CloseHandle( process );
827 *ret_size = sizeof( *res );
829 wait_fence_and_close( fence );
830 return STATUS_SUCCESS;
832 ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
833 return android_error_to_status( ret );
836 static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
838 struct ioctl_android_cancelBuffer *res = data;
839 struct ANativeWindow *parent;
840 struct ANativeWindowBuffer *buffer;
841 struct native_win_data *win_data;
842 int ret;
844 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
846 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
847 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
848 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
850 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
852 TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer );
853 wrap_java_call();
854 ret = parent->cancelBuffer( parent, buffer, -1 );
855 unwrap_java_call();
856 return android_error_to_status( ret );
859 static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
861 struct ioctl_android_queueBuffer *res = data;
862 struct ANativeWindow *parent;
863 struct ANativeWindowBuffer *buffer;
864 struct native_win_data *win_data;
865 int ret;
867 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
869 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
870 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
871 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
873 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
875 TRACE( "%08x buffer %p mapping %p\n", res->hdr.hwnd, buffer, win_data->mappings[res->buffer_id] );
876 if (win_data->mappings[res->buffer_id])
878 void *bits;
879 ret = gralloc_lock( buffer, &bits );
880 if (ret) return android_error_to_status( ret );
881 memcpy( bits, win_data->mappings[res->buffer_id], buffer->stride * buffer->height * 4 );
882 gralloc_unlock( buffer );
884 wrap_java_call();
885 ret = parent->queueBuffer( parent, buffer, -1 );
886 unwrap_java_call();
887 return android_error_to_status( ret );
890 static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
892 struct ioctl_android_query *res = data;
893 struct ANativeWindow *parent;
894 struct native_win_data *win_data;
895 int ret;
897 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
898 if (out_size < sizeof(*res)) return STATUS_BUFFER_OVERFLOW;
900 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
901 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
903 *ret_size = sizeof( *res );
904 wrap_java_call();
905 ret = parent->query( parent, res->what, &res->value );
906 unwrap_java_call();
907 return android_error_to_status( ret );
910 static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
912 struct ioctl_android_perform *res = data;
913 struct ANativeWindow *parent;
914 struct native_win_data *win_data;
915 int ret = -ENOENT;
917 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
919 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
920 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
922 switch (res->operation)
924 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
925 wrap_java_call();
926 ret = parent->perform( parent, res->operation, res->args[0] );
927 unwrap_java_call();
928 if (!ret) win_data->buffer_format = res->args[0];
929 break;
930 case NATIVE_WINDOW_API_CONNECT:
931 wrap_java_call();
932 ret = parent->perform( parent, res->operation, res->args[0] );
933 unwrap_java_call();
934 if (!ret) win_data->api = res->args[0];
935 break;
936 case NATIVE_WINDOW_API_DISCONNECT:
937 wrap_java_call();
938 ret = parent->perform( parent, res->operation, res->args[0] );
939 unwrap_java_call();
940 if (!ret) win_data->api = 0;
941 break;
942 case NATIVE_WINDOW_SET_USAGE:
943 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
944 case NATIVE_WINDOW_SET_SCALING_MODE:
945 wrap_java_call();
946 ret = parent->perform( parent, res->operation, res->args[0] );
947 unwrap_java_call();
948 break;
949 case NATIVE_WINDOW_SET_BUFFER_COUNT:
950 wrap_java_call();
951 ret = parent->perform( parent, res->operation, (size_t)res->args[0] );
952 unwrap_java_call();
953 break;
954 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
955 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
956 wrap_java_call();
957 ret = parent->perform( parent, res->operation, res->args[0], res->args[1] );
958 unwrap_java_call();
959 break;
960 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
961 wrap_java_call();
962 ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] );
963 unwrap_java_call();
964 break;
965 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
966 wrap_java_call();
967 ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) );
968 unwrap_java_call();
969 break;
970 case NATIVE_WINDOW_CONNECT:
971 case NATIVE_WINDOW_DISCONNECT:
972 case NATIVE_WINDOW_UNLOCK_AND_POST:
973 wrap_java_call();
974 ret = parent->perform( parent, res->operation );
975 unwrap_java_call();
976 break;
977 case NATIVE_WINDOW_SET_CROP:
979 android_native_rect_t rect;
980 rect.left = res->args[0];
981 rect.top = res->args[1];
982 rect.right = res->args[2];
983 rect.bottom = res->args[3];
984 wrap_java_call();
985 ret = parent->perform( parent, res->operation, &rect );
986 unwrap_java_call();
987 break;
989 case NATIVE_WINDOW_LOCK:
990 default:
991 FIXME( "unsupported perform op %d\n", res->operation );
992 break;
994 return android_error_to_status( ret );
997 static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
999 struct ioctl_android_set_swap_interval *res = data;
1000 struct ANativeWindow *parent;
1001 struct native_win_data *win_data;
1002 int ret;
1004 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1006 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
1007 win_data->swap_interval = res->interval;
1009 if (!(parent = win_data->parent)) return STATUS_SUCCESS;
1010 wrap_java_call();
1011 ret = parent->setSwapInterval( parent, res->interval );
1012 unwrap_java_call();
1013 return android_error_to_status( ret );
1016 static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1018 static jmethodID method;
1019 jobject object;
1020 struct ioctl_android_set_window_parent *res = data;
1021 struct native_win_data *win_data;
1022 DWORD pid = current_client_id();
1024 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1026 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
1028 TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
1030 if (!(object = load_java_method( &method, "setParent", "(IIFI)V" ))) return STATUS_NOT_SUPPORTED;
1032 wrap_java_call();
1033 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, res->scale, pid );
1034 unwrap_java_call();
1035 return STATUS_SUCCESS;
1038 static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1040 struct ioctl_android_set_capture *res = data;
1042 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
1044 if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE;
1046 TRACE( "hwnd %08x\n", res->hdr.hwnd );
1048 InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd ));
1049 return STATUS_SUCCESS;
1052 static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
1054 static jmethodID method;
1055 jobject object;
1056 int size;
1057 struct ioctl_android_set_cursor *res = data;
1059 if (in_size < offsetof( struct ioctl_android_set_cursor, bits )) return STATUS_INVALID_PARAMETER;
1061 if (res->width < 0 || res->height < 0 || res->width > 256 || res->height > 256)
1062 return STATUS_INVALID_PARAMETER;
1064 size = res->width * res->height;
1065 if (in_size != offsetof( struct ioctl_android_set_cursor, bits[size] ))
1066 return STATUS_INVALID_PARAMETER;
1068 TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size );
1070 if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" )))
1071 return STATUS_NOT_SUPPORTED;
1073 wrap_java_call();
1075 if (size)
1077 jintArray array = (*jni_env)->NewIntArray( jni_env, size );
1078 (*jni_env)->SetIntArrayRegion( jni_env, array, 0, size, (jint *)res->bits );
1079 (*jni_env)->CallVoidMethod( jni_env, object, method, 0, res->width, res->height,
1080 res->hotspotx, res->hotspoty, array );
1081 (*jni_env)->DeleteLocalRef( jni_env, array );
1083 else (*jni_env)->CallVoidMethod( jni_env, object, method, res->id, 0, 0, 0, 0, 0 );
1085 unwrap_java_call();
1087 return STATUS_SUCCESS;
1090 typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
1091 static const ioctl_func ioctl_funcs[] =
1093 createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
1094 destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
1095 windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */
1096 setWindowParent_ioctl, /* IOCTL_SET_WINDOW_PARENT */
1097 dequeueBuffer_ioctl, /* IOCTL_DEQUEUE_BUFFER */
1098 queueBuffer_ioctl, /* IOCTL_QUEUE_BUFFER */
1099 cancelBuffer_ioctl, /* IOCTL_CANCEL_BUFFER */
1100 query_ioctl, /* IOCTL_QUERY */
1101 perform_ioctl, /* IOCTL_PERFORM */
1102 setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
1103 setCapture_ioctl, /* IOCTL_SET_CAPTURE */
1104 setCursor_ioctl, /* IOCTL_SET_CURSOR */
1107 static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
1109 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
1110 DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
1112 if (code < NB_IOCTLS)
1114 struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
1115 DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
1116 ioctl_func func = ioctl_funcs[code];
1118 if (in_size >= sizeof(*header))
1120 irp->IoStatus.Information = 0;
1121 irp->IoStatus.u.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
1122 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
1123 &irp->IoStatus.Information );
1125 else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
1127 else
1129 FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
1130 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
1132 IoCompleteRequest( irp, IO_NO_INCREMENT );
1133 return STATUS_SUCCESS;
1136 static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name )
1138 static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1139 static const WCHAR device_linkW[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1141 UNICODE_STRING nameW, linkW;
1142 DEVICE_OBJECT *device;
1143 NTSTATUS status;
1145 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback;
1147 RtlInitUnicodeString( &nameW, device_nameW );
1148 RtlInitUnicodeString( &linkW, device_linkW );
1150 if ((status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ))) return status;
1151 return IoCreateSymbolicLink( &linkW, &nameW );
1154 static DWORD CALLBACK device_thread( void *arg )
1156 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1158 HANDLE start_event = arg;
1159 UNICODE_STRING nameW;
1160 NTSTATUS status;
1161 JavaVM *java_vm;
1162 DWORD ret;
1164 TRACE( "starting process %x\n", GetCurrentProcessId() );
1166 if (!(java_vm = p_wine_get_java_vm())) return 0; /* not running under Java */
1168 init_java_thread( java_vm );
1170 create_desktop_window( GetDesktopWindow() );
1172 RtlInitUnicodeString( &nameW, driver_nameW );
1173 if ((status = IoCreateDriver( &nameW, init_android_driver )))
1175 FIXME( "failed to create driver error %x\n", status );
1176 return status;
1179 stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
1180 SetEvent( start_event );
1182 ret = wine_ntoskrnl_main_loop( stop_event );
1184 wrap_java_call();
1185 (*java_vm)->DetachCurrentThread( java_vm );
1186 unwrap_java_call();
1187 return ret;
1190 void start_android_device(void)
1192 HANDLE handles[2];
1194 handles[0] = CreateEventW( NULL, TRUE, FALSE, NULL );
1195 handles[1] = thread = CreateThread( NULL, 0, device_thread, handles[0], 0, NULL );
1196 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
1197 CloseHandle( handles[0] );
1201 /* Client-side ioctl support */
1204 static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
1206 static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1207 static HANDLE device;
1208 IO_STATUS_BLOCK iosb;
1209 NTSTATUS status;
1211 if (!device)
1213 HANDLE file = CreateFileW( deviceW, GENERIC_READ,
1214 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1215 if (file == INVALID_HANDLE_VALUE) return -ENOENT;
1216 if (InterlockedCompareExchangePointer( &device, file, NULL )) CloseHandle( file );
1219 status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
1220 in, in_size, out, out_size ? *out_size : 0 );
1221 if (status == STATUS_FILE_DELETED)
1223 WARN( "parent process is gone\n" );
1224 ExitProcess( 1 );
1226 if (out_size) *out_size = iosb.Information;
1227 return status_to_android_error( status );
1230 static void win_incRef( struct android_native_base_t *base )
1232 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1233 InterlockedIncrement( &win->ref );
1236 static void win_decRef( struct android_native_base_t *base )
1238 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1239 InterlockedDecrement( &win->ref );
1242 static void buffer_incRef( struct android_native_base_t *base )
1244 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1245 InterlockedIncrement( &buffer->ref );
1248 static void buffer_decRef( struct android_native_base_t *base )
1250 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1252 if (!InterlockedDecrement( &buffer->ref ))
1254 if (!is_in_desktop_process()) gralloc_release_buffer( &buffer->buffer );
1255 if (buffer->bits) UnmapViewOfFile( buffer->bits );
1256 HeapFree( GetProcessHeap(), 0, buffer );
1260 static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence )
1262 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1263 struct ioctl_android_dequeueBuffer res;
1264 DWORD size = sizeof(res);
1265 int ret, use_win32 = !gralloc_module && !gralloc1_device;
1267 res.hdr.hwnd = HandleToLong( win->hwnd );
1268 res.hdr.opengl = win->opengl;
1269 res.win32 = use_win32;
1270 ret = android_ioctl( IOCTL_DEQUEUE_BUFFER,
1271 &res, offsetof( struct ioctl_android_dequeueBuffer, native_handle ),
1272 &res, &size );
1273 if (ret) return ret;
1275 /* if we received the native handle, this is a new buffer */
1276 if (size > offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
1278 struct native_buffer_wrapper *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buf) );
1280 buf->buffer.common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
1281 buf->buffer.common.version = sizeof( buf->buffer );
1282 buf->buffer.common.incRef = buffer_incRef;
1283 buf->buffer.common.decRef = buffer_decRef;
1284 buf->buffer.width = res.width;
1285 buf->buffer.height = res.height;
1286 buf->buffer.stride = res.stride;
1287 buf->buffer.format = res.format;
1288 buf->buffer.usage = res.usage;
1289 buf->buffer.handle = unmap_native_handle( &res.native_handle.handle );
1290 buf->ref = 1;
1291 buf->hwnd = win->hwnd;
1292 buf->buffer_id = res.buffer_id;
1293 buf->generation = res.generation;
1294 if (win->buffers[res.buffer_id])
1295 win->buffers[res.buffer_id]->buffer.common.decRef(&win->buffers[res.buffer_id]->buffer.common);
1296 win->buffers[res.buffer_id] = buf;
1298 if (use_win32)
1300 HANDLE mapping = LongToHandle( res.native_handle.handle.data[0] );
1301 buf->bits = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
1302 CloseHandle( mapping );
1304 else if (!is_in_desktop_process())
1306 if ((ret = gralloc_grab_buffer( &buf->buffer )) < 0)
1307 WARN( "hwnd %p, buffer %p failed to register %d %s\n",
1308 win->hwnd, &buf->buffer, ret, strerror(-ret) );
1312 *buffer = &win->buffers[res.buffer_id]->buffer;
1313 *fence = -1;
1315 TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1316 win->hwnd, *buffer, res.width, res.height, res.stride, res.format, res.usage, *fence );
1317 return 0;
1320 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1322 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1323 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1324 struct ioctl_android_cancelBuffer cancel;
1326 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1327 win->hwnd, buffer, buffer->width, buffer->height,
1328 buffer->stride, buffer->format, buffer->usage, fence );
1329 cancel.buffer_id = buf->buffer_id;
1330 cancel.generation = buf->generation;
1331 cancel.hdr.hwnd = HandleToLong( win->hwnd );
1332 cancel.hdr.opengl = win->opengl;
1333 wait_fence_and_close( fence );
1334 return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL );
1337 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1339 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1340 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1341 struct ioctl_android_queueBuffer queue;
1343 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1344 win->hwnd, buffer, buffer->width, buffer->height,
1345 buffer->stride, buffer->format, buffer->usage, fence );
1346 queue.buffer_id = buf->buffer_id;
1347 queue.generation = buf->generation;
1348 queue.hdr.hwnd = HandleToLong( win->hwnd );
1349 queue.hdr.opengl = win->opengl;
1350 wait_fence_and_close( fence );
1351 return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL );
1354 static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer )
1356 int fence, ret = dequeueBuffer( window, buffer, &fence );
1358 if (!ret) wait_fence_and_close( fence );
1359 return ret;
1362 static int cancelBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1364 return cancelBuffer( window, buffer, -1 );
1367 static int lockBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1369 return 0; /* nothing to do */
1372 static int queueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1374 return queueBuffer( window, buffer, -1 );
1377 static int setSwapInterval( struct ANativeWindow *window, int interval )
1379 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1380 struct ioctl_android_set_swap_interval swap;
1382 TRACE( "hwnd %p interval %d\n", win->hwnd, interval );
1383 swap.hdr.hwnd = HandleToLong( win->hwnd );
1384 swap.hdr.opengl = win->opengl;
1385 swap.interval = interval;
1386 return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL );
1389 static int query( const ANativeWindow *window, int what, int *value )
1391 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1392 struct ioctl_android_query query;
1393 DWORD size = sizeof( query );
1394 int ret;
1396 query.hdr.hwnd = HandleToLong( win->hwnd );
1397 query.hdr.opengl = win->opengl;
1398 query.what = what;
1399 ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size );
1400 TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value );
1401 if (!ret) *value = query.value;
1402 return ret;
1405 static int perform( ANativeWindow *window, int operation, ... )
1407 static const char * const names[] =
1409 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
1410 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
1411 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
1412 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
1415 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1416 struct ioctl_android_perform perf;
1417 va_list args;
1419 perf.hdr.hwnd = HandleToLong( win->hwnd );
1420 perf.hdr.opengl = win->opengl;
1421 perf.operation = operation;
1422 memset( perf.args, 0, sizeof(perf.args) );
1424 va_start( args, operation );
1425 switch (operation)
1427 case NATIVE_WINDOW_SET_USAGE:
1428 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
1429 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
1430 case NATIVE_WINDOW_SET_SCALING_MODE:
1431 case NATIVE_WINDOW_API_CONNECT:
1432 case NATIVE_WINDOW_API_DISCONNECT:
1433 perf.args[0] = va_arg( args, int );
1434 TRACE( "hwnd %p %s arg %d\n", win->hwnd, names[operation], perf.args[0] );
1435 break;
1436 case NATIVE_WINDOW_SET_BUFFER_COUNT:
1437 perf.args[0] = va_arg( args, size_t );
1438 TRACE( "hwnd %p %s count %d\n", win->hwnd, names[operation], perf.args[0] );
1439 break;
1440 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
1441 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
1442 perf.args[0] = va_arg( args, int );
1443 perf.args[1] = va_arg( args, int );
1444 TRACE( "hwnd %p %s arg %dx%d\n", win->hwnd, names[operation], perf.args[0], perf.args[1] );
1445 break;
1446 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
1447 perf.args[0] = va_arg( args, int );
1448 perf.args[1] = va_arg( args, int );
1449 perf.args[2] = va_arg( args, int );
1450 TRACE( "hwnd %p %s arg %dx%d %d\n", win->hwnd, names[operation],
1451 perf.args[0], perf.args[1], perf.args[2] );
1452 break;
1453 case NATIVE_WINDOW_SET_CROP:
1455 android_native_rect_t *rect = va_arg( args, android_native_rect_t * );
1456 perf.args[0] = rect->left;
1457 perf.args[1] = rect->top;
1458 perf.args[2] = rect->right;
1459 perf.args[3] = rect->bottom;
1460 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win->hwnd, names[operation],
1461 perf.args[0], perf.args[1], perf.args[2], perf.args[3] );
1462 break;
1464 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
1466 int64_t timestamp = va_arg( args, int64_t );
1467 perf.args[0] = timestamp;
1468 perf.args[1] = timestamp >> 32;
1469 TRACE( "hwnd %p %s arg %08x%08x\n", win->hwnd, names[operation], perf.args[1], perf.args[0] );
1470 break;
1472 case NATIVE_WINDOW_LOCK:
1474 struct ANativeWindowBuffer *buffer;
1475 struct ANativeWindow_Buffer *buffer_ret = va_arg( args, ANativeWindow_Buffer * );
1476 ARect *bounds = va_arg( args, ARect * );
1477 int ret = window->dequeueBuffer_DEPRECATED( window, &buffer );
1478 if (!ret)
1480 if ((ret = gralloc_lock( buffer, &buffer_ret->bits )))
1482 WARN( "gralloc->lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
1483 window->cancelBuffer( window, buffer, -1 );
1486 if (!ret)
1488 buffer_ret->width = buffer->width;
1489 buffer_ret->height = buffer->height;
1490 buffer_ret->stride = buffer->stride;
1491 buffer_ret->format = buffer->format;
1492 win->locked_buffer = buffer;
1493 if (bounds)
1495 bounds->left = 0;
1496 bounds->top = 0;
1497 bounds->right = buffer->width;
1498 bounds->bottom = buffer->height;
1501 va_end( args );
1502 TRACE( "hwnd %p %s bits %p ret %d %s\n", win->hwnd, names[operation], buffer_ret->bits, ret, strerror(-ret) );
1503 return ret;
1505 case NATIVE_WINDOW_UNLOCK_AND_POST:
1507 int ret = -EINVAL;
1508 if (win->locked_buffer)
1510 gralloc_unlock( win->locked_buffer );
1511 ret = window->queueBuffer( window, win->locked_buffer, -1 );
1512 win->locked_buffer = NULL;
1514 va_end( args );
1515 TRACE( "hwnd %p %s ret %d\n", win->hwnd, names[operation], ret );
1516 return ret;
1518 case NATIVE_WINDOW_CONNECT:
1519 case NATIVE_WINDOW_DISCONNECT:
1520 TRACE( "hwnd %p %s\n", win->hwnd, names[operation] );
1521 break;
1522 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP:
1523 default:
1524 FIXME( "unsupported perform hwnd %p op %d %s\n", win->hwnd, operation,
1525 operation < ARRAY_SIZE( names ) ? names[operation] : "???" );
1526 break;
1528 va_end( args );
1529 return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL );
1532 struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl, float scale )
1534 struct ioctl_android_create_window req;
1535 struct native_win_wrapper *win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*win) );
1537 if (!win) return NULL;
1539 win->win.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
1540 win->win.common.version = sizeof(ANativeWindow);
1541 win->win.common.incRef = win_incRef;
1542 win->win.common.decRef = win_decRef;
1543 win->win.setSwapInterval = setSwapInterval;
1544 win->win.dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
1545 win->win.lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
1546 win->win.queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
1547 win->win.query = query;
1548 win->win.perform = perform;
1549 win->win.cancelBuffer_DEPRECATED = cancelBuffer_DEPRECATED;
1550 win->win.dequeueBuffer = dequeueBuffer;
1551 win->win.queueBuffer = queueBuffer;
1552 win->win.cancelBuffer = cancelBuffer;
1553 win->ref = 1;
1554 win->hwnd = hwnd;
1555 win->opengl = opengl;
1556 TRACE( "-> %p %p opengl=%u\n", win, win->hwnd, opengl );
1558 req.hdr.hwnd = HandleToLong( win->hwnd );
1559 req.hdr.opengl = win->opengl;
1560 req.parent = get_ioctl_win_parent( GetAncestor( hwnd, GA_PARENT ));
1561 req.scale = scale;
1562 android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
1564 return &win->win;
1567 struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window )
1569 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1570 InterlockedIncrement( &win->ref );
1571 return window;
1574 void release_ioctl_window( struct ANativeWindow *window )
1576 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1577 unsigned int i;
1579 if (InterlockedDecrement( &win->ref ) > 0) return;
1581 TRACE( "%p %p\n", win, win->hwnd );
1582 for (i = 0; i < ARRAY_SIZE( win->buffers ); i++)
1583 if (win->buffers[i]) win->buffers[i]->buffer.common.decRef( &win->buffers[i]->buffer.common );
1585 destroy_ioctl_window( win->hwnd, win->opengl );
1586 HeapFree( GetProcessHeap(), 0, win );
1589 void destroy_ioctl_window( HWND hwnd, BOOL opengl )
1591 struct ioctl_android_destroy_window req;
1593 req.hdr.hwnd = HandleToLong( hwnd );
1594 req.hdr.opengl = opengl;
1595 android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
1598 int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect,
1599 const RECT *visible_rect, UINT style, UINT flags, HWND after, HWND owner )
1601 struct ioctl_android_window_pos_changed req;
1603 req.hdr.hwnd = HandleToLong( hwnd );
1604 req.hdr.opengl = FALSE;
1605 req.window_rect = *window_rect;
1606 req.client_rect = *client_rect;
1607 req.visible_rect = *visible_rect;
1608 req.style = style;
1609 req.flags = flags;
1610 req.after = HandleToLong( after );
1611 req.owner = HandleToLong( owner );
1612 return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );
1615 int ioctl_set_window_parent( HWND hwnd, HWND parent, float scale )
1617 struct ioctl_android_set_window_parent req;
1619 req.hdr.hwnd = HandleToLong( hwnd );
1620 req.hdr.opengl = FALSE;
1621 req.parent = get_ioctl_win_parent( parent );
1622 req.scale = scale;
1623 return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL );
1626 int ioctl_set_capture( HWND hwnd )
1628 struct ioctl_android_set_capture req;
1630 req.hdr.hwnd = HandleToLong( hwnd );
1631 req.hdr.opengl = FALSE;
1632 return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );
1635 int ioctl_set_cursor( int id, int width, int height,
1636 int hotspotx, int hotspoty, const unsigned int *bits )
1638 struct ioctl_android_set_cursor *req;
1639 unsigned int size = offsetof( struct ioctl_android_set_cursor, bits[width * height] );
1640 int ret;
1642 if (!(req = HeapAlloc( GetProcessHeap(), 0, size ))) return -ENOMEM;
1643 req->hdr.hwnd = 0; /* unused */
1644 req->hdr.opengl = FALSE;
1645 req->id = id;
1646 req->width = width;
1647 req->height = height;
1648 req->hotspotx = hotspotx;
1649 req->hotspoty = hotspoty;
1650 memcpy( req->bits, bits, width * height * sizeof(req->bits[0]) );
1651 ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL );
1652 HeapFree( GetProcessHeap(), 0, req );
1653 return ret;