windowscodecs: Directly use patterns stored in component info object in IWICBitmapDec...
[wine.git] / dlls / wineandroid.drv / device.c
blob0ccae1130c750984ab9199b3f14844d415586e06
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/library.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 extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
52 static HANDLE stop_event;
53 static HANDLE thread;
54 static JNIEnv *jni_env;
55 static HWND capture_window;
57 #define ANDROIDCONTROLTYPE ((ULONG)'A')
58 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
60 enum android_ioctl
62 IOCTL_CREATE_WINDOW,
63 IOCTL_DESTROY_WINDOW,
64 IOCTL_WINDOW_POS_CHANGED,
65 IOCTL_SET_WINDOW_PARENT,
66 IOCTL_DEQUEUE_BUFFER,
67 IOCTL_QUEUE_BUFFER,
68 IOCTL_CANCEL_BUFFER,
69 IOCTL_QUERY,
70 IOCTL_PERFORM,
71 IOCTL_SET_SWAP_INT,
72 IOCTL_SET_CAPTURE,
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;
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;
208 struct ioctl_android_set_capture
210 struct ioctl_header hdr;
213 static inline BOOL is_in_desktop_process(void)
215 return thread != NULL;
218 static inline DWORD current_client_id(void)
220 return HandleToUlong( PsGetCurrentProcessId() );
223 static inline BOOL is_client_in_process(void)
225 return current_client_id() == GetCurrentProcessId();
228 #ifdef __i386__ /* the Java VM uses %fs for its own purposes, so we need to wrap the calls */
229 static WORD orig_fs, java_fs;
230 static inline void wrap_java_call(void) { wine_set_fs( java_fs ); }
231 static inline void unwrap_java_call(void) { wine_set_fs( orig_fs ); }
232 #else
233 static inline void wrap_java_call(void) { }
234 static inline void unwrap_java_call(void) { }
235 #endif /* __i386__ */
237 static struct native_win_data *data_map[65536];
239 static unsigned int data_map_idx( HWND hwnd, BOOL opengl )
241 /* window handles are always even, so use low-order bit for opengl flag */
242 return LOWORD(hwnd) + !!opengl;
245 static struct native_win_data *get_native_win_data( HWND hwnd, BOOL opengl )
247 struct native_win_data *data = data_map[data_map_idx( hwnd, opengl )];
249 if (data && data->hwnd == hwnd && !data->opengl == !opengl) return data;
250 WARN( "unknown win %p opengl %u\n", hwnd, opengl );
251 return NULL;
254 static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr )
256 return get_native_win_data( LongToHandle(hdr->hwnd), hdr->opengl );
259 static int get_ioctl_win_parent( HWND parent )
261 if (parent != GetDesktopWindow() && !GetAncestor( parent, GA_PARENT ))
262 return HandleToLong( HWND_MESSAGE );
263 return HandleToLong( parent );
266 static void wait_fence_and_close( int fence )
268 __s32 timeout = 1000; /* FIXME: should be -1 for infinite timeout */
270 if (fence == -1) return;
271 ioctl( fence, SYNC_IOC_WAIT, &timeout );
272 close( fence );
275 static int duplicate_fd( HANDLE client, int fd )
277 HANDLE handle, ret = 0;
279 if (!wine_server_fd_to_handle( dup(fd), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
280 DuplicateHandle( GetCurrentProcess(), handle, client, &ret,
281 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE );
283 if (!ret) return -1;
284 return HandleToLong( ret );
287 static int map_native_handle( union native_handle_buffer *dest, const native_handle_t *src,
288 HANDLE mapping, HANDLE client )
290 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
291 int i;
293 if (mapping) /* only duplicate the mapping handle */
295 HANDLE ret = 0;
296 if (!DuplicateHandle( GetCurrentProcess(), mapping, client, &ret,
297 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE ))
298 return -ENOSPC;
299 dest->handle.numFds = 0;
300 dest->handle.numInts = 1;
301 dest->handle.data[0] = HandleToLong( ret );
302 return 0;
304 if (is_client_in_process()) /* transfer the actual handle pointer */
306 dest->handle.numFds = 0;
307 dest->handle.numInts = sizeof(src) / sizeof(int);
308 memcpy( dest->handle.data, &src, sizeof(src) );
309 return 0;
311 if (size > sizeof(*dest)) return -ENOSPC;
312 memcpy( dest, src, size );
313 /* transfer file descriptors to the client process */
314 for (i = 0; i < dest->handle.numFds; i++)
315 dest->handle.data[i] = duplicate_fd( client, src->data[i] );
316 return 0;
319 static native_handle_t *unmap_native_handle( const native_handle_t *src )
321 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
322 native_handle_t *dest;
323 int i;
325 if (!is_in_desktop_process())
327 dest = HeapAlloc( GetProcessHeap(), 0, size );
328 memcpy( dest, src, size );
329 /* fetch file descriptors passed from the server process */
330 for (i = 0; i < dest->numFds; i++)
331 wine_server_handle_to_fd( LongToHandle(src->data[i]), GENERIC_READ | SYNCHRONIZE,
332 &dest->data[i], NULL );
334 else memcpy( &dest, src->data, sizeof(dest) );
335 return dest;
338 static void close_native_handle( native_handle_t *handle )
340 int i;
342 for (i = 0; i < handle->numFds; i++) close( handle->data[i] );
343 HeapFree( GetProcessHeap(), 0, handle );
346 /* insert a buffer index at the head of the LRU list */
347 static void insert_buffer_lru( struct native_win_data *win, int index )
349 unsigned int i;
351 for (i = 0; i < NB_CACHED_BUFFERS; i++)
353 if (win->buffer_lru[i] == index) break;
354 if (win->buffer_lru[i] == -1) break;
357 assert( i < NB_CACHED_BUFFERS );
358 memmove( win->buffer_lru + 1, win->buffer_lru, i * sizeof(win->buffer_lru[0]) );
359 win->buffer_lru[0] = index;
362 static int register_buffer( struct native_win_data *win, struct ANativeWindowBuffer *buffer,
363 HANDLE *mapping, int *is_new )
365 unsigned int i;
367 *is_new = 0;
368 for (i = 0; i < NB_CACHED_BUFFERS; i++)
370 if (win->buffers[i] == buffer) goto done;
371 if (!win->buffers[i]) break;
374 if (i == NB_CACHED_BUFFERS)
376 /* reuse the least recently used buffer */
377 i = win->buffer_lru[NB_CACHED_BUFFERS - 1];
378 assert( i < NB_CACHED_BUFFERS );
380 TRACE( "%p %p evicting buffer %p id %d from cache\n",
381 win->hwnd, win->parent, win->buffers[i], i );
382 win->buffers[i]->common.decRef( &win->buffers[i]->common );
383 if (win->mappings[i]) UnmapViewOfFile( win->mappings[i] );
386 win->buffers[i] = buffer;
387 win->mappings[i] = NULL;
389 if (mapping)
391 *mapping = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
392 buffer->stride * buffer->height * 4, NULL );
393 win->mappings[i] = MapViewOfFile( *mapping, FILE_MAP_READ, 0, 0, 0 );
395 buffer->common.incRef( &buffer->common );
396 *is_new = 1;
397 TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i );
399 done:
400 insert_buffer_lru( win, i );
401 return i;
404 static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data *win, int id )
406 if (id < 0 || id >= NB_CACHED_BUFFERS || !win->buffers[id])
408 ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent );
409 return NULL;
411 return win->buffers[id];
414 static void release_native_window( struct native_win_data *data )
416 unsigned int i;
418 if (data->parent) pANativeWindow_release( data->parent );
419 for (i = 0; i < NB_CACHED_BUFFERS; i++)
421 if (data->buffers[i]) data->buffers[i]->common.decRef( &data->buffers[i]->common );
422 if (data->mappings[i]) UnmapViewOfFile( data->mappings[i] );
423 data->buffer_lru[i] = -1;
425 memset( data->buffers, 0, sizeof(data->buffers) );
426 memset( data->mappings, 0, sizeof(data->mappings) );
429 static void free_native_win_data( struct native_win_data *data )
431 unsigned int idx = data_map_idx( data->hwnd, data->opengl );
433 InterlockedCompareExchangePointer( (void **)&capture_window, 0, data->hwnd );
434 release_native_window( data );
435 HeapFree( GetProcessHeap(), 0, data );
436 data_map[idx] = NULL;
439 static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl )
441 unsigned int i, idx = data_map_idx( hwnd, opengl );
442 struct native_win_data *data = data_map[idx];
444 if (data)
446 WARN( "data for %p not freed correctly\n", data->hwnd );
447 free_native_win_data( data );
449 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return NULL;
450 data->hwnd = hwnd;
451 data->opengl = opengl;
452 if (!opengl) data->api = NATIVE_WINDOW_API_CPU;
453 data->buffer_format = PF_BGRA_8888;
454 data_map[idx] = data;
455 for (i = 0; i < NB_CACHED_BUFFERS; i++) data->buffer_lru[i] = -1;
456 return data;
459 static void CALLBACK register_native_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
461 HWND hwnd = (HWND)arg1;
462 struct ANativeWindow *win = (struct ANativeWindow *)arg2;
463 BOOL opengl = arg3;
464 struct native_win_data *data = get_native_win_data( hwnd, opengl );
466 if (!win) return; /* do nothing and hold on to the window until we get a new surface */
468 if (!data || data->parent == win)
470 if (win) pANativeWindow_release( win );
471 if (data && win) PostMessageW( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
472 TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win );
473 return;
476 release_native_window( data );
477 data->parent = win;
478 data->generation++;
479 if (win)
481 wrap_java_call();
482 if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api );
483 win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format );
484 win->setSwapInterval( win, data->swap_interval );
485 unwrap_java_call();
486 PostMessageW( hwnd, WM_ANDROID_REFRESH, opengl, 0 );
488 TRACE( "%p -> %p win %p\n", hwnd, data, win );
491 /* register a native window received from the Java side for use in ioctls */
492 void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl )
494 NtQueueApcThread( thread, register_native_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl );
497 /* get the capture window stored in the desktop process */
498 HWND get_capture_window(void)
500 return capture_window;
503 static NTSTATUS android_error_to_status( int err )
505 switch (err)
507 case 0: return STATUS_SUCCESS;
508 case -ENOMEM: return STATUS_NO_MEMORY;
509 case -ENOSYS: return STATUS_NOT_SUPPORTED;
510 case -EINVAL: return STATUS_INVALID_PARAMETER;
511 case -ENOENT: return STATUS_INVALID_HANDLE;
512 case -EPERM: return STATUS_ACCESS_DENIED;
513 case -ENODEV: return STATUS_NO_SUCH_DEVICE;
514 case -EEXIST: return STATUS_DUPLICATE_NAME;
515 case -EPIPE: return STATUS_PIPE_DISCONNECTED;
516 case -ENODATA: return STATUS_NO_MORE_FILES;
517 case -ETIMEDOUT: return STATUS_IO_TIMEOUT;
518 case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST;
519 case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
520 default:
521 FIXME( "unmapped error %d\n", err );
522 return STATUS_UNSUCCESSFUL;
526 static int status_to_android_error( NTSTATUS status )
528 switch (status)
530 case STATUS_SUCCESS: return 0;
531 case STATUS_NO_MEMORY: return -ENOMEM;
532 case STATUS_NOT_SUPPORTED: return -ENOSYS;
533 case STATUS_INVALID_PARAMETER: return -EINVAL;
534 case STATUS_BUFFER_OVERFLOW: return -EINVAL;
535 case STATUS_INVALID_HANDLE: return -ENOENT;
536 case STATUS_ACCESS_DENIED: return -EPERM;
537 case STATUS_NO_SUCH_DEVICE: return -ENODEV;
538 case STATUS_DUPLICATE_NAME: return -EEXIST;
539 case STATUS_PIPE_DISCONNECTED: return -EPIPE;
540 case STATUS_NO_MORE_FILES: return -ENODATA;
541 case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
542 case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
543 case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
544 default:
545 FIXME( "unmapped status %08x\n", status );
546 return -EINVAL;
550 static jobject load_java_method( jmethodID *method, const char *name, const char *args )
552 jobject object = wine_get_java_object();
554 if (!*method)
556 jclass class;
558 wrap_java_call();
559 class = (*jni_env)->GetObjectClass( jni_env, object );
560 *method = (*jni_env)->GetMethodID( jni_env, class, name, args );
561 unwrap_java_call();
562 if (!*method)
564 FIXME( "method %s not found\n", name );
565 return NULL;
568 return object;
571 static void create_desktop_window( HWND hwnd )
573 static jmethodID method;
574 jobject object;
576 if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
578 wrap_java_call();
579 (*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
580 unwrap_java_call();
583 static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
585 static jmethodID method;
586 jobject object;
587 struct ioctl_android_create_window *res = data;
588 struct native_win_data *win_data;
589 DWORD pid = current_client_id();
591 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
593 if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd), res->hdr.opengl )))
594 return STATUS_NO_MEMORY;
596 TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent );
598 if (!(object = load_java_method( &method, "createWindow", "(IZII)V" ))) return STATUS_NOT_SUPPORTED;
600 wrap_java_call();
601 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->hdr.opengl, res->parent, pid );
602 unwrap_java_call();
603 return STATUS_SUCCESS;
606 static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
608 static jmethodID method;
609 jobject object;
610 struct ioctl_android_destroy_window *res = data;
611 struct native_win_data *win_data;
613 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
615 win_data = get_ioctl_native_win_data( &res->hdr );
617 TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl );
619 if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
621 wrap_java_call();
622 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
623 unwrap_java_call();
624 if (win_data) free_native_win_data( win_data );
625 return STATUS_SUCCESS;
628 static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
630 static jmethodID method;
631 jobject object;
632 struct ioctl_android_window_pos_changed *res = data;
634 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
636 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
637 res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect),
638 wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner );
640 if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
641 return STATUS_NOT_SUPPORTED;
643 wrap_java_call();
644 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style,
645 res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom,
646 res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom,
647 res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom );
648 unwrap_java_call();
649 return STATUS_SUCCESS;
652 static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
654 struct ANativeWindow *parent;
655 struct ioctl_android_dequeueBuffer *res = data;
656 struct native_win_data *win_data;
657 struct ANativeWindowBuffer *buffer;
658 int fence, ret, is_new;
660 if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW;
662 if (in_size < offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
663 return STATUS_INVALID_PARAMETER;
665 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
666 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
668 *ret_size = offsetof( struct ioctl_android_dequeueBuffer, native_handle );
669 wrap_java_call();
670 ret = parent->dequeueBuffer( parent, &buffer, &fence );
671 unwrap_java_call();
672 if (!ret)
674 HANDLE mapping = 0;
676 TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
677 res->width = buffer->width;
678 res->height = buffer->height;
679 res->stride = buffer->stride;
680 res->format = buffer->format;
681 res->usage = buffer->usage;
682 res->buffer_id = register_buffer( win_data, buffer, res->win32 ? &mapping : NULL, &is_new );
683 res->generation = win_data->generation;
684 if (is_new)
686 HANDLE process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, current_client_id() );
687 map_native_handle( &res->native_handle, buffer->handle, mapping, process );
688 CloseHandle( process );
689 *ret_size = sizeof( *res );
691 wait_fence_and_close( fence );
692 return STATUS_SUCCESS;
694 ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
695 return android_error_to_status( ret );
698 static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
700 struct ioctl_android_cancelBuffer *res = data;
701 struct ANativeWindow *parent;
702 struct ANativeWindowBuffer *buffer;
703 struct native_win_data *win_data;
704 int ret;
706 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
708 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
709 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
710 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
712 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
714 TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer );
715 wrap_java_call();
716 ret = parent->cancelBuffer( parent, buffer, -1 );
717 unwrap_java_call();
718 return android_error_to_status( ret );
721 static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
723 struct ioctl_android_queueBuffer *res = data;
724 struct ANativeWindow *parent;
725 struct ANativeWindowBuffer *buffer;
726 struct native_win_data *win_data;
727 int ret;
729 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
731 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
732 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
733 if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */
735 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
737 TRACE( "%08x buffer %p mapping %p\n", res->hdr.hwnd, buffer, win_data->mappings[res->buffer_id] );
738 if (win_data->mappings[res->buffer_id])
740 void *bits;
741 int ret = gralloc_module->lock( gralloc_module, buffer->handle,
742 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
743 0, 0, buffer->width, buffer->height, &bits );
744 if (ret) return android_error_to_status( ret );
745 memcpy( bits, win_data->mappings[res->buffer_id], buffer->stride * buffer->height * 4 );
746 gralloc_module->unlock( gralloc_module, buffer->handle );
748 wrap_java_call();
749 ret = parent->queueBuffer( parent, buffer, -1 );
750 unwrap_java_call();
751 return android_error_to_status( ret );
754 static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
756 struct ioctl_android_query *res = data;
757 struct ANativeWindow *parent;
758 struct native_win_data *win_data;
759 int ret;
761 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
762 if (out_size < sizeof(*res)) return STATUS_BUFFER_OVERFLOW;
764 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
765 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
767 *ret_size = sizeof( *res );
768 wrap_java_call();
769 ret = parent->query( parent, res->what, &res->value );
770 unwrap_java_call();
771 return android_error_to_status( ret );
774 static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
776 struct ioctl_android_perform *res = data;
777 struct ANativeWindow *parent;
778 struct native_win_data *win_data;
779 int ret = -ENOENT;
781 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
783 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
784 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
786 switch (res->operation)
788 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
789 wrap_java_call();
790 ret = parent->perform( parent, res->operation, res->args[0] );
791 unwrap_java_call();
792 if (!ret) win_data->buffer_format = res->args[0];
793 break;
794 case NATIVE_WINDOW_API_CONNECT:
795 wrap_java_call();
796 ret = parent->perform( parent, res->operation, res->args[0] );
797 unwrap_java_call();
798 if (!ret) win_data->api = res->args[0];
799 break;
800 case NATIVE_WINDOW_API_DISCONNECT:
801 wrap_java_call();
802 ret = parent->perform( parent, res->operation, res->args[0] );
803 unwrap_java_call();
804 if (!ret) win_data->api = 0;
805 break;
806 case NATIVE_WINDOW_SET_USAGE:
807 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
808 case NATIVE_WINDOW_SET_SCALING_MODE:
809 wrap_java_call();
810 ret = parent->perform( parent, res->operation, res->args[0] );
811 unwrap_java_call();
812 break;
813 case NATIVE_WINDOW_SET_BUFFER_COUNT:
814 wrap_java_call();
815 ret = parent->perform( parent, res->operation, (size_t)res->args[0] );
816 unwrap_java_call();
817 break;
818 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
819 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
820 wrap_java_call();
821 ret = parent->perform( parent, res->operation, res->args[0], res->args[1] );
822 unwrap_java_call();
823 break;
824 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
825 wrap_java_call();
826 ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] );
827 unwrap_java_call();
828 break;
829 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
830 wrap_java_call();
831 ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) );
832 unwrap_java_call();
833 break;
834 case NATIVE_WINDOW_CONNECT:
835 case NATIVE_WINDOW_DISCONNECT:
836 case NATIVE_WINDOW_UNLOCK_AND_POST:
837 wrap_java_call();
838 ret = parent->perform( parent, res->operation );
839 unwrap_java_call();
840 break;
841 case NATIVE_WINDOW_SET_CROP:
843 android_native_rect_t rect;
844 rect.left = res->args[0];
845 rect.top = res->args[1];
846 rect.right = res->args[2];
847 rect.bottom = res->args[3];
848 wrap_java_call();
849 ret = parent->perform( parent, res->operation, &rect );
850 unwrap_java_call();
851 break;
853 case NATIVE_WINDOW_LOCK:
854 default:
855 FIXME( "unsupported perform op %d\n", res->operation );
856 break;
858 return android_error_to_status( ret );
861 static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
863 struct ioctl_android_set_swap_interval *res = data;
864 struct ANativeWindow *parent;
865 struct native_win_data *win_data;
866 int ret;
868 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
870 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
871 win_data->swap_interval = res->interval;
873 if (!(parent = win_data->parent)) return STATUS_SUCCESS;
874 wrap_java_call();
875 ret = parent->setSwapInterval( parent, res->interval );
876 unwrap_java_call();
877 return android_error_to_status( ret );
880 static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
882 static jmethodID method;
883 jobject object;
884 struct ioctl_android_set_window_parent *res = data;
885 struct native_win_data *win_data;
886 DWORD pid = current_client_id();
888 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
890 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
892 TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
894 if (!(object = load_java_method( &method, "setParent", "(III)V" ))) return STATUS_NOT_SUPPORTED;
896 wrap_java_call();
897 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
898 unwrap_java_call();
899 return STATUS_SUCCESS;
902 static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
904 struct ioctl_android_set_capture *res = data;
906 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
908 if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE;
910 TRACE( "hwnd %08x\n", res->hdr.hwnd );
912 InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd ));
913 return STATUS_SUCCESS;
916 typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
917 static const ioctl_func ioctl_funcs[] =
919 createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
920 destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
921 windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */
922 setWindowParent_ioctl, /* IOCTL_SET_WINDOW_PARENT */
923 dequeueBuffer_ioctl, /* IOCTL_DEQUEUE_BUFFER */
924 queueBuffer_ioctl, /* IOCTL_QUEUE_BUFFER */
925 cancelBuffer_ioctl, /* IOCTL_CANCEL_BUFFER */
926 query_ioctl, /* IOCTL_QUERY */
927 perform_ioctl, /* IOCTL_PERFORM */
928 setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
929 setCapture_ioctl, /* IOCTL_SET_CAPTURE */
932 static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
934 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
935 DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
937 if (code < NB_IOCTLS)
939 struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
940 DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
941 ioctl_func func = ioctl_funcs[code];
943 if (in_size >= sizeof(*header))
945 irp->IoStatus.Information = 0;
946 irp->IoStatus.u.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
947 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
948 &irp->IoStatus.Information );
950 else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
952 else
954 FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
955 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
957 IoCompleteRequest( irp, IO_NO_INCREMENT );
958 return STATUS_SUCCESS;
961 static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name )
963 static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
964 static const WCHAR device_linkW[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
966 UNICODE_STRING nameW, linkW;
967 DEVICE_OBJECT *device;
968 NTSTATUS status;
970 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback;
972 RtlInitUnicodeString( &nameW, device_nameW );
973 RtlInitUnicodeString( &linkW, device_linkW );
975 if ((status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ))) return status;
976 return IoCreateSymbolicLink( &linkW, &nameW );
979 static DWORD CALLBACK device_thread( void *arg )
981 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
983 HANDLE start_event = arg;
984 UNICODE_STRING nameW;
985 NTSTATUS status;
986 JavaVM *java_vm;
987 DWORD ret;
989 TRACE( "starting process %x\n", GetCurrentProcessId() );
991 if (!(java_vm = wine_get_java_vm())) return 0; /* not running under Java */
993 #ifdef __i386__
994 orig_fs = wine_get_fs();
995 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
996 java_fs = wine_get_fs();
997 wine_set_fs( orig_fs );
998 if (java_fs != orig_fs) TRACE( "%%fs changed from %04x to %04x by Java VM\n", orig_fs, java_fs );
999 #else
1000 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
1001 #endif
1003 create_desktop_window( GetDesktopWindow() );
1005 RtlInitUnicodeString( &nameW, driver_nameW );
1006 if ((status = IoCreateDriver( &nameW, init_android_driver )))
1008 FIXME( "failed to create driver error %x\n", status );
1009 return status;
1012 stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
1013 SetEvent( start_event );
1015 ret = wine_ntoskrnl_main_loop( stop_event );
1017 (*java_vm)->DetachCurrentThread( java_vm );
1018 return ret;
1021 void start_android_device(void)
1023 HANDLE handles[2];
1025 handles[0] = CreateEventW( NULL, TRUE, FALSE, NULL );
1026 handles[1] = thread = CreateThread( NULL, 0, device_thread, handles[0], 0, NULL );
1027 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
1028 CloseHandle( handles[0] );
1032 /* Client-side ioctl support */
1035 static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
1037 static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1038 static HANDLE device;
1039 IO_STATUS_BLOCK iosb;
1040 NTSTATUS status;
1042 if (!device)
1044 HANDLE file = CreateFileW( deviceW, GENERIC_READ,
1045 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1046 if (file == INVALID_HANDLE_VALUE) return -ENOENT;
1047 if (InterlockedCompareExchangePointer( &device, file, NULL )) CloseHandle( file );
1050 status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
1051 in, in_size, out, out_size ? *out_size : 0 );
1052 if (status == STATUS_FILE_DELETED)
1054 WARN( "parent process is gone\n" );
1055 ExitProcess( 1 );
1057 if (out_size) *out_size = iosb.Information;
1058 return status_to_android_error( status );
1061 static void win_incRef( struct android_native_base_t *base )
1063 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1064 InterlockedIncrement( &win->ref );
1067 static void win_decRef( struct android_native_base_t *base )
1069 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1070 InterlockedDecrement( &win->ref );
1073 static void buffer_incRef( struct android_native_base_t *base )
1075 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1076 InterlockedIncrement( &buffer->ref );
1079 static void buffer_decRef( struct android_native_base_t *base )
1081 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1083 if (!InterlockedDecrement( &buffer->ref ))
1085 if (!is_in_desktop_process())
1087 if (gralloc_module) gralloc_module->unregisterBuffer( gralloc_module, buffer->buffer.handle );
1088 close_native_handle( (native_handle_t *)buffer->buffer.handle );
1090 if (buffer->bits) UnmapViewOfFile( buffer->bits );
1091 HeapFree( GetProcessHeap(), 0, buffer );
1095 static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence )
1097 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1098 struct ioctl_android_dequeueBuffer res;
1099 DWORD size = sizeof(res);
1100 int ret, use_win32 = !gralloc_module;
1102 res.hdr.hwnd = HandleToLong( win->hwnd );
1103 res.hdr.opengl = win->opengl;
1104 res.win32 = use_win32;
1105 ret = android_ioctl( IOCTL_DEQUEUE_BUFFER,
1106 &res, offsetof( struct ioctl_android_dequeueBuffer, native_handle ),
1107 &res, &size );
1108 if (ret) return ret;
1110 /* if we received the native handle, this is a new buffer */
1111 if (size > offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
1113 struct native_buffer_wrapper *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buf) );
1115 buf->buffer.common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
1116 buf->buffer.common.version = sizeof( buf->buffer );
1117 buf->buffer.common.incRef = buffer_incRef;
1118 buf->buffer.common.decRef = buffer_decRef;
1119 buf->buffer.width = res.width;
1120 buf->buffer.height = res.height;
1121 buf->buffer.stride = res.stride;
1122 buf->buffer.format = res.format;
1123 buf->buffer.usage = res.usage;
1124 buf->buffer.handle = unmap_native_handle( &res.native_handle.handle );
1125 buf->ref = 1;
1126 buf->hwnd = win->hwnd;
1127 buf->buffer_id = res.buffer_id;
1128 buf->generation = res.generation;
1129 if (win->buffers[res.buffer_id])
1130 win->buffers[res.buffer_id]->buffer.common.decRef(&win->buffers[res.buffer_id]->buffer.common);
1131 win->buffers[res.buffer_id] = buf;
1133 if (use_win32)
1135 HANDLE mapping = LongToHandle( res.native_handle.handle.data[0] );
1136 buf->bits = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
1137 CloseHandle( mapping );
1139 else if (!is_in_desktop_process())
1141 if ((ret = gralloc_module->registerBuffer( gralloc_module, buf->buffer.handle )) < 0)
1142 WARN( "hwnd %p, buffer %p failed to register %d %s\n", win->hwnd, &buf->buffer, ret, strerror(-ret) );
1146 *buffer = &win->buffers[res.buffer_id]->buffer;
1147 *fence = -1;
1149 TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1150 win->hwnd, *buffer, res.width, res.height, res.stride, res.format, res.usage, *fence );
1151 return 0;
1154 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1156 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1157 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1158 struct ioctl_android_cancelBuffer cancel;
1160 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1161 win->hwnd, buffer, buffer->width, buffer->height,
1162 buffer->stride, buffer->format, buffer->usage, fence );
1163 cancel.buffer_id = buf->buffer_id;
1164 cancel.generation = buf->generation;
1165 cancel.hdr.hwnd = HandleToLong( win->hwnd );
1166 cancel.hdr.opengl = win->opengl;
1167 wait_fence_and_close( fence );
1168 return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL );
1171 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1173 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1174 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1175 struct ioctl_android_queueBuffer queue;
1177 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1178 win->hwnd, buffer, buffer->width, buffer->height,
1179 buffer->stride, buffer->format, buffer->usage, fence );
1180 queue.buffer_id = buf->buffer_id;
1181 queue.generation = buf->generation;
1182 queue.hdr.hwnd = HandleToLong( win->hwnd );
1183 queue.hdr.opengl = win->opengl;
1184 wait_fence_and_close( fence );
1185 return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL );
1188 static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer )
1190 int fence, ret = dequeueBuffer( window, buffer, &fence );
1192 if (!ret) wait_fence_and_close( fence );
1193 return ret;
1196 static int cancelBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1198 return cancelBuffer( window, buffer, -1 );
1201 static int lockBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1203 return 0; /* nothing to do */
1206 static int queueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1208 return queueBuffer( window, buffer, -1 );
1211 static int setSwapInterval( struct ANativeWindow *window, int interval )
1213 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1214 struct ioctl_android_set_swap_interval swap;
1216 TRACE( "hwnd %p interval %d\n", win->hwnd, interval );
1217 swap.hdr.hwnd = HandleToLong( win->hwnd );
1218 swap.hdr.opengl = win->opengl;
1219 swap.interval = interval;
1220 return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL );
1223 static int query( const ANativeWindow *window, int what, int *value )
1225 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1226 struct ioctl_android_query query;
1227 DWORD size = sizeof( query );
1228 int ret;
1230 query.hdr.hwnd = HandleToLong( win->hwnd );
1231 query.hdr.opengl = win->opengl;
1232 query.what = what;
1233 ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size );
1234 TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value );
1235 if (!ret) *value = query.value;
1236 return ret;
1239 static int perform( ANativeWindow *window, int operation, ... )
1241 static const char * const names[] =
1243 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
1244 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
1245 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
1246 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
1249 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1250 struct ioctl_android_perform perf;
1251 va_list args;
1253 perf.hdr.hwnd = HandleToLong( win->hwnd );
1254 perf.hdr.opengl = win->opengl;
1255 perf.operation = operation;
1256 memset( perf.args, 0, sizeof(perf.args) );
1258 va_start( args, operation );
1259 switch (operation)
1261 case NATIVE_WINDOW_SET_USAGE:
1262 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
1263 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
1264 case NATIVE_WINDOW_SET_SCALING_MODE:
1265 case NATIVE_WINDOW_API_CONNECT:
1266 case NATIVE_WINDOW_API_DISCONNECT:
1267 perf.args[0] = va_arg( args, int );
1268 TRACE( "hwnd %p %s arg %d\n", win->hwnd, names[operation], perf.args[0] );
1269 break;
1270 case NATIVE_WINDOW_SET_BUFFER_COUNT:
1271 perf.args[0] = va_arg( args, size_t );
1272 TRACE( "hwnd %p %s count %d\n", win->hwnd, names[operation], perf.args[0] );
1273 break;
1274 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
1275 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
1276 perf.args[0] = va_arg( args, int );
1277 perf.args[1] = va_arg( args, int );
1278 TRACE( "hwnd %p %s arg %dx%d\n", win->hwnd, names[operation], perf.args[0], perf.args[1] );
1279 break;
1280 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
1281 perf.args[0] = va_arg( args, int );
1282 perf.args[1] = va_arg( args, int );
1283 perf.args[2] = va_arg( args, int );
1284 TRACE( "hwnd %p %s arg %dx%d %d\n", win->hwnd, names[operation],
1285 perf.args[0], perf.args[1], perf.args[2] );
1286 break;
1287 case NATIVE_WINDOW_SET_CROP:
1289 android_native_rect_t *rect = va_arg( args, android_native_rect_t * );
1290 perf.args[0] = rect->left;
1291 perf.args[1] = rect->top;
1292 perf.args[2] = rect->right;
1293 perf.args[3] = rect->bottom;
1294 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win->hwnd, names[operation],
1295 perf.args[0], perf.args[1], perf.args[2], perf.args[3] );
1296 break;
1298 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
1300 int64_t timestamp = va_arg( args, int64_t );
1301 perf.args[0] = timestamp;
1302 perf.args[1] = timestamp >> 32;
1303 TRACE( "hwnd %p %s arg %08x%08x\n", win->hwnd, names[operation], perf.args[1], perf.args[0] );
1304 break;
1306 case NATIVE_WINDOW_LOCK:
1308 struct ANativeWindowBuffer *buffer;
1309 struct ANativeWindow_Buffer *buffer_ret = va_arg( args, ANativeWindow_Buffer * );
1310 ARect *bounds = va_arg( args, ARect * );
1311 int ret = window->dequeueBuffer_DEPRECATED( window, &buffer );
1312 if (!ret)
1314 if (gralloc_module)
1316 if ((ret = gralloc_module->lock( gralloc_module, buffer->handle,
1317 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
1318 0, 0, buffer->width, buffer->height, &buffer_ret->bits )))
1320 WARN( "gralloc->lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
1321 window->cancelBuffer( window, buffer, -1 );
1324 else
1325 buffer_ret->bits = ((struct native_buffer_wrapper *)buffer)->bits;
1327 if (!ret)
1329 buffer_ret->width = buffer->width;
1330 buffer_ret->height = buffer->height;
1331 buffer_ret->stride = buffer->stride;
1332 buffer_ret->format = buffer->format;
1333 win->locked_buffer = buffer;
1334 if (bounds)
1336 bounds->left = 0;
1337 bounds->top = 0;
1338 bounds->right = buffer->width;
1339 bounds->bottom = buffer->height;
1342 va_end( args );
1343 TRACE( "hwnd %p %s bits %p ret %d %s\n", win->hwnd, names[operation], buffer_ret->bits, ret, strerror(-ret) );
1344 return ret;
1346 case NATIVE_WINDOW_UNLOCK_AND_POST:
1348 int ret = -EINVAL;
1349 if (win->locked_buffer)
1351 if (gralloc_module) gralloc_module->unlock( gralloc_module, win->locked_buffer->handle );
1352 ret = window->queueBuffer( window, win->locked_buffer, -1 );
1353 win->locked_buffer = NULL;
1355 va_end( args );
1356 TRACE( "hwnd %p %s ret %d\n", win->hwnd, names[operation], ret );
1357 return ret;
1359 case NATIVE_WINDOW_CONNECT:
1360 case NATIVE_WINDOW_DISCONNECT:
1361 TRACE( "hwnd %p %s\n", win->hwnd, names[operation] );
1362 break;
1363 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP:
1364 default:
1365 FIXME( "unsupported perform hwnd %p op %d %s\n", win->hwnd, operation,
1366 operation < sizeof(names)/sizeof(names[0]) ? names[operation] : "???" );
1367 break;
1369 va_end( args );
1370 return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL );
1373 struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl )
1375 struct ioctl_android_create_window req;
1376 struct native_win_wrapper *win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*win) );
1378 if (!win) return NULL;
1380 win->win.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
1381 win->win.common.version = sizeof(ANativeWindow);
1382 win->win.common.incRef = win_incRef;
1383 win->win.common.decRef = win_decRef;
1384 win->win.setSwapInterval = setSwapInterval;
1385 win->win.dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
1386 win->win.lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
1387 win->win.queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
1388 win->win.query = query;
1389 win->win.perform = perform;
1390 win->win.cancelBuffer_DEPRECATED = cancelBuffer_DEPRECATED;
1391 win->win.dequeueBuffer = dequeueBuffer;
1392 win->win.queueBuffer = queueBuffer;
1393 win->win.cancelBuffer = cancelBuffer;
1394 win->ref = 1;
1395 win->hwnd = hwnd;
1396 win->opengl = opengl;
1397 TRACE( "-> %p %p opengl=%u\n", win, win->hwnd, opengl );
1399 req.hdr.hwnd = HandleToLong( win->hwnd );
1400 req.hdr.opengl = win->opengl;
1401 req.parent = get_ioctl_win_parent( GetAncestor( hwnd, GA_PARENT ));
1402 android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
1404 return &win->win;
1407 struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window )
1409 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1410 InterlockedIncrement( &win->ref );
1411 return window;
1414 void release_ioctl_window( struct ANativeWindow *window )
1416 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1417 unsigned int i;
1419 if (InterlockedDecrement( &win->ref ) > 0) return;
1421 TRACE( "%p %p\n", win, win->hwnd );
1422 for (i = 0; i < sizeof(win->buffers)/sizeof(win->buffers[0]); i++)
1423 if (win->buffers[i]) win->buffers[i]->buffer.common.decRef( &win->buffers[i]->buffer.common );
1425 destroy_ioctl_window( win->hwnd, win->opengl );
1426 HeapFree( GetProcessHeap(), 0, win );
1429 void destroy_ioctl_window( HWND hwnd, BOOL opengl )
1431 struct ioctl_android_destroy_window req;
1433 req.hdr.hwnd = HandleToLong( hwnd );
1434 req.hdr.opengl = opengl;
1435 android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
1438 int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect,
1439 const RECT *visible_rect, UINT style, UINT flags, HWND after, HWND owner )
1441 struct ioctl_android_window_pos_changed req;
1443 req.hdr.hwnd = HandleToLong( hwnd );
1444 req.hdr.opengl = FALSE;
1445 req.window_rect = *window_rect;
1446 req.client_rect = *client_rect;
1447 req.visible_rect = *visible_rect;
1448 req.style = style;
1449 req.flags = flags;
1450 req.after = HandleToLong( after );
1451 req.owner = HandleToLong( owner );
1452 return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );
1455 int ioctl_set_window_parent( HWND hwnd, HWND parent )
1457 struct ioctl_android_set_window_parent req;
1459 req.hdr.hwnd = HandleToLong( hwnd );
1460 req.hdr.opengl = FALSE;
1461 req.parent = get_ioctl_win_parent( parent );
1462 return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL );
1465 int ioctl_set_capture( HWND hwnd )
1467 struct ioctl_android_set_capture req;
1469 req.hdr.hwnd = HandleToLong( hwnd );
1470 req.hdr.opengl = FALSE;
1471 return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );